First set of new device support, features and cleanups for IIO in the 5.6 cycle

New device support
 
 * ad7091r5 ADC
   - New driver with follow up patch adding scale and vref support.
   - DT bindings
 * ad7923
   - Support for ad7908, ad7918 and ad7928 added to driver.
 * bma180
   - Support the BMA254 accelerometer. Required fairly substantial rework
     to allow for small differences between this an existing parts.
 * bma400 accelerometer
   - New driver with follow up patch for regulator support.
   - DT bindings.
 * asc dlhl60d
   - New driver support this range of pressure and temperature sensors.
   - DT bindings.
 * ltc2496 ADC
   - New driver to support this ADC.
   - Split the existing LTC2497 driver generic component out and reuse.
   - DT bindings.
 * parallax ping
   - New driver supporting ultrasonic and laser tof distance sensors.
   - Bindings for these sensors.
 
 New features
 
 * core
   - New char type for read_raw returns, used for thermocouple types.
   - Rename read_first_n callback to read.   The reasons behind the original
     naming are lost to the mists of time.
 * ad799x
   - Allow pm_ops to disable device completely allowing regulator power down.
 * bma180
   - Enable basic regulator support.
 * dmaengine buffer
   - Report platform data alignment requirements via new ABI.
 * max31856
   - Add option to set mains filter rejection frequency and document
     new in_temp_filter_notch_center_frequency ABI.
   - Add support for configuring HW averaging (oversampling ratio)
   - Add runtime configuration of thermocouple type and document new ABI.
 * maxim-thermocouple
   - Add read only access to thermocouple type using new ABI, includes
     adding more specific compatibles to reflect which variant of the
     chip is being used.
 * mpu6050
   - Provide option to support the PMU9150 in package magnetometer directly
     rather than via auxiliary bus.
 * stm32_adc
   - Add overrun interrupt checks to detect if this happens.
 * st_lsm6dsx
   - Enable the sensor-hub support for lsm6dsm. Includes various reworks to
     allow this.
 
 Cleanups and minor fixes
 
 * Subsystem wide
   - Tidy up indentation in Kconfig and fix alphabetical order of AD7091R5.
   - Drop linux/gpio.h and linux/of_gpio.h from drivers that don't use them.
 * ad7266
   - Convert to GPIO descriptors.
 * ad7303
   - Avoid a dance with checking if the regulator is supplied by just
     using the optional request interface.
 * ad7887
   - Simplify channel specification assignment to enable adding more devices.
 * ad7923
   - Drop some unused and largely pointless defines of BOB_N==N variety.
   - Tidy up checkpatch warnings.
   - Add missing of_device_id table.
 * adf4350
   - Convert to GPIO descriptors.
 * ak8975
   - Convert to GPIO descriptors.
 * ADIS library and drivers
   - Expand scope of txrx_lock to cover all state and rename as state_lock
   - Add unlocked read / write to allow grouping of consecutive calls under
     single lock / unlock.
   - Add unlocked check_status, reset to allow grouping under single
     lock / unlock.
   - Remove remaining uses of core mlock for local state protection.
     mlock should never be used directly as it protects tightly defined
     core IIO device management state.
 * adis16240
   - Enforce only supported SPI mode on driver load + add DT binding doc.
 * atlas-ph-sensor
   - Rename to atlas-sensor given it now covers things beyond ph sensors.
 * bma180
   - Use local dev variable to tidy up code.
   - Use c99 style explicity .member assignment to make driver more readable.
 * bmp280
   - Drop ACPI support. No evidence this was used and appropriate ID is not
     registered.
   - Allow ACPI to bind device via PRP0001
 * dmaengine buffer
   - Use dma_request_chan instead of dma_request_slave_channel_reason as that
     ABI is going away.
   - Add module info to avoid tainting the kernel.
 * hts221
   - Avoid magic number defines when only used to fill structure elements
     that are self describing.
 * lm3533
   - Drop a stray semicolon.
 * max9611
   - Cleanup enum handling to be more resilient to future changes.
 * mpu6050
   - Delete MPU9150 from supported SPI devices as doesn't provide SPI.
   - Select I2C_MUX again after kbuild issue fixed elsewhere.
 * stm32-timer
   - Drop an unnecessary register update.
 * ssp_sensors
   - Convert to GPIO descriptors.
 * st_sensors
   - drop !CONFIG_ACPI defines as ACPI_PTR() will stop them being used
     anyway.
   - Make default platform data structures __maybe_unsued.
   - Fill in some missing kernel-doc function parameters.
 * st_lsm6dsx
   - white space fixes.
   - Mark some constants that aren't always used as __maybe_unused.
   - Drop of ID table guards as they just pervent use under ACPI.
   - Switch to device properties to allow ACPI usage.
 * st_uvis25
   - Drop acpi.h include as no ACPI APIs used.
 * ti-ads1015
   - Drop legacy platform data as no one seems to be using it.
   - Use the device property API instead of OF specific.
 * ti-ads7950
   - typo fix in error message.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl4R2mwRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0Fogfow//Rfsrd2oiAwy4ypm70ZWGnr84C3O/Vpic
 Agwdd2/lHiCA2Gjg+n7ZT6XkKQmKiojuBMT05PuskEm5onJVQuSAKMVppXwU6UDP
 uOUS5MAbo87GLogzXJnAR/eCrx/VkC4UqFRBSi7IUIj+lTpjiOhmoqm78VTMxkgT
 hvp5PVN/mLNxNV3eVrR9uILjZLpbBjKjWil00IS2zj0o78sGtd2QtMIdTbn3iBLp
 m0ngCDww1KDH+idwbOIn8YX8GSK8mTjNV5q4r9+xnjoAk8RPk+H317idyRHCKfCM
 wWFSFB6u/oqtHXRgQVi3ndRrZnPLTycA/R20f3ezzhVYZzf3RpH8Upcx0lqqCmrB
 +ZTbYW1L7KL6zCSR4ZYIEmw2TeQngfCGy0yDoEDXm9V8/B2nGWFc3Iknq+fK415V
 7OgJCWAw6ybF2LZfJHpcuJTb0EPxCKnInHbRsaxCsSAPRyERSdAz8RLn3lpH/k2D
 X32Q9hz/6sXKzIAD1Y0jv8ll28D5S7d2FgaWufy1tpB+CMb0Mp0RQn+Ho8lNMh70
 Zh9SF8RvknAiCT9iHeVIdbJxoYEtMuCaDwScliukVcg12gVViY5VzXMbSV/4jCnZ
 bAVZDpcM3LVLxCGbWqCNxjQ9wle99LsVHRld/KDpOfI6VIYDb8Y900Nf6efkQkAs
 a6z6rhpVdDg=
 =8FmM
 -----END PGP SIGNATURE-----

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

Jonathan writes:

First set of new device support, features and cleanups for IIO in the 5.6 cycle

New device support

* ad7091r5 ADC
  - New driver with follow up patch adding scale and vref support.
  - DT bindings
* ad7923
  - Support for ad7908, ad7918 and ad7928 added to driver.
* bma180
  - Support the BMA254 accelerometer. Required fairly substantial rework
    to allow for small differences between this an existing parts.
* bma400 accelerometer
  - New driver with follow up patch for regulator support.
  - DT bindings.
* asc dlhl60d
  - New driver support this range of pressure and temperature sensors.
  - DT bindings.
* ltc2496 ADC
  - New driver to support this ADC.
  - Split the existing LTC2497 driver generic component out and reuse.
  - DT bindings.
* parallax ping
  - New driver supporting ultrasonic and laser tof distance sensors.
  - Bindings for these sensors.

New features

* core
  - New char type for read_raw returns, used for thermocouple types.
  - Rename read_first_n callback to read.   The reasons behind the original
    naming are lost to the mists of time.
* ad799x
  - Allow pm_ops to disable device completely allowing regulator power down.
* bma180
  - Enable basic regulator support.
* dmaengine buffer
  - Report platform data alignment requirements via new ABI.
* max31856
  - Add option to set mains filter rejection frequency and document
    new in_temp_filter_notch_center_frequency ABI.
  - Add support for configuring HW averaging (oversampling ratio)
  - Add runtime configuration of thermocouple type and document new ABI.
* maxim-thermocouple
  - Add read only access to thermocouple type using new ABI, includes
    adding more specific compatibles to reflect which variant of the
    chip is being used.
* mpu6050
  - Provide option to support the PMU9150 in package magnetometer directly
    rather than via auxiliary bus.
* stm32_adc
  - Add overrun interrupt checks to detect if this happens.
* st_lsm6dsx
  - Enable the sensor-hub support for lsm6dsm. Includes various reworks to
    allow this.

Cleanups and minor fixes

* Subsystem wide
  - Tidy up indentation in Kconfig and fix alphabetical order of AD7091R5.
  - Drop linux/gpio.h and linux/of_gpio.h from drivers that don't use them.
* ad7266
  - Convert to GPIO descriptors.
* ad7303
  - Avoid a dance with checking if the regulator is supplied by just
    using the optional request interface.
* ad7887
  - Simplify channel specification assignment to enable adding more devices.
* ad7923
  - Drop some unused and largely pointless defines of BOB_N==N variety.
  - Tidy up checkpatch warnings.
  - Add missing of_device_id table.
* adf4350
  - Convert to GPIO descriptors.
* ak8975
  - Convert to GPIO descriptors.
* ADIS library and drivers
  - Expand scope of txrx_lock to cover all state and rename as state_lock
  - Add unlocked read / write to allow grouping of consecutive calls under
    single lock / unlock.
  - Add unlocked check_status, reset to allow grouping under single
    lock / unlock.
  - Remove remaining uses of core mlock for local state protection.
    mlock should never be used directly as it protects tightly defined
    core IIO device management state.
* adis16240
  - Enforce only supported SPI mode on driver load + add DT binding doc.
* atlas-ph-sensor
  - Rename to atlas-sensor given it now covers things beyond ph sensors.
* bma180
  - Use local dev variable to tidy up code.
  - Use c99 style explicity .member assignment to make driver more readable.
* bmp280
  - Drop ACPI support. No evidence this was used and appropriate ID is not
    registered.
  - Allow ACPI to bind device via PRP0001
* dmaengine buffer
  - Use dma_request_chan instead of dma_request_slave_channel_reason as that
    ABI is going away.
  - Add module info to avoid tainting the kernel.
* hts221
  - Avoid magic number defines when only used to fill structure elements
    that are self describing.
* lm3533
  - Drop a stray semicolon.
* max9611
  - Cleanup enum handling to be more resilient to future changes.
* mpu6050
  - Delete MPU9150 from supported SPI devices as doesn't provide SPI.
  - Select I2C_MUX again after kbuild issue fixed elsewhere.
* stm32-timer
  - Drop an unnecessary register update.
* ssp_sensors
  - Convert to GPIO descriptors.
* st_sensors
  - drop !CONFIG_ACPI defines as ACPI_PTR() will stop them being used
    anyway.
  - Make default platform data structures __maybe_unsued.
  - Fill in some missing kernel-doc function parameters.
* st_lsm6dsx
  - white space fixes.
  - Mark some constants that aren't always used as __maybe_unused.
  - Drop of ID table guards as they just pervent use under ACPI.
  - Switch to device properties to allow ACPI usage.
* st_uvis25
  - Drop acpi.h include as no ACPI APIs used.
* ti-ads1015
  - Drop legacy platform data as no one seems to be using it.
  - Use the device property API instead of OF specific.
* ti-ads7950
  - typo fix in error message.

* tag 'iio-for-5.6a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (99 commits)
  iio: accel: bma180: BMA254 support
  iio: pressure: bmp280: Allow device to be enumerated from ACPI
  iio: pressure: bmp280: Drop ACPI support
  dt-bindings: iio: adc: convert sd modulator to json-schema
  iio: buffer: rename 'read_first_n' callback to 'read'
  iio: buffer-dmaengine: Report buffer length requirements
  bindings: iio: pressure: Add documentation for dlh driver
  dt-bindings: Add asc vendor
  iio: pressure: Add driver for DLH pressure sensors
  iio: buffer-dmaengine: Add module information
  iio: accel: bma180: Use explicit member assignment
  iio: accel: bma180: Basic regulator support
  iio: accel: bma180: Add dev helper variable
  iio: imu: st_lsm6dsx: enable sensor-hub support for lsm6dsm
  iio: imu: st_lsm6dsx: rename st_lsm6dsx_shub_read_reg in st_lsm6dsx_shub_read_output
  iio: imu: st_lsm6dsx: check if shub_output reg is located in primary page
  iio: imu: st_lsm6dsx: check if pull_up is located in primary page
  iio: imu: st_lsm6dsx: check if master_enable is located in primary page
  iio: imu: st_lsm6dsx: export max num of slave devices in st_lsm6dsx_shub_settings
  iio: light: remove unneeded semicolon
  ...
This commit is contained in:
Greg Kroah-Hartman 2020-01-10 10:44:00 +01:00
commit 821f7ce79f
105 changed files with 4394 additions and 860 deletions

View file

@ -1726,3 +1726,16 @@ Contact: linux-iio@vger.kernel.org
Description:
List of valid periods (in seconds) for which the light intensity
must be above the threshold level before interrupt is asserted.
What: /sys/bus/iio/devices/iio:deviceX/in_filter_notch_center_frequency
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
Center frequency in Hz for a notch filter. Used i.e. for line
noise suppression.
What: /sys/bus/iio/devices/iio:deviceX/in_temp_thermocouple_type
KernelVersion: 5.5
Contact: linux-iio@vger.kernel.org
Description:
One of the following thermocouple types: B, E, J, K, N, R, S, T.

View file

@ -0,0 +1,19 @@
What: /sys/bus/iio/devices/iio:deviceX/buffer/length_align_bytes
KernelVersion: 5.4
Contact: linux-iio@vger.kernel.org
Description:
DMA buffers tend to have a alignment requirement for the
buffers. If this alignment requirement is not met samples might
be dropped from the buffer.
This property reports the alignment requirements in bytes.
This means that the buffer size in bytes needs to be a integer
multiple of the number reported by this file.
The alignment requirements in number of sample sets will depend
on the enabled channels and the bytes per channel. This means
that the alignment requirement in samples sets might change
depending on which and how many channels are enabled. Whereas
the alignment requirement reported in bytes by this property
will remain static and does not depend on which channels are
enabled.

View file

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/accel/adi,adis16240.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ADIS16240 Programmable Impact Sensor and Recorder driver
maintainers:
- Alexandru Ardelean <alexandru.ardelean@analog.com>
description: |
ADIS16240 Programmable Impact Sensor and Recorder driver that supports
SPI interface.
https://www.analog.com/en/products/adis16240.html
properties:
compatible:
enum:
- adi,adis16240
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
/* Example for a SPI device node */
accelerometer@0 {
compatible = "adi,adis16240";
reg = <0>;
spi-max-frequency = <2500000>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
};
};

View file

@ -1,11 +1,14 @@
* Bosch BMA180 / BMA250 triaxial acceleration sensor
* Bosch BMA180 / BMA25x triaxial acceleration sensor
http://omapworld.com/BMA180_111_1002839.pdf
http://ae-bst.resource.bosch.com/media/products/dokumente/bma250/bst-bma250-ds002-05.pdf
Required properties:
- compatible : should be "bosch,bma180" or "bosch,bma250"
- compatible : should be one of:
"bosch,bma180"
"bosch,bma250"
"bosch,bma254"
- reg : the I2C address of the sensor
Optional properties:

View file

@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/accel/bosch,bma400.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch BMA400 triaxial acceleration sensor
maintainers:
- Dan Robertson <dan@dlrobertson.com>
description: |
Acceleration and temperature iio sensors with an i2c interface
Specifications about the sensor can be found at:
https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMA400-DS000.pdf
properties:
compatible:
enum:
- bosch,bma400
reg:
maxItems: 1
vdd-supply:
description: phandle to the regulator that provides power to the accelerometer
vddio-supply:
description: phandle to the regulator that provides power to the sensor's IO
interrupts:
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
accelerometer@14 {
compatible = "bosch,bma400";
reg = <0x14>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
};
};

View file

@ -0,0 +1,54 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD7091R5 4-Channel 12-Bit ADC
maintainers:
- Beniamin Bia <beniamin.bia@analog.com>
description: |
Analog Devices AD7091R5 4-Channel 12-Bit ADC
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf
properties:
compatible:
enum:
- adi,ad7091r5
reg:
maxItems: 1
vref-supply:
description:
Phandle to the vref power supply
interrupts:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
adc@2f {
compatible = "adi,ad7091r5";
reg = <0x2f>;
interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio>;
};
};
...

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/adc/lltc,ltc2496.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Linear Technology / Analog Devices LTC2496 ADC
maintainers:
- Lars-Peter Clausen <lars@metafoo.de>
- Michael Hennerich <Michael.Hennerich@analog.com>
- Stefan Popa <stefan.popa@analog.com>
properties:
compatible:
enum:
- lltc,ltc2496
vref-supply:
description: phandle to an external regulator providing the reference voltage
allOf:
- $ref: /schemas/types.yaml#/definitions/phandle
reg:
description: spi chipselect number according to the usual spi bindings
spi-max-frequency:
description: maximal spi bus frequency supported
required:
- compatible
- vref-supply
- reg
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "lltc,ltc2496";
reg = <0>;
vref-supply = <&ltc2496_reg>;
spi-max-frequency = <2000000>;
};
};

View file

@ -1,13 +0,0 @@
Device-Tree bindings for sigma delta modulator
Required properties:
- compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use
as a generic SD modulator if modulator not specified in compatible list.
- #io-channel-cells = <0>: See the IIO bindings section "IIO consumers".
Example node:
ads1202: adc {
compatible = "sd-modulator";
#io-channel-cells = <0>;
};

View file

@ -0,0 +1,37 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/sigma-delta-modulator.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Device-Tree bindings for sigma delta modulator
maintainers:
- Arnaud Pouliquen <arnaud.pouliquen@st.com>
properties:
compatible:
description: |
"sd-modulator" can be used as a generic SD modulator,
if the modulator is not specified in the compatible list.
enum:
- sd-modulator
- ads1201
'#io-channel-cells':
const: 0
required:
- compatible
- '#io-channel-cells'
additionalProperties: false
examples:
- |
ads1202: adc {
compatible = "sd-modulator";
#io-channel-cells = <0>;
};
...

View file

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/pressure/asc,dlhl60d.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: All Sensors DLH series low voltage digital pressure sensors
maintainers:
- Tomislav Denis <tomislav.denis@avl.com>
description: |
Bindings for the All Sensors DLH series pressure sensors.
Specifications about the sensors can be found at:
http://www.allsensors.com/cad/DS-0355_Rev_B.PDF
properties:
compatible:
enum:
- asc,dlhl60d
- asc,dlhl60g
reg:
description: I2C device address
maxItems: 1
interrupts:
description: interrupt mapping for EOC(data ready) pin
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
pressure@29 {
compatible = "asc,dlhl60d";
reg = <0x29>;
interrupt-parent = <&gpio0>;
interrupts = <10 IRQ_TYPE_EDGE_RISING>;
};
};
...

View file

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/proximity/parallax-ping.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Parallax PING))) and LaserPING range finder
maintainers:
- Andreas Klinger <ak@it-klinger.de>
description: |
Bit-banging driver using one GPIO:
- ping-gpios is raised by the driver to start measurement
- direction of ping-gpio is then switched into input with an interrupt
for receiving distance value as PWM signal
Specifications about the devices can be found at:
http://parallax.com/sites/default/files/downloads/28041-LaserPING-2m-Rangefinder-Guide.pdf
http://parallax.com/sites/default/files/downloads/28015-PING-Documentation-v1.6.pdf
properties:
compatible:
enum:
- parallax,ping
- parallax,laserping
ping-gpios:
description:
Definition of the GPIO for the triggering and echo (output and input)
This GPIO is set for about 5 us by the driver to tell the device it
should initiate the measurement cycle. Afterwards the GPIO is switched
to input direction with an interrupt. The device sets it and the
length of the input signal corresponds to the measured distance.
It needs to be an GPIO which is able to deliver an interrupt because
the time between two interrupts is measured in the driver.
See Documentation/devicetree/bindings/gpio/gpio.txt for information
on how to specify a consumer gpio.
maxItems: 1
required:
- compatible
- ping-gpios
examples:
- |
#include <dt-bindings/gpio/gpio.h>
proximity {
compatible = "parallax,laserping";
ping-gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
};

View file

@ -5,7 +5,10 @@ Maxim thermocouple support
Required properties:
- compatible: must be "maxim,max31855" or "maxim,max6675"
- compatible: must be "maxim,max6675" or one of the following:
"maxim,max31855k", "maxim,max31855j", "maxim,max31855n",
"maxim,max31855s", "maxim,max31855t", "maxim,max31855e",
"maxim,max31855r"; the generic "max,max31855" is deprecated.
- reg: SPI chip select number for the device
- spi-max-frequency: must be 4300000
- spi-cpha: must be defined for max6675 to enable SPI mode 1
@ -15,7 +18,7 @@ Required properties:
Example:
max31855@0 {
compatible = "maxim,max31855";
compatible = "maxim,max31855k";
reg = <0>;
spi-max-frequency = <4300000>;
};

View file

@ -109,6 +109,8 @@ patternProperties:
description: Artesyn Embedded Technologies Inc.
"^asahi-kasei,.*":
description: Asahi Kasei Corp.
"^asc,.*":
description: All Sensors Corporation
"^aspeed,.*":
description: ASPEED Technology Inc.
"^asus,.*":
@ -717,6 +719,8 @@ patternProperties:
description: Panasonic Corporation
"^parade,.*":
description: Parade Technologies Inc.
"^parallax,.*":
description: Parallax Inc.
"^pda,.*":
description: Precision Design Associates, Inc.
"^pericom,.*":

View file

@ -674,6 +674,14 @@ S: Maintained
F: Documentation/i2c/busses/i2c-ali1563.rst
F: drivers/i2c/busses/i2c-ali1563.c
ALL SENSORS DLH SERIES PRESSURE SENSORS DRIVER
M: Tomislav Denis <tomislav.denis@avl.com>
W: http://www.allsensors.com/
S: Maintained
L: linux-iio@vger.kernel.org
F: drivers/iio/pressure/dlhl60d.c
F: Documentation/devicetree/bindings/iio/pressure/asc,dlhl60d.yaml
ALLEGRO DVT VIDEO IP CORE DRIVER
M: Michael Tretter <m.tretter@pengutronix.de>
R: Pengutronix Kernel Team <kernel@pengutronix.de>
@ -898,6 +906,14 @@ S: Supported
F: drivers/iio/dac/ad5758.c
F: Documentation/devicetree/bindings/iio/dac/ad5758.txt
ANALOG DEVICES INC AD7091R5 DRIVER
M: Beniamin Bia <beniamin.bia@analog.com>
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: drivers/iio/adc/ad7091r5.c
F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
ANALOG DEVICES INC AD7124 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-iio@vger.kernel.org
@ -1043,7 +1059,7 @@ S: Supported
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc2497*
F: drivers/iio/adc/ltc249*
X: drivers/iio/*/adjd*
F: drivers/staging/iio/*/ad*
@ -3089,6 +3105,13 @@ S: Supported
F: drivers/net/bonding/
F: include/uapi/linux/if_bonding.h
BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
M: Dan Robertson <dan@dlrobertson.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/accel/bma400*
F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
BPF (Safe dynamic programs and tools)
M: Alexei Starovoitov <ast@kernel.org>
M: Daniel Borkmann <daniel@iogearbox.net>
@ -12443,6 +12466,13 @@ L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/panasonic-laptop.c
PARALLAX PING IIO SENSOR DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/proximity/parallax-ping.yaml
F: drivers/iio/proximity/ping.c
PARALLEL LCD/KEYPAD PANEL DRIVER
M: Willy Tarreau <willy@haproxy.com>
M: Ksenija Stanojevic <ksenija.stanojevic@gmail.com>

View file

@ -89,13 +89,13 @@ config ADXL372_I2C
module will be called adxl372_i2c.
config BMA180
tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver"
tristate "Bosch BMA180/BMA25x 3-Axis Accelerometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Bosch BMA180 or
BMA250 triaxial acceleration sensor.
BMA25x triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma180.
@ -112,6 +112,22 @@ config BMA220
To compile this driver as a module, choose M here: the
module will be called bma220_spi.
config BMA400
tristate "Bosch BMA400 3-Axis Accelerometer Driver"
select REGMAP
select BMA400_I2C if I2C
help
Say Y here if you want to build a driver for the Bosch BMA400
triaxial acceleration sensor.
To compile this driver as a module, choose M here: the
module will be called bma400_core and you will also get
bma400_i2c if I2C is enabled.
config BMA400_I2C
tristate
depends on BMA400
config BMC150_ACCEL
tristate "Bosch BMC150 Accelerometer Driver"
select IIO_BUFFER

View file

@ -14,6 +14,8 @@ obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
obj-$(CONFIG_BMA180) += bma180.o
obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMA400) += bma400_core.o
obj-$(CONFIG_BMA400_I2C) += bma400_i2c.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o

View file

@ -9,6 +9,7 @@
* SPI is not supported by driver
* BMA180: 7-bit I2C slave address 0x40 or 0x41
* BMA250: 7-bit I2C slave address 0x18 or 0x19
* BMA254: 7-bit I2C slave address 0x18 or 0x19
*/
#include <linux/module.h>
@ -18,6 +19,7 @@
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/iio/iio.h>
@ -33,17 +35,20 @@
enum chip_ids {
BMA180,
BMA250,
BMA254,
};
struct bma180_data;
struct bma180_part_info {
u8 chip_id;
const struct iio_chan_spec *channels;
unsigned int num_channels;
const int *scale_table;
unsigned int num_scales;
const int *bw_table;
unsigned int num_bw;
int center_temp;
u8 int_reset_reg, int_reset_mask;
u8 sleep_reg, sleep_mask;
@ -51,6 +56,7 @@ struct bma180_part_info {
u8 scale_reg, scale_mask;
u8 power_reg, power_mask, lowpower_val;
u8 int_enable_reg, int_enable_mask;
u8 int_map_reg, int_enable_dataready_int1_mask;
u8 softreset_reg;
int (*chip_config)(struct bma180_data *data);
@ -89,6 +95,8 @@ struct bma180_part_info {
#define BMA180_RESET_VAL 0xb6
#define BMA180_ID_REG_VAL 0x03
#define BMA250_ID_REG_VAL 0x03
#define BMA254_ID_REG_VAL 0xfa /* 250 decimal */
/* Chip power modes */
#define BMA180_LOW_POWER 0x03
@ -109,7 +117,26 @@ struct bma180_part_info {
#define BMA250_INT1_DATA_MASK BIT(0)
#define BMA250_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
#define BMA254_RANGE_REG 0x0f
#define BMA254_BW_REG 0x10
#define BMA254_POWER_REG 0x11
#define BMA254_RESET_REG 0x14
#define BMA254_INT_ENABLE_REG 0x17
#define BMA254_INT_MAP_REG 0x1a
#define BMA254_INT_RESET_REG 0x21
#define BMA254_RANGE_MASK GENMASK(3, 0) /* Range of accel values */
#define BMA254_BW_MASK GENMASK(4, 0) /* Accel bandwidth */
#define BMA254_SUSPEND_MASK BIT(7) /* chip will sleep */
#define BMA254_LOWPOWER_MASK BIT(6)
#define BMA254_DATA_INTEN_MASK BIT(4)
#define BMA254_INT2_DATA_MASK BIT(7)
#define BMA254_INT1_DATA_MASK BIT(0)
#define BMA254_INT_RESET_MASK BIT(7) /* Reset pending interrupts */
struct bma180_data {
struct regulator *vdd_supply;
struct regulator *vddio_supply;
struct i2c_client *client;
struct iio_trigger *trig;
const struct bma180_part_info *part_info;
@ -132,8 +159,8 @@ enum bma180_chan {
static int bma180_bw_table[] = { 10, 20, 40, 75, 150, 300 }; /* Hz */
static int bma180_scale_table[] = { 1275, 1863, 2452, 3727, 4903, 9709, 19417 };
static int bma250_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
static int bma250_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
static int bma25x_bw_table[] = { 8, 16, 31, 63, 125, 250 }; /* Hz */
static int bma25x_scale_table[] = { 0, 0, 0, 38344, 0, 76590, 0, 0, 153180, 0,
0, 0, 306458 };
static int bma180_get_data_reg(struct bma180_data *data, enum bma180_chan chan)
@ -307,8 +334,11 @@ static int bma180_chip_init(struct bma180_data *data)
if (ret < 0)
return ret;
if (ret != BMA180_ID_REG_VAL)
if (ret != data->part_info->chip_id) {
dev_err(&data->client->dev, "wrong chip ID %d expected %d\n",
ret, data->part_info->chip_id);
return -ENODEV;
}
ret = bma180_soft_reset(data);
if (ret)
@ -355,7 +385,7 @@ err:
return ret;
}
static int bma250_chip_config(struct bma180_data *data)
static int bma25x_chip_config(struct bma180_data *data)
{
int ret = bma180_chip_init(data);
@ -367,8 +397,12 @@ static int bma250_chip_config(struct bma180_data *data)
ret = bma180_set_scale(data, 38344); /* 2 G */
if (ret)
goto err;
ret = bma180_set_bits(data, BMA250_INT_MAP_REG,
BMA250_INT1_DATA_MASK, 1);
/*
* This enables dataready interrupt on the INT1 pin
* FIXME: support using the INT2 pin
*/
ret = bma180_set_bits(data, data->part_info->int_map_reg,
data->part_info->int_enable_dataready_int1_mask, 1);
if (ret)
goto err;
@ -394,7 +428,7 @@ err:
dev_err(&data->client->dev, "failed to disable the chip\n");
}
static void bma250_chip_disable(struct bma180_data *data)
static void bma25x_chip_disable(struct bma180_data *data)
{
if (bma180_set_new_data_intr_state(data, false))
goto err;
@ -497,7 +531,7 @@ static int bma180_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 48; /* 0 LSB @ 24 degree C */
*val = data->part_info->center_temp;
return IIO_VAL_INT;
default:
return -EINVAL;
@ -627,34 +661,96 @@ static const struct iio_chan_spec bma250_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct iio_chan_spec bma254_channels[] = {
BMA180_ACC_CHANNEL(X, 12),
BMA180_ACC_CHANNEL(Y, 12),
BMA180_ACC_CHANNEL(Z, 12),
BMA180_TEMP_CHANNEL,
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct bma180_part_info bma180_part_info[] = {
[BMA180] = {
bma180_channels, ARRAY_SIZE(bma180_channels),
bma180_scale_table, ARRAY_SIZE(bma180_scale_table),
bma180_bw_table, ARRAY_SIZE(bma180_bw_table),
BMA180_CTRL_REG0, BMA180_RESET_INT,
BMA180_CTRL_REG0, BMA180_SLEEP,
BMA180_BW_TCS, BMA180_BW,
BMA180_OFFSET_LSB1, BMA180_RANGE,
BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER,
BMA180_CTRL_REG3, BMA180_NEW_DATA_INT,
BMA180_RESET,
bma180_chip_config,
bma180_chip_disable,
.chip_id = BMA180_ID_REG_VAL,
.channels = bma180_channels,
.num_channels = ARRAY_SIZE(bma180_channels),
.scale_table = bma180_scale_table,
.num_scales = ARRAY_SIZE(bma180_scale_table),
.bw_table = bma180_bw_table,
.num_bw = ARRAY_SIZE(bma180_bw_table),
.center_temp = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA180_CTRL_REG0,
.int_reset_mask = BMA180_RESET_INT,
.sleep_reg = BMA180_CTRL_REG0,
.sleep_mask = BMA180_SLEEP,
.bw_reg = BMA180_BW_TCS,
.bw_mask = BMA180_BW,
.scale_reg = BMA180_OFFSET_LSB1,
.scale_mask = BMA180_RANGE,
.power_reg = BMA180_TCO_Z,
.power_mask = BMA180_MODE_CONFIG,
.lowpower_val = BMA180_LOW_POWER,
.int_enable_reg = BMA180_CTRL_REG3,
.int_enable_mask = BMA180_NEW_DATA_INT,
.softreset_reg = BMA180_RESET,
.chip_config = bma180_chip_config,
.chip_disable = bma180_chip_disable,
},
[BMA250] = {
bma250_channels, ARRAY_SIZE(bma250_channels),
bma250_scale_table, ARRAY_SIZE(bma250_scale_table),
bma250_bw_table, ARRAY_SIZE(bma250_bw_table),
BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK,
BMA250_POWER_REG, BMA250_SUSPEND_MASK,
BMA250_BW_REG, BMA250_BW_MASK,
BMA250_RANGE_REG, BMA250_RANGE_MASK,
BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1,
BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK,
BMA250_RESET_REG,
bma250_chip_config,
bma250_chip_disable,
.chip_id = BMA250_ID_REG_VAL,
.channels = bma250_channels,
.num_channels = ARRAY_SIZE(bma250_channels),
.scale_table = bma25x_scale_table,
.num_scales = ARRAY_SIZE(bma25x_scale_table),
.bw_table = bma25x_bw_table,
.num_bw = ARRAY_SIZE(bma25x_bw_table),
.center_temp = 48, /* 0 LSB @ 24 degree C */
.int_reset_reg = BMA250_INT_RESET_REG,
.int_reset_mask = BMA250_INT_RESET_MASK,
.sleep_reg = BMA250_POWER_REG,
.sleep_mask = BMA250_SUSPEND_MASK,
.bw_reg = BMA250_BW_REG,
.bw_mask = BMA250_BW_MASK,
.scale_reg = BMA250_RANGE_REG,
.scale_mask = BMA250_RANGE_MASK,
.power_reg = BMA250_POWER_REG,
.power_mask = BMA250_LOWPOWER_MASK,
.lowpower_val = 1,
.int_enable_reg = BMA250_INT_ENABLE_REG,
.int_enable_mask = BMA250_DATA_INTEN_MASK,
.int_map_reg = BMA250_INT_MAP_REG,
.int_enable_dataready_int1_mask = BMA250_INT1_DATA_MASK,
.softreset_reg = BMA250_RESET_REG,
.chip_config = bma25x_chip_config,
.chip_disable = bma25x_chip_disable,
},
[BMA254] = {
.chip_id = BMA254_ID_REG_VAL,
.channels = bma254_channels,
.num_channels = ARRAY_SIZE(bma254_channels),
.scale_table = bma25x_scale_table,
.num_scales = ARRAY_SIZE(bma25x_scale_table),
.bw_table = bma25x_bw_table,
.num_bw = ARRAY_SIZE(bma25x_bw_table),
.center_temp = 46, /* 0 LSB @ 23 degree C */
.int_reset_reg = BMA254_INT_RESET_REG,
.int_reset_mask = BMA254_INT_RESET_MASK,
.sleep_reg = BMA254_POWER_REG,
.sleep_mask = BMA254_SUSPEND_MASK,
.bw_reg = BMA254_BW_REG,
.bw_mask = BMA254_BW_MASK,
.scale_reg = BMA254_RANGE_REG,
.scale_mask = BMA254_RANGE_MASK,
.power_reg = BMA254_POWER_REG,
.power_mask = BMA254_LOWPOWER_MASK,
.lowpower_val = 1,
.int_enable_reg = BMA254_INT_ENABLE_REG,
.int_enable_mask = BMA254_DATA_INTEN_MASK,
.int_map_reg = BMA254_INT_MAP_REG,
.int_enable_dataready_int1_mask = BMA254_INT1_DATA_MASK,
.softreset_reg = BMA254_RESET_REG,
.chip_config = bma25x_chip_config,
.chip_disable = bma25x_chip_disable,
},
};
@ -712,12 +808,13 @@ static const struct iio_trigger_ops bma180_trigger_ops = {
static int bma180_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct bma180_data *data;
struct iio_dev *indio_dev;
enum chip_ids chip;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
@ -725,22 +822,56 @@ static int bma180_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
data->client = client;
if (client->dev.of_node)
chip = (enum chip_ids)of_device_get_match_data(&client->dev);
chip = (enum chip_ids)of_device_get_match_data(dev);
else
chip = id->driver_data;
data->part_info = &bma180_part_info[chip];
ret = iio_read_mount_matrix(&client->dev, "mount-matrix",
ret = iio_read_mount_matrix(dev, "mount-matrix",
&data->orientation);
if (ret)
return ret;
data->vdd_supply = devm_regulator_get(dev, "vdd");
if (IS_ERR(data->vdd_supply)) {
if (PTR_ERR(data->vdd_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vdd regulator %d\n",
(int)PTR_ERR(data->vdd_supply));
return PTR_ERR(data->vdd_supply);
}
data->vddio_supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(data->vddio_supply)) {
if (PTR_ERR(data->vddio_supply) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vddio regulator %d\n",
(int)PTR_ERR(data->vddio_supply));
return PTR_ERR(data->vddio_supply);
}
/* Typical voltage 2.4V these are min and max */
ret = regulator_set_voltage(data->vdd_supply, 1620000, 3600000);
if (ret)
return ret;
ret = regulator_set_voltage(data->vddio_supply, 1200000, 3600000);
if (ret)
return ret;
ret = regulator_enable(data->vdd_supply);
if (ret) {
dev_err(dev, "Failed to enable vdd regulator: %d\n", ret);
return ret;
}
ret = regulator_enable(data->vddio_supply);
if (ret) {
dev_err(dev, "Failed to enable vddio regulator: %d\n", ret);
goto err_disable_vdd;
}
/* Wait to make sure we started up properly (3 ms at least) */
usleep_range(3000, 5000);
ret = data->part_info->chip_config(data);
if (ret < 0)
goto err_chip_disable;
mutex_init(&data->mutex);
indio_dev->dev.parent = &client->dev;
indio_dev->dev.parent = dev;
indio_dev->channels = data->part_info->channels;
indio_dev->num_channels = data->part_info->num_channels;
indio_dev->name = id->name;
@ -755,15 +886,15 @@ static int bma180_probe(struct i2c_client *client,
goto err_chip_disable;
}
ret = devm_request_irq(&client->dev, client->irq,
ret = devm_request_irq(dev, client->irq,
iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING,
"bma180_event", data->trig);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
dev_err(dev, "unable to request IRQ\n");
goto err_trigger_free;
}
data->trig->dev.parent = &client->dev;
data->trig->dev.parent = dev;
data->trig->ops = &bma180_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
indio_dev->trig = iio_trigger_get(data->trig);
@ -776,13 +907,13 @@ static int bma180_probe(struct i2c_client *client,
ret = iio_triggered_buffer_setup(indio_dev, NULL,
bma180_trigger_handler, NULL);
if (ret < 0) {
dev_err(&client->dev, "unable to setup iio triggered buffer\n");
dev_err(dev, "unable to setup iio triggered buffer\n");
goto err_trigger_unregister;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
dev_err(dev, "unable to register iio device\n");
goto err_buffer_cleanup;
}
@ -797,6 +928,9 @@ err_trigger_free:
iio_trigger_free(data->trig);
err_chip_disable:
data->part_info->chip_disable(data);
regulator_disable(data->vddio_supply);
err_disable_vdd:
regulator_disable(data->vdd_supply);
return ret;
}
@ -816,6 +950,8 @@ static int bma180_remove(struct i2c_client *client)
mutex_lock(&data->mutex);
data->part_info->chip_disable(data);
mutex_unlock(&data->mutex);
regulator_disable(data->vddio_supply);
regulator_disable(data->vdd_supply);
return 0;
}
@ -856,6 +992,7 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
static const struct i2c_device_id bma180_ids[] = {
{ "bma180", BMA180 },
{ "bma250", BMA250 },
{ "bma254", BMA254 },
{ }
};
@ -870,6 +1007,10 @@ static const struct of_device_id bma180_of_match[] = {
.compatible = "bosch,bma250",
.data = (void *)BMA250
},
{
.compatible = "bosch,bma254",
.data = (void *)BMA254
},
{ }
};
MODULE_DEVICE_TABLE(of, bma180_of_match);
@ -889,5 +1030,5 @@ module_i2c_driver(bma180_driver);
MODULE_AUTHOR("Kravchenko Oleksandr <x0199363@ti.com>");
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("Bosch BMA180/BMA250 triaxial acceleration sensor");
MODULE_DESCRIPTION("Bosch BMA180/BMA25x triaxial acceleration sensor");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,99 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Register constants and other forward declarations needed by the bma400
* sources.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*/
#ifndef _BMA400_H_
#define _BMA400_H_
#include <linux/bits.h>
#include <linux/regmap.h>
/*
* Read-Only Registers
*/
/* Status and ID registers */
#define BMA400_CHIP_ID_REG 0x00
#define BMA400_ERR_REG 0x02
#define BMA400_STATUS_REG 0x03
/* Acceleration registers */
#define BMA400_X_AXIS_LSB_REG 0x04
#define BMA400_X_AXIS_MSB_REG 0x05
#define BMA400_Y_AXIS_LSB_REG 0x06
#define BMA400_Y_AXIS_MSB_REG 0x07
#define BMA400_Z_AXIS_LSB_REG 0x08
#define BMA400_Z_AXIS_MSB_REG 0x09
/* Sensor time registers */
#define BMA400_SENSOR_TIME0 0x0a
#define BMA400_SENSOR_TIME1 0x0b
#define BMA400_SENSOR_TIME2 0x0c
/* Event and interrupt registers */
#define BMA400_EVENT_REG 0x0d
#define BMA400_INT_STAT0_REG 0x0e
#define BMA400_INT_STAT1_REG 0x0f
#define BMA400_INT_STAT2_REG 0x10
/* Temperature register */
#define BMA400_TEMP_DATA_REG 0x11
/* FIFO length and data registers */
#define BMA400_FIFO_LENGTH0_REG 0x12
#define BMA400_FIFO_LENGTH1_REG 0x13
#define BMA400_FIFO_DATA_REG 0x14
/* Step count registers */
#define BMA400_STEP_CNT0_REG 0x15
#define BMA400_STEP_CNT1_REG 0x16
#define BMA400_STEP_CNT3_REG 0x17
#define BMA400_STEP_STAT_REG 0x18
/*
* Read-write configuration registers
*/
#define BMA400_ACC_CONFIG0_REG 0x19
#define BMA400_ACC_CONFIG1_REG 0x1a
#define BMA400_ACC_CONFIG2_REG 0x1b
#define BMA400_CMD_REG 0x7e
/* Chip ID of BMA 400 devices found in the chip ID register. */
#define BMA400_ID_REG_VAL 0x90
#define BMA400_LP_OSR_SHIFT 5
#define BMA400_NP_OSR_SHIFT 4
#define BMA400_SCALE_SHIFT 6
#define BMA400_TWO_BITS_MASK GENMASK(1, 0)
#define BMA400_LP_OSR_MASK GENMASK(6, 5)
#define BMA400_NP_OSR_MASK GENMASK(5, 4)
#define BMA400_ACC_ODR_MASK GENMASK(3, 0)
#define BMA400_ACC_SCALE_MASK GENMASK(7, 6)
#define BMA400_ACC_ODR_MIN_RAW 0x05
#define BMA400_ACC_ODR_LP_RAW 0x06
#define BMA400_ACC_ODR_MAX_RAW 0x0b
#define BMA400_ACC_ODR_MAX_HZ 800
#define BMA400_ACC_ODR_MIN_WHOLE_HZ 25
#define BMA400_ACC_ODR_MIN_HZ 12
#define BMA400_SCALE_MIN 38357
#define BMA400_SCALE_MAX 306864
#define BMA400_NUM_REGULATORS 2
#define BMA400_VDD_REGULATOR 0
#define BMA400_VDDIO_REGULATOR 1
extern const struct regmap_config bma400_regmap_config;
int bma400_probe(struct device *dev, struct regmap *regmap, const char *name);
int bma400_remove(struct device *dev);
#endif

View file

@ -0,0 +1,852 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Core IIO driver for Bosch BMA400 triaxial acceleration sensor.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*
* TODO:
* - Support for power management
* - Support events and interrupts
* - Create channel for step count
* - Create channel for sensor time
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "bma400.h"
/*
* The G-range selection may be one of 2g, 4g, 8, or 16g. The scale may
* be selected with the acc_range bits of the ACC_CONFIG1 register.
* NB: This buffer is populated in the device init.
*/
static int bma400_scales[8];
/*
* See the ACC_CONFIG1 section of the datasheet.
* NB: This buffer is populated in the device init.
*/
static int bma400_sample_freqs[14];
static const int bma400_osr_range[] = { 0, 1, 3 };
/* See the ACC_CONFIG0 section of the datasheet */
enum bma400_power_mode {
POWER_MODE_SLEEP = 0x00,
POWER_MODE_LOW = 0x01,
POWER_MODE_NORMAL = 0x02,
POWER_MODE_INVALID = 0x03,
};
struct bma400_sample_freq {
int hz;
int uhz;
};
struct bma400_data {
struct device *dev;
struct regmap *regmap;
struct regulator_bulk_data regulators[BMA400_NUM_REGULATORS];
struct mutex mutex; /* data register lock */
struct iio_mount_matrix orientation;
enum bma400_power_mode power_mode;
struct bma400_sample_freq sample_freq;
int oversampling_ratio;
int scale;
};
static bool bma400_is_writable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_CHIP_ID_REG:
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return false;
default:
return true;
}
}
static bool bma400_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case BMA400_ERR_REG:
case BMA400_STATUS_REG:
case BMA400_X_AXIS_LSB_REG:
case BMA400_X_AXIS_MSB_REG:
case BMA400_Y_AXIS_LSB_REG:
case BMA400_Y_AXIS_MSB_REG:
case BMA400_Z_AXIS_LSB_REG:
case BMA400_Z_AXIS_MSB_REG:
case BMA400_SENSOR_TIME0:
case BMA400_SENSOR_TIME1:
case BMA400_SENSOR_TIME2:
case BMA400_EVENT_REG:
case BMA400_INT_STAT0_REG:
case BMA400_INT_STAT1_REG:
case BMA400_INT_STAT2_REG:
case BMA400_TEMP_DATA_REG:
case BMA400_FIFO_LENGTH0_REG:
case BMA400_FIFO_LENGTH1_REG:
case BMA400_FIFO_DATA_REG:
case BMA400_STEP_CNT0_REG:
case BMA400_STEP_CNT1_REG:
case BMA400_STEP_CNT3_REG:
case BMA400_STEP_STAT_REG:
return true;
default:
return false;
}
}
const struct regmap_config bma400_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BMA400_CMD_REG,
.cache_type = REGCACHE_RBTREE,
.writeable_reg = bma400_is_writable_reg,
.volatile_reg = bma400_is_volatile_reg,
};
EXPORT_SYMBOL(bma400_regmap_config);
static const struct iio_mount_matrix *
bma400_accel_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct bma400_data *data = iio_priv(indio_dev);
return &data->orientation;
}
static const struct iio_chan_spec_ext_info bma400_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, bma400_accel_get_mount_matrix),
{ }
};
#define BMA400_ACC_CHANNEL(_axis) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
.ext_info = bma400_ext_info, \
}
static const struct iio_chan_spec bma400_channels[] = {
BMA400_ACC_CHANNEL(X),
BMA400_ACC_CHANNEL(Y),
BMA400_ACC_CHANNEL(Z),
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
};
static int bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
{
unsigned int raw_temp;
int host_temp;
int ret;
if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &raw_temp);
if (ret)
return ret;
host_temp = sign_extend32(raw_temp, 7);
/*
* The formula for the TEMP_DATA register in the datasheet
* is: x * 0.5 + 23
*/
*val = (host_temp >> 1) + 23;
*val2 = (host_temp & 0x1) * 500000;
return IIO_VAL_INT_PLUS_MICRO;
}
static int bma400_get_accel_reg(struct bma400_data *data,
const struct iio_chan_spec *chan,
int *val)
{
__le16 raw_accel;
int lsb_reg;
int ret;
if (data->power_mode == POWER_MODE_SLEEP)
return -EBUSY;
switch (chan->channel2) {
case IIO_MOD_X:
lsb_reg = BMA400_X_AXIS_LSB_REG;
break;
case IIO_MOD_Y:
lsb_reg = BMA400_Y_AXIS_LSB_REG;
break;
case IIO_MOD_Z:
lsb_reg = BMA400_Z_AXIS_LSB_REG;
break;
default:
dev_err(data->dev, "invalid axis channel modifier\n");
return -EINVAL;
}
/* bulk read two registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, lsb_reg, &raw_accel,
sizeof(raw_accel));
if (ret)
return ret;
*val = sign_extend32(le16_to_cpu(raw_accel), 11);
return IIO_VAL_INT;
}
static void bma400_output_data_rate_from_raw(int raw, unsigned int *val,
unsigned int *val2)
{
*val = BMA400_ACC_ODR_MAX_HZ >> (BMA400_ACC_ODR_MAX_RAW - raw);
if (raw > BMA400_ACC_ODR_MIN_RAW)
*val2 = 0;
else
*val2 = 500000;
}
static int bma400_get_accel_output_data_rate(struct bma400_data *data)
{
unsigned int val;
unsigned int odr;
int ret;
switch (data->power_mode) {
case POWER_MODE_LOW:
/*
* Runs at a fixed rate in low-power mode. See section 4.3
* in the datasheet.
*/
bma400_output_data_rate_from_raw(BMA400_ACC_ODR_LP_RAW,
&data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_NORMAL:
/*
* In normal mode the ODR can be found in the ACC_CONFIG1
* register.
*/
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
goto error;
odr = val & BMA400_ACC_ODR_MASK;
if (odr < BMA400_ACC_ODR_MIN_RAW ||
odr > BMA400_ACC_ODR_MAX_RAW) {
ret = -EINVAL;
goto error;
}
bma400_output_data_rate_from_raw(odr, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
case POWER_MODE_SLEEP:
data->sample_freq.hz = 0;
data->sample_freq.uhz = 0;
return 0;
default:
ret = 0;
goto error;
}
error:
data->sample_freq.hz = -1;
data->sample_freq.uhz = -1;
return ret;
}
static int bma400_set_accel_output_data_rate(struct bma400_data *data,
int hz, int uhz)
{
unsigned int idx;
unsigned int odr;
unsigned int val;
int ret;
if (hz >= BMA400_ACC_ODR_MIN_WHOLE_HZ) {
if (uhz || hz > BMA400_ACC_ODR_MAX_HZ)
return -EINVAL;
/* Note this works because MIN_WHOLE_HZ is odd */
idx = __ffs(hz);
if (hz >> idx != BMA400_ACC_ODR_MIN_WHOLE_HZ)
return -EINVAL;
idx += BMA400_ACC_ODR_MIN_RAW + 1;
} else if (hz == BMA400_ACC_ODR_MIN_HZ && uhz == 500000) {
idx = BMA400_ACC_ODR_MIN_RAW;
} else {
return -EINVAL;
}
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;
/* preserve the range and normal mode osr */
odr = (~BMA400_ACC_ODR_MASK & val) | idx;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG, odr);
if (ret)
return ret;
bma400_output_data_rate_from_raw(idx, &data->sample_freq.hz,
&data->sample_freq.uhz);
return 0;
}
static int bma400_get_accel_oversampling_ratio(struct bma400_data *data)
{
unsigned int val;
unsigned int osr;
int ret;
/*
* The oversampling ratio is stored in a different register
* based on the power-mode. In normal mode the OSR is stored
* in ACC_CONFIG1. In low-power mode it is stored in
* ACC_CONFIG0.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}
osr = (val & BMA400_LP_OSR_MASK) >> BMA400_LP_OSR_SHIFT;
data->oversampling_ratio = osr;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret) {
data->oversampling_ratio = -1;
return ret;
}
osr = (val & BMA400_NP_OSR_MASK) >> BMA400_NP_OSR_SHIFT;
data->oversampling_ratio = osr;
return 0;
case POWER_MODE_SLEEP:
data->oversampling_ratio = 0;
return 0;
default:
data->oversampling_ratio = -1;
return -EINVAL;
}
}
static int bma400_set_accel_oversampling_ratio(struct bma400_data *data,
int val)
{
unsigned int acc_config;
int ret;
if (val & ~BMA400_TWO_BITS_MASK)
return -EINVAL;
/*
* The oversampling ratio is stored in a different register
* based on the power-mode.
*/
switch (data->power_mode) {
case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG,
&acc_config);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
(acc_config & ~BMA400_LP_OSR_MASK) |
(val << BMA400_LP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR\n");
return ret;
}
data->oversampling_ratio = val;
return 0;
case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG,
&acc_config);
if (ret)
return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_NP_OSR_MASK) |
(val << BMA400_NP_OSR_SHIFT));
if (ret) {
dev_err(data->dev, "Failed to write out OSR\n");
return ret;
}
data->oversampling_ratio = val;
return 0;
default:
return -EINVAL;
}
return ret;
}
static int bma400_accel_scale_to_raw(struct bma400_data *data,
unsigned int val)
{
int raw;
if (val == 0)
return -EINVAL;
/* Note this works because BMA400_SCALE_MIN is odd */
raw = __ffs(val);
if (val >> raw != BMA400_SCALE_MIN)
return -EINVAL;
return raw;
}
static int bma400_get_accel_scale(struct bma400_data *data)
{
unsigned int raw_scale;
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val);
if (ret)
return ret;
raw_scale = (val & BMA400_ACC_SCALE_MASK) >> BMA400_SCALE_SHIFT;
if (raw_scale > BMA400_TWO_BITS_MASK)
return -EINVAL;
data->scale = BMA400_SCALE_MIN << raw_scale;
return 0;
}
static int bma400_set_accel_scale(struct bma400_data *data, unsigned int val)
{
unsigned int acc_config;
int raw;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &acc_config);
if (ret)
return ret;
raw = bma400_accel_scale_to_raw(data, val);
if (raw < 0)
return raw;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_ACC_SCALE_MASK) |
(raw << BMA400_SCALE_SHIFT));
if (ret)
return ret;
data->scale = val;
return 0;
}
static int bma400_get_power_mode(struct bma400_data *data)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_STATUS_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read status register\n");
return ret;
}
data->power_mode = (val >> 1) & BMA400_TWO_BITS_MASK;
return 0;
}
static int bma400_set_power_mode(struct bma400_data *data,
enum bma400_power_mode mode)
{
unsigned int val;
int ret;
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val);
if (ret)
return ret;
if (data->power_mode == mode)
return 0;
if (mode == POWER_MODE_INVALID)
return -EINVAL;
/* Preserve the low-power oversample ratio etc */
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
mode | (val & ~BMA400_TWO_BITS_MASK));
if (ret) {
dev_err(data->dev, "Failed to write to power-mode\n");
return ret;
}
data->power_mode = mode;
/*
* Update our cached osr and odr based on the new
* power-mode.
*/
bma400_get_accel_output_data_rate(data);
bma400_get_accel_oversampling_ratio(data);
return 0;
}
static void bma400_init_tables(void)
{
int raw;
int i;
for (i = 0; i + 1 < ARRAY_SIZE(bma400_sample_freqs); i += 2) {
raw = (i / 2) + 5;
bma400_output_data_rate_from_raw(raw, &bma400_sample_freqs[i],
&bma400_sample_freqs[i + 1]);
}
for (i = 0; i + 1 < ARRAY_SIZE(bma400_scales); i += 2) {
raw = i / 2;
bma400_scales[i] = 0;
bma400_scales[i + 1] = BMA400_SCALE_MIN << raw;
}
}
static int bma400_init(struct bma400_data *data)
{
unsigned int val;
int ret;
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val);
if (ret) {
dev_err(data->dev, "Failed to read chip id register\n");
goto out;
}
if (val != BMA400_ID_REG_VAL) {
dev_err(data->dev, "Chip ID mismatch\n");
ret = -ENODEV;
goto out;
}
data->regulators[BMA400_VDD_REGULATOR].supply = "vdd";
data->regulators[BMA400_VDDIO_REGULATOR].supply = "vddio";
ret = devm_regulator_bulk_get(data->dev,
ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(data->dev,
"Failed to get regulators: %d\n",
ret);
goto out;
}
ret = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators);
if (ret) {
dev_err(data->dev, "Failed to enable regulators: %d\n",
ret);
goto out;
}
ret = bma400_get_power_mode(data);
if (ret) {
dev_err(data->dev, "Failed to get the initial power-mode\n");
goto err_reg_disable;
}
if (data->power_mode != POWER_MODE_NORMAL) {
ret = bma400_set_power_mode(data, POWER_MODE_NORMAL);
if (ret) {
dev_err(data->dev, "Failed to wake up the device\n");
goto err_reg_disable;
}
/*
* TODO: The datasheet waits 1500us here in the example, but
* lists 2/ODR as the wakeup time.
*/
usleep_range(1500, 2000);
}
bma400_init_tables();
ret = bma400_get_accel_output_data_rate(data);
if (ret)
goto err_reg_disable;
ret = bma400_get_accel_oversampling_ratio(data);
if (ret)
goto err_reg_disable;
ret = bma400_get_accel_scale(data);
if (ret)
goto err_reg_disable;
/*
* Once the interrupt engine is supported we might use the
* data_src_reg, but for now ensure this is set to the
* variable ODR filter selectable by the sample frequency
* channel.
*/
return regmap_write(data->regmap, BMA400_ACC_CONFIG2_REG, 0x00);
err_reg_disable:
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
out:
return ret;
}
static int bma400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&data->mutex);
ret = bma400_get_temp_reg(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
ret = bma400_get_accel_reg(data, chan, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
switch (chan->type) {
case IIO_ACCEL:
if (data->sample_freq.hz < 0)
return -EINVAL;
*val = data->sample_freq.hz;
*val2 = data->sample_freq.uhz;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP:
/*
* Runs at a fixed sampling frequency. See Section 4.4
* of the datasheet.
*/
*val = 6;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->scale;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
/*
* TODO: We could avoid this logic and returning -EINVAL here if
* we set both the low-power and normal mode OSR registers when
* we configure the device.
*/
if (data->oversampling_ratio < 0)
return -EINVAL;
*val = data->oversampling_ratio;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int bma400_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SCALE:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_scales;
*length = ARRAY_SIZE(bma400_scales);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*type = IIO_VAL_INT;
*vals = bma400_osr_range;
*length = ARRAY_SIZE(bma400_osr_range);
return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SAMP_FREQ:
*type = IIO_VAL_INT_PLUS_MICRO;
*vals = bma400_sample_freqs;
*length = ARRAY_SIZE(bma400_sample_freqs);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int bma400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2,
long mask)
{
struct bma400_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
/*
* The sample frequency is readonly for the temperature
* register and a fixed value in low-power mode.
*/
if (chan->type != IIO_ACCEL)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_output_data_rate(data, val, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SCALE:
if (val != 0 || val2 > BMA400_SCALE_MAX)
return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_scale(data, val2);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
mutex_lock(&data->mutex);
ret = bma400_set_accel_oversampling_ratio(data, val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static int bma400_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info bma400_info = {
.read_raw = bma400_read_raw,
.read_avail = bma400_read_avail,
.write_raw = bma400_write_raw,
.write_raw_get_fmt = bma400_write_raw_get_fmt,
};
int bma400_probe(struct device *dev, struct regmap *regmap, const char *name)
{
struct iio_dev *indio_dev;
struct bma400_data *data;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
data->regmap = regmap;
data->dev = dev;
ret = bma400_init(data);
if (ret)
return ret;
ret = iio_read_mount_matrix(dev, "mount-matrix", &data->orientation);
if (ret)
return ret;
mutex_init(&data->mutex);
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->info = &bma400_info;
indio_dev->channels = bma400_channels;
indio_dev->num_channels = ARRAY_SIZE(bma400_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
dev_set_drvdata(dev, indio_dev);
return iio_device_register(indio_dev);
}
EXPORT_SYMBOL(bma400_probe);
int bma400_remove(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bma400_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = bma400_set_power_mode(data, POWER_MODE_SLEEP);
mutex_unlock(&data->mutex);
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
iio_device_unregister(indio_dev);
return ret;
}
EXPORT_SYMBOL(bma400_remove);
MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>");
MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor core");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C IIO driver for Bosch BMA400 triaxial acceleration sensor.
*
* Copyright 2019 Dan Robertson <dan@dlrobertson.com>
*
* I2C address is either 0x14 or 0x15 depending on SDO
*/
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "bma400.h"
static int bma400_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &bma400_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "failed to create regmap\n");
return PTR_ERR(regmap);
}
return bma400_probe(&client->dev, regmap, id->name);
}
static int bma400_i2c_remove(struct i2c_client *client)
{
return bma400_remove(&client->dev);
}
static const struct i2c_device_id bma400_i2c_ids[] = {
{ "bma400", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bma400_i2c_ids);
static const struct of_device_id bma400_of_i2c_match[] = {
{ .compatible = "bosch,bma400" },
{ }
};
MODULE_DEVICE_TABLE(of, bma400_of_i2c_match);
static struct i2c_driver bma400_i2c_driver = {
.driver = {
.name = "bma400",
.of_match_table = bma400_of_i2c_match,
},
.probe = bma400_i2c_probe,
.remove = bma400_i2c_remove,
.id_table = bma400_i2c_ids,
};
module_i2c_driver(bma400_i2c_driver);
MODULE_AUTHOR("Dan Robertson <dan@dlrobertson.com>");
MODULE_DESCRIPTION("Bosch BMA400 triaxial acceleration sensor (I2C)");
MODULE_LICENSE("GPL");

View file

@ -64,7 +64,7 @@ enum st_accel_type {
* struct st_sensors_platform_data - default accel platform data
* @drdy_int_pin: default accel DRDY is available on INT1 pin.
*/
static const struct st_sensors_platform_data default_accel_pdata = {
static __maybe_unused const struct st_sensors_platform_data default_accel_pdata = {
.drdy_int_pin = 1,
};

View file

@ -119,8 +119,6 @@ static const struct acpi_device_id st_accel_acpi_match[] = {
{ },
};
MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
#else
#define st_accel_acpi_match NULL
#endif
static const struct i2c_device_id st_accel_id_table[] = {

View file

@ -21,6 +21,13 @@ config AD_SIGMA_DELTA
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
config AD7091R5
tristate "Analog Devices AD7091R5 ADC Driver"
depends on I2C
select REGMAP_I2C
help
Say yes here to build support for Analog Devices AD7091R-5 ADC.
config AD7124
tristate "Analog Devices AD7124 and similar sigma-delta ADCs driver"
depends on SPI_MASTER
@ -523,6 +530,16 @@ config LTC2485
To compile this driver as a module, choose M here: the module will be
called ltc2485.
config LTC2496
tristate "Linear Technology LTC2496 ADC driver"
depends on SPI
help
Say yes here to build support for Linear Technology LTC2496
16-Bit 8-/16-Channel Delta Sigma ADC.
To compile this driver as a module, choose M here: the module will be
called ltc2496.
config LTC2497
tristate "Linear Technology LTC2497 ADC driver"
depends on I2C

View file

@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7091R5) += ad7091r5.o ad7091r-base.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7266) += ad7266.o
obj-$(CONFIG_AD7291) += ad7291.o
@ -50,7 +51,8 @@ obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
obj-$(CONFIG_LTC2471) += ltc2471.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_LTC2497) += ltc2497.o
obj-$(CONFIG_LTC2496) += ltc2496.o ltc2497-core.o
obj-$(CONFIG_LTC2497) += ltc2497.o ltc2497-core.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1118) += max1118.o

View file

@ -0,0 +1,298 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AD7091RX Analog to Digital converter driver
*
* Copyright 2014-2019 Analog Devices Inc.
*/
#include <linux/bitops.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include "ad7091r-base.h"
#define AD7091R_REG_RESULT 0
#define AD7091R_REG_CHANNEL 1
#define AD7091R_REG_CONF 2
#define AD7091R_REG_ALERT 3
#define AD7091R_REG_CH_LOW_LIMIT(ch) ((ch) * 3 + 4)
#define AD7091R_REG_CH_HIGH_LIMIT(ch) ((ch) * 3 + 5)
#define AD7091R_REG_CH_HYSTERESIS(ch) ((ch) * 3 + 6)
/* AD7091R_REG_RESULT */
#define AD7091R_REG_RESULT_CH_ID(x) (((x) >> 13) & 0x3)
#define AD7091R_REG_RESULT_CONV_RESULT(x) ((x) & 0xfff)
/* AD7091R_REG_CONF */
#define AD7091R_REG_CONF_AUTO BIT(8)
#define AD7091R_REG_CONF_CMD BIT(10)
#define AD7091R_REG_CONF_MODE_MASK \
(AD7091R_REG_CONF_AUTO | AD7091R_REG_CONF_CMD)
enum ad7091r_mode {
AD7091R_MODE_SAMPLE,
AD7091R_MODE_COMMAND,
AD7091R_MODE_AUTOCYCLE,
};
struct ad7091r_state {
struct device *dev;
struct regmap *map;
struct regulator *vref;
const struct ad7091r_chip_info *chip_info;
enum ad7091r_mode mode;
struct mutex lock; /*lock to prevent concurent reads */
};
static int ad7091r_set_mode(struct ad7091r_state *st, enum ad7091r_mode mode)
{
int ret, conf;
switch (mode) {
case AD7091R_MODE_SAMPLE:
conf = 0;
break;
case AD7091R_MODE_COMMAND:
conf = AD7091R_REG_CONF_CMD;
break;
case AD7091R_MODE_AUTOCYCLE:
conf = AD7091R_REG_CONF_AUTO;
break;
default:
return -EINVAL;
}
ret = regmap_update_bits(st->map, AD7091R_REG_CONF,
AD7091R_REG_CONF_MODE_MASK, conf);
if (ret)
return ret;
st->mode = mode;
return 0;
}
static int ad7091r_set_channel(struct ad7091r_state *st, unsigned int channel)
{
unsigned int dummy;
int ret;
/* AD7091R_REG_CHANNEL specified which channels to be converted */
ret = regmap_write(st->map, AD7091R_REG_CHANNEL,
BIT(channel) | (BIT(channel) << 8));
if (ret)
return ret;
/*
* There is a latency of one conversion before the channel conversion
* sequence is updated
*/
return regmap_read(st->map, AD7091R_REG_RESULT, &dummy);
}
static int ad7091r_read_one(struct iio_dev *iio_dev,
unsigned int channel, unsigned int *read_val)
{
struct ad7091r_state *st = iio_priv(iio_dev);
unsigned int val;
int ret;
ret = ad7091r_set_channel(st, channel);
if (ret)
return ret;
ret = regmap_read(st->map, AD7091R_REG_RESULT, &val);
if (ret)
return ret;
if (AD7091R_REG_RESULT_CH_ID(val) != channel)
return -EIO;
*read_val = AD7091R_REG_RESULT_CONV_RESULT(val);
return 0;
}
static int ad7091r_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long m)
{
struct ad7091r_state *st = iio_priv(iio_dev);
unsigned int read_val;
int ret;
mutex_lock(&st->lock);
switch (m) {
case IIO_CHAN_INFO_RAW:
if (st->mode != AD7091R_MODE_COMMAND) {
ret = -EBUSY;
goto unlock;
}
ret = ad7091r_read_one(iio_dev, chan->channel, &read_val);
if (ret)
goto unlock;
*val = read_val;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
if (st->vref) {
ret = regulator_get_voltage(st->vref);
if (ret < 0)
goto unlock;
*val = ret / 1000;
} else {
*val = st->chip_info->vref_mV;
}
*val2 = chan->scan_type.realbits;
ret = IIO_VAL_FRACTIONAL_LOG2;
break;
default:
ret = -EINVAL;
break;
}
unlock:
mutex_unlock(&st->lock);
return ret;
}
static const struct iio_info ad7091r_info = {
.read_raw = ad7091r_read_raw,
};
static irqreturn_t ad7091r_event_handler(int irq, void *private)
{
struct ad7091r_state *st = (struct ad7091r_state *) private;
struct iio_dev *iio_dev = dev_get_drvdata(st->dev);
unsigned int i, read_val;
int ret;
s64 timestamp = iio_get_time_ns(iio_dev);
ret = regmap_read(st->map, AD7091R_REG_ALERT, &read_val);
if (ret)
return IRQ_HANDLED;
for (i = 0; i < st->chip_info->num_channels; i++) {
if (read_val & BIT(i * 2))
iio_push_event(iio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING), timestamp);
if (read_val & BIT(i * 2 + 1))
iio_push_event(iio_dev,
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
IIO_EV_TYPE_THRESH,
IIO_EV_DIR_FALLING), timestamp);
}
return IRQ_HANDLED;
}
static void ad7091r_remove(void *data)
{
struct ad7091r_state *st = data;
regulator_disable(st->vref);
}
int ad7091r_probe(struct device *dev, const char *name,
const struct ad7091r_chip_info *chip_info,
struct regmap *map, int irq)
{
struct iio_dev *iio_dev;
struct ad7091r_state *st;
int ret;
iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!iio_dev)
return -ENOMEM;
st = iio_priv(iio_dev);
st->dev = dev;
st->chip_info = chip_info;
st->map = map;
iio_dev->dev.parent = dev;
iio_dev->name = name;
iio_dev->info = &ad7091r_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->num_channels = chip_info->num_channels;
iio_dev->channels = chip_info->channels;
if (irq) {
ret = devm_request_threaded_irq(dev, irq, NULL,
ad7091r_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, name, st);
if (ret)
return ret;
}
st->vref = devm_regulator_get_optional(dev, "vref");
if (IS_ERR(st->vref)) {
if (PTR_ERR(st->vref) == -EPROBE_DEFER)
return -EPROBE_DEFER;
st->vref = NULL;
} else {
ret = regulator_enable(st->vref);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ad7091r_remove, st);
if (ret)
return ret;
}
/* Use command mode by default to convert only desired channels*/
ret = ad7091r_set_mode(st, AD7091R_MODE_COMMAND);
if (ret)
return ret;
return devm_iio_device_register(dev, iio_dev);
}
EXPORT_SYMBOL_GPL(ad7091r_probe);
static bool ad7091r_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AD7091R_REG_RESULT:
case AD7091R_REG_ALERT:
return false;
default:
return true;
}
}
static bool ad7091r_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AD7091R_REG_RESULT:
case AD7091R_REG_ALERT:
return true;
default:
return false;
}
}
const struct regmap_config ad7091r_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.writeable_reg = ad7091r_writeable_reg,
.volatile_reg = ad7091r_volatile_reg,
};
EXPORT_SYMBOL_GPL(ad7091r_regmap_config);
MODULE_AUTHOR("Beniamin Bia <beniamin.bia@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7091Rx multi-channel converters");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* AD7091RX Analog to Digital converter driver
*
* Copyright 2014-2019 Analog Devices Inc.
*/
#ifndef __DRIVERS_IIO_ADC_AD7091R_BASE_H__
#define __DRIVERS_IIO_ADC_AD7091R_BASE_H__
struct device;
struct ad7091r_state;
struct ad7091r_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
unsigned int vref_mV;
};
extern const struct regmap_config ad7091r_regmap_config;
int ad7091r_probe(struct device *dev, const char *name,
const struct ad7091r_chip_info *chip_info,
struct regmap *map, int irq);
#endif /* __DRIVERS_IIO_ADC_AD7091R_BASE_H__ */

113
drivers/iio/adc/ad7091r5.c Normal file
View file

@ -0,0 +1,113 @@
// SPDX-License-Identifier: GPL-2.0
/*
* AD7091R5 Analog to Digital converter driver
*
* Copyright 2014-2019 Analog Devices Inc.
*/
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "ad7091r-base.h"
static const struct iio_event_spec ad7091r5_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS),
},
};
#define AD7091R_CHANNEL(idx, bits, ev, num_ev) { \
.type = IIO_VOLTAGE, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.indexed = 1, \
.channel = idx, \
.event_spec = ev, \
.num_event_specs = num_ev, \
.scan_type.storagebits = 16, \
.scan_type.realbits = bits, \
}
static const struct iio_chan_spec ad7091r5_channels_irq[] = {
AD7091R_CHANNEL(0, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
AD7091R_CHANNEL(1, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
AD7091R_CHANNEL(2, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
AD7091R_CHANNEL(3, 12, ad7091r5_events, ARRAY_SIZE(ad7091r5_events)),
};
static const struct iio_chan_spec ad7091r5_channels_noirq[] = {
AD7091R_CHANNEL(0, 12, NULL, 0),
AD7091R_CHANNEL(1, 12, NULL, 0),
AD7091R_CHANNEL(2, 12, NULL, 0),
AD7091R_CHANNEL(3, 12, NULL, 0),
};
static const struct ad7091r_chip_info ad7091r5_chip_info_irq = {
.channels = ad7091r5_channels_irq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_irq),
.vref_mV = 2500,
};
static const struct ad7091r_chip_info ad7091r5_chip_info_noirq = {
.channels = ad7091r5_channels_noirq,
.num_channels = ARRAY_SIZE(ad7091r5_channels_noirq),
.vref_mV = 2500,
};
static int ad7091r5_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
const struct ad7091r_chip_info *chip_info;
struct regmap *map = devm_regmap_init_i2c(i2c, &ad7091r_regmap_config);
if (IS_ERR(map))
return PTR_ERR(map);
if (i2c->irq)
chip_info = &ad7091r5_chip_info_irq;
else
chip_info = &ad7091r5_chip_info_noirq;
return ad7091r_probe(&i2c->dev, id->name, chip_info, map, i2c->irq);
}
static const struct of_device_id ad7091r5_dt_ids[] = {
{ .compatible = "adi,ad7091r5" },
{},
};
MODULE_DEVICE_TABLE(of, ad7091r5_dt_ids);
static const struct i2c_device_id ad7091r5_i2c_ids[] = {
{"ad7091r5", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ad7091r5_i2c_ids);
static struct i2c_driver ad7091r5_driver = {
.driver = {
.name = "ad7091r5",
.of_match_table = ad7091r5_dt_ids,
},
.probe = ad7091r5_i2c_probe,
.id_table = ad7091r5_i2c_ids,
};
module_i2c_driver(ad7091r5_driver);
MODULE_AUTHOR("Beniamin Bia <beniamin.bia@analog.com>");
MODULE_DESCRIPTION("Analog Devices AD7091R5 multi-channel ADC driver");
MODULE_LICENSE("GPL v2");

View file

@ -11,7 +11,7 @@
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@ -34,7 +34,7 @@ struct ad7266_state {
enum ad7266_range range;
enum ad7266_mode mode;
bool fixed_addr;
struct gpio gpios[3];
struct gpio_desc *gpios[3];
/*
* DMA (thus cache coherency maintenance) requires the
@ -117,7 +117,7 @@ static void ad7266_select_input(struct ad7266_state *st, unsigned int nr)
}
for (i = 0; i < 3; ++i)
gpio_set_value(st->gpios[i].gpio, (bool)(nr & BIT(i)));
gpiod_set_value(st->gpios[i], (bool)(nr & BIT(i)));
}
static int ad7266_update_scan_mode(struct iio_dev *indio_dev,
@ -376,7 +376,7 @@ static void ad7266_init_channels(struct iio_dev *indio_dev)
}
static const char * const ad7266_gpio_labels[] = {
"AD0", "AD1", "AD2",
"ad0", "ad1", "ad2",
};
static int ad7266_probe(struct spi_device *spi)
@ -419,14 +419,14 @@ static int ad7266_probe(struct spi_device *spi)
if (!st->fixed_addr) {
for (i = 0; i < ARRAY_SIZE(st->gpios); ++i) {
st->gpios[i].gpio = pdata->addr_gpios[i];
st->gpios[i].flags = GPIOF_OUT_INIT_LOW;
st->gpios[i].label = ad7266_gpio_labels[i];
st->gpios[i] = devm_gpiod_get(&spi->dev,
ad7266_gpio_labels[i],
GPIOD_OUT_LOW);
if (IS_ERR(st->gpios[i])) {
ret = PTR_ERR(st->gpios[i]);
goto error_disable_reg;
}
}
ret = gpio_request_array(st->gpios,
ARRAY_SIZE(st->gpios));
if (ret)
goto error_disable_reg;
}
} else {
st->fixed_addr = true;
@ -465,7 +465,7 @@ static int ad7266_probe(struct spi_device *spi)
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
&ad7266_trigger_handler, &iio_triggered_buffer_setup_ops);
if (ret)
goto error_free_gpios;
goto error_disable_reg;
ret = iio_device_register(indio_dev);
if (ret)
@ -475,9 +475,6 @@ static int ad7266_probe(struct spi_device *spi)
error_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
error_free_gpios:
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
error_disable_reg:
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
@ -492,8 +489,6 @@ static int ad7266_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
if (!IS_ERR(st->reg))
regulator_disable(st->reg);

View file

@ -43,11 +43,17 @@ enum ad7887_channels {
/**
* struct ad7887_chip_info - chip specifc information
* @int_vref_mv: the internal reference voltage
* @channel: channel specification
* @channels: channels specification
* @num_channels: number of channels
* @dual_channels: channels specification in dual mode
* @num_dual_channels: number of channels in dual mode
*/
struct ad7887_chip_info {
u16 int_vref_mv;
struct iio_chan_spec channel[3];
const struct iio_chan_spec *channels;
unsigned int num_channels;
const struct iio_chan_spec *dual_channels;
unsigned int num_dual_channels;
};
struct ad7887_state {
@ -183,45 +189,43 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
#define AD7887_CHANNEL(x) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (x), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.address = (x), \
.scan_index = (x), \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.shift = 0, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec ad7887_channels[] = {
AD7887_CHANNEL(0),
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static const struct iio_chan_spec ad7887_dual_channels[] = {
AD7887_CHANNEL(0),
AD7887_CHANNEL(1),
IIO_CHAN_SOFT_TIMESTAMP(2),
};
static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
/*
* More devices added in future
*/
[ID_AD7887] = {
.channel[0] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 1,
.scan_index = 1,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.channel[1] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
.address = 0,
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 0,
.endianness = IIO_BE,
},
},
.channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2),
.channels = ad7887_channels,
.num_channels = ARRAY_SIZE(ad7887_channels),
.dual_channels = ad7887_dual_channels,
.num_dual_channels = ARRAY_SIZE(ad7887_dual_channels),
.int_vref_mv = 2500,
},
};
@ -306,11 +310,11 @@ static int ad7887_probe(struct spi_device *spi)
spi_message_init(&st->msg[AD7887_CH1]);
spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]);
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = 3;
indio_dev->channels = st->chip_info->dual_channels;
indio_dev->num_channels = st->chip_info->num_dual_channels;
} else {
indio_dev->channels = &st->chip_info->channel[1];
indio_dev->num_channels = 2;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
}
ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* AD7904/AD7914/AD7923/AD7924 SPI ADC driver
* AD7904/AD7914/AD7923/AD7924/AD7908/AD7918/AD7928 SPI ADC driver
*
* Copyright 2011 Analog Devices Inc (from AD7923 Driver)
* Copyright 2012 CS Systemes d'Information
@ -29,15 +29,10 @@
#define AD7923_PM_MODE_AS (1) /* auto shutdown */
#define AD7923_PM_MODE_FS (2) /* full shutdown */
#define AD7923_PM_MODE_OPS (3) /* normal operation */
#define AD7923_CHANNEL_0 (0) /* analog input 0 */
#define AD7923_CHANNEL_1 (1) /* analog input 1 */
#define AD7923_CHANNEL_2 (2) /* analog input 2 */
#define AD7923_CHANNEL_3 (3) /* analog input 3 */
#define AD7923_SEQUENCE_OFF (0) /* no sequence fonction */
#define AD7923_SEQUENCE_PROTECT (2) /* no interrupt write cycle */
#define AD7923_SEQUENCE_ON (3) /* continuous sequence */
#define AD7923_MAX_CHAN 4
#define AD7923_PM_MODE_WRITE(mode) ((mode) << 4) /* write mode */
#define AD7923_CHANNEL_WRITE(channel) ((channel) << 6) /* write channel */
@ -78,6 +73,9 @@ enum ad7923_id {
AD7904,
AD7914,
AD7924,
AD7908,
AD7918,
AD7928
};
#define AD7923_V_CHAN(index, bits) \
@ -106,9 +104,25 @@ const struct iio_chan_spec name ## _channels[] = { \
IIO_CHAN_SOFT_TIMESTAMP(4), \
}
#define DECLARE_AD7908_CHANNELS(name, bits) \
const struct iio_chan_spec name ## _channels[] = { \
AD7923_V_CHAN(0, bits), \
AD7923_V_CHAN(1, bits), \
AD7923_V_CHAN(2, bits), \
AD7923_V_CHAN(3, bits), \
AD7923_V_CHAN(4, bits), \
AD7923_V_CHAN(5, bits), \
AD7923_V_CHAN(6, bits), \
AD7923_V_CHAN(7, bits), \
IIO_CHAN_SOFT_TIMESTAMP(8), \
}
static DECLARE_AD7923_CHANNELS(ad7904, 8);
static DECLARE_AD7923_CHANNELS(ad7914, 10);
static DECLARE_AD7923_CHANNELS(ad7924, 12);
static DECLARE_AD7908_CHANNELS(ad7908, 8);
static DECLARE_AD7908_CHANNELS(ad7918, 10);
static DECLARE_AD7908_CHANNELS(ad7928, 12);
static const struct ad7923_chip_info ad7923_chip_info[] = {
[AD7904] = {
@ -123,6 +137,18 @@ static const struct ad7923_chip_info ad7923_chip_info[] = {
.channels = ad7924_channels,
.num_channels = ARRAY_SIZE(ad7924_channels),
},
[AD7908] = {
.channels = ad7908_channels,
.num_channels = ARRAY_SIZE(ad7908_channels),
},
[AD7918] = {
.channels = ad7918_channels,
.num_channels = ARRAY_SIZE(ad7918_channels),
},
[AD7928] = {
.channels = ad7928_channels,
.num_channels = ARRAY_SIZE(ad7928_channels),
},
};
/**
@ -135,7 +161,11 @@ static int ad7923_update_scan_mode(struct iio_dev *indio_dev,
int i, cmd, len;
len = 0;
for_each_set_bit(i, active_scan_mask, AD7923_MAX_CHAN) {
/*
* For this driver the last channel is always the software timestamp so
* skip that one.
*/
for_each_set_bit(i, active_scan_mask, indio_dev->num_channels - 1) {
cmd = AD7923_WRITE_CR | AD7923_CHANNEL_WRITE(i) |
AD7923_SEQUENCE_WRITE(AD7923_SEQUENCE_OFF) |
st->settings;
@ -188,7 +218,7 @@ done:
return IRQ_HANDLED;
}
static int ad7923_scan_direct(struct ad7923_state *st, unsigned ch)
static int ad7923_scan_direct(struct ad7923_state *st, unsigned int ch)
{
int ret, cmd;
@ -348,13 +378,29 @@ static const struct spi_device_id ad7923_id[] = {
{"ad7914", AD7914},
{"ad7923", AD7924},
{"ad7924", AD7924},
{"ad7908", AD7908},
{"ad7918", AD7918},
{"ad7928", AD7928},
{}
};
MODULE_DEVICE_TABLE(spi, ad7923_id);
static const struct of_device_id ad7923_of_match[] = {
{ .compatible = "adi,ad7904", },
{ .compatible = "adi,ad7914", },
{ .compatible = "adi,ad7923", },
{ .compatible = "adi,ad7924", },
{ .compatible = "adi,ad7908", },
{ .compatible = "adi,ad7918", },
{ .compatible = "adi,ad7928", },
{ },
};
MODULE_DEVICE_TABLE(of, ad7923_of_match);
static struct spi_driver ad7923_driver = {
.driver = {
.name = "ad7923",
.of_match_table = ad7923_of_match,
},
.probe = ad7923_probe,
.remove = ad7923_remove,
@ -364,5 +410,5 @@ module_spi_driver(ad7923_driver);
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
MODULE_DESCRIPTION("Analog Devices AD7923 and similar ADC");
MODULE_LICENSE("GPL v2");

View file

@ -167,6 +167,21 @@ static int ad799x_read_config(struct ad799x_state *st)
}
}
static int ad799x_update_config(struct ad799x_state *st, u16 config)
{
int ret;
ret = ad799x_write_config(st, config);
if (ret < 0)
return ret;
ret = ad799x_read_config(st);
if (ret < 0)
return ret;
st->config = ret;
return 0;
}
/**
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer
*
@ -808,13 +823,9 @@ static int ad799x_probe(struct i2c_client *client,
indio_dev->channels = st->chip_config->channel;
indio_dev->num_channels = chip_info->num_channels;
ret = ad799x_write_config(st, st->chip_config->default_config);
if (ret < 0)
ret = ad799x_update_config(st, st->chip_config->default_config);
if (ret)
goto error_disable_vref;
ret = ad799x_read_config(st);
if (ret < 0)
goto error_disable_vref;
st->config = ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad799x_trigger_handler, NULL);
@ -864,6 +875,48 @@ static int ad799x_remove(struct i2c_client *client)
return 0;
}
static int __maybe_unused ad799x_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ad799x_state *st = iio_priv(indio_dev);
regulator_disable(st->vref);
regulator_disable(st->reg);
return 0;
}
static int __maybe_unused ad799x_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
ret = regulator_enable(st->reg);
if (ret) {
dev_err(dev, "Unable to enable vcc regulator\n");
return ret;
}
ret = regulator_enable(st->vref);
if (ret) {
regulator_disable(st->reg);
dev_err(dev, "Unable to enable vref regulator\n");
return ret;
}
/* resync config */
ret = ad799x_update_config(st, st->config);
if (ret) {
regulator_disable(st->vref);
regulator_disable(st->reg);
return ret;
}
return 0;
}
static SIMPLE_DEV_PM_OPS(ad799x_pm_ops, ad799x_suspend, ad799x_resume);
static const struct i2c_device_id ad799x_id[] = {
{ "ad7991", ad7991 },
{ "ad7995", ad7995 },
@ -881,6 +934,7 @@ MODULE_DEVICE_TABLE(i2c, ad799x_id);
static struct i2c_driver ad799x_driver = {
.driver = {
.name = "ad799x",
.pm = &ad799x_pm_ops,
},
.probe = ad799x_probe,
.remove = ad799x_remove,

108
drivers/iio/adc/ltc2496.c Normal file
View file

@ -0,0 +1,108 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ltc2496.c - Driver for Analog Devices/Linear Technology LTC2496 ADC
*
* Based on ltc2497.c which has
* Copyright (C) 2017 Analog Devices Inc.
*
* Licensed under the GPL-2.
*
* Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2496fc.pdf
*/
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include "ltc2497.h"
struct ltc2496_driverdata {
/* this must be the first member */
struct ltc2497core_driverdata common_ddata;
struct spi_device *spi;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
*/
unsigned char rxbuf[3] ____cacheline_aligned;
unsigned char txbuf[3];
};
static int ltc2496_result_and_measure(struct ltc2497core_driverdata *ddata,
u8 address, int *val)
{
struct ltc2496_driverdata *st =
container_of(ddata, struct ltc2496_driverdata, common_ddata);
struct spi_transfer t = {
.tx_buf = st->txbuf,
.rx_buf = st->rxbuf,
.len = sizeof(st->txbuf),
};
int ret;
st->txbuf[0] = LTC2497_ENABLE | address;
ret = spi_sync_transfer(st->spi, &t, 1);
if (ret < 0) {
dev_err(&st->spi->dev, "spi_sync_transfer failed: %pe\n",
ERR_PTR(ret));
return ret;
}
if (val)
*val = ((st->rxbuf[0] & 0x3f) << 12 |
st->rxbuf[1] << 4 | st->rxbuf[2] >> 4) -
(1 << 17);
return 0;
}
static int ltc2496_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ltc2496_driverdata *st;
struct device *dev = &spi->dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->common_ddata.result_and_measure = ltc2496_result_and_measure;
return ltc2497core_probe(dev, indio_dev);
}
static int ltc2496_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
ltc2497core_remove(indio_dev);
return 0;
}
static const struct of_device_id ltc2496_of_match[] = {
{ .compatible = "lltc,ltc2496", },
{},
};
MODULE_DEVICE_TABLE(of, ltc2496_of_match);
static struct spi_driver ltc2496_driver = {
.driver = {
.name = "ltc2496",
.of_match_table = of_match_ptr(ltc2496_of_match),
},
.probe = ltc2496_probe,
.remove = ltc2496_remove,
};
module_spi_driver(ltc2496_driver);
MODULE_AUTHOR("Uwe Kleine-König <u.kleine-könig@pengutronix.de>");
MODULE_DESCRIPTION("Linear Technology LTC2496 ADC driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,243 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ltc2497-core.c - Common code for Analog Devices/Linear Technology
* LTC2496 and LTC2497 ADCs
*
* Copyright (C) 2017 Analog Devices Inc.
*/
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include "ltc2497.h"
#define LTC2497_SGL BIT(4)
#define LTC2497_DIFF 0
#define LTC2497_SIGN BIT(3)
static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata)
{
s64 time_elapsed;
time_elapsed = ktime_ms_delta(ktime_get(), ddata->time_prev);
if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
/* delay if conversion time not passed
* since last read or write
*/
if (msleep_interruptible(
LTC2497_CONVERSION_TIME_MS - time_elapsed))
return -ERESTARTSYS;
return 0;
}
if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
/* We're in automatic mode -
* so the last reading is still not outdated
*/
return 0;
}
return 1;
}
static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, int *val)
{
int ret;
ret = ltc2497core_wait_conv(ddata);
if (ret < 0)
return ret;
if (ret || ddata->addr_prev != address) {
ret = ddata->result_and_measure(ddata, address, NULL);
if (ret < 0)
return ret;
ddata->addr_prev = address;
if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
return -ERESTARTSYS;
}
ret = ddata->result_and_measure(ddata, address, val);
if (ret < 0)
return ret;
ddata->time_prev = ktime_get();
return ret;
}
static int ltc2497core_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ltc2497core_read(ddata, chan->address, val);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(ddata->ref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = 17;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = (_ds_name), \
}
#define LTC2497_CHAN_DIFF(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
.address = (_addr | _chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.differential = 1, \
}
static const struct iio_chan_spec ltc2497core_channel[] = {
LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
};
static const struct iio_info ltc2497core_info = {
.read_raw = ltc2497core_read_raw,
};
int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
{
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
int ret;
indio_dev->dev.parent = dev;
indio_dev->name = dev_name(dev);
indio_dev->info = &ltc2497core_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ltc2497core_channel;
indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);
if (ret < 0)
return ret;
ddata->ref = devm_regulator_get(dev, "vref");
if (IS_ERR(ddata->ref)) {
if (PTR_ERR(ddata->ref) != -EPROBE_DEFER)
dev_err(dev, "Failed to get vref regulator: %pe\n",
ddata->ref);
return PTR_ERR(ddata->ref);
}
ret = regulator_enable(ddata->ref);
if (ret < 0) {
dev_err(dev, "Failed to enable vref regulator: %pe\n",
ERR_PTR(ret));
return ret;
}
if (dev->platform_data) {
struct iio_map *plat_data;
plat_data = (struct iio_map *)dev->platform_data;
ret = iio_map_array_register(indio_dev, plat_data);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
goto err_regulator_disable;
}
}
ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
ddata->time_prev = ktime_get();
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_array_unregister;
return 0;
err_array_unregister:
iio_map_array_unregister(indio_dev);
err_regulator_disable:
regulator_disable(ddata->ref);
return ret;
}
EXPORT_SYMBOL_NS(ltc2497core_probe, LTC2497);
void ltc2497core_remove(struct iio_dev *indio_dev)
{
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
regulator_disable(ddata->ref);
}
EXPORT_SYMBOL_NS(ltc2497core_remove, LTC2497);
MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers");
MODULE_LICENSE("GPL v2");

View file

@ -7,27 +7,18 @@
* Datasheet: http://cds.linear.com/docs/en/datasheet/2497fd.pdf
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#define LTC2497_ENABLE 0xA0
#define LTC2497_SGL BIT(4)
#define LTC2497_DIFF 0
#define LTC2497_SIGN BIT(3)
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
#define LTC2497_CONVERSION_TIME_MS 150ULL
#include "ltc2497.h"
struct ltc2497_st {
struct ltc2497_driverdata {
/* this must be the first member */
struct ltc2497core_driverdata common_ddata;
struct i2c_client *client;
struct regulator *ref;
ktime_t time_prev;
u8 addr_prev;
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@ -35,232 +26,59 @@ struct ltc2497_st {
__be32 buf ____cacheline_aligned;
};
static int ltc2497_wait_conv(struct ltc2497_st *st)
static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
u8 address, int *val)
{
s64 time_elapsed;
time_elapsed = ktime_ms_delta(ktime_get(), st->time_prev);
if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {
/* delay if conversion time not passed
* since last read or write
*/
if (msleep_interruptible(
LTC2497_CONVERSION_TIME_MS - time_elapsed))
return -ERESTARTSYS;
return 0;
}
if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {
/* We're in automatic mode -
* so the last reading is stil not outdated
*/
return 0;
}
return 1;
}
static int ltc2497_read(struct ltc2497_st *st, u8 address, int *val)
{
struct i2c_client *client = st->client;
struct ltc2497_driverdata *st =
container_of(ddata, struct ltc2497_driverdata, common_ddata);
int ret;
ret = ltc2497_wait_conv(st);
if (ret < 0)
return ret;
if (ret || st->addr_prev != address) {
ret = i2c_smbus_write_byte(st->client,
LTC2497_ENABLE | address);
if (ret < 0)
if (val) {
ret = i2c_master_recv(st->client, (char *)&st->buf, 3);
if (ret < 0) {
dev_err(&st->client->dev, "i2c_master_recv failed\n");
return ret;
st->addr_prev = address;
if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))
return -ERESTARTSYS;
}
ret = i2c_master_recv(client, (char *)&st->buf, 3);
if (ret < 0) {
dev_err(&client->dev, "i2c_master_recv failed\n");
return ret;
}
st->time_prev = ktime_get();
}
/* convert and shift the result,
* and finally convert from offset binary to signed integer
*/
*val = (be32_to_cpu(st->buf) >> 14) - (1 << 17);
*val = (be32_to_cpu(st->buf) >> 14) - (1 << 17);
}
ret = i2c_smbus_write_byte(st->client,
LTC2497_ENABLE | address);
if (ret)
dev_err(&st->client->dev, "i2c transfer failed: %pe\n",
ERR_PTR(ret));
return ret;
}
static int ltc2497_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ltc2497_st *st = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ltc2497_read(st, chan->address, val);
mutex_unlock(&indio_dev->mlock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(st->ref);
if (ret < 0)
return ret;
*val = ret / 1000;
*val2 = 17;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
}
#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan), \
.address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.datasheet_name = (_ds_name), \
}
#define LTC2497_CHAN_DIFF(_chan, _addr) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \
.channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\
.address = (_addr | _chan), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.differential = 1, \
}
static const struct iio_chan_spec ltc2497_channel[] = {
LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF),
LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),
LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),
};
static const struct iio_info ltc2497_info = {
.read_raw = ltc2497_read_raw,
};
static int ltc2497_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct ltc2497_st *st;
struct iio_map *plat_data;
int ret;
struct ltc2497_driverdata *st;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_WRITE_BYTE))
return -EOPNOTSUPP;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
st->client = client;
st->common_ddata.result_and_measure = ltc2497_result_and_measure;
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->info = &ltc2497_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ltc2497_channel;
indio_dev->num_channels = ARRAY_SIZE(ltc2497_channel);
st->ref = devm_regulator_get(&client->dev, "vref");
if (IS_ERR(st->ref))
return PTR_ERR(st->ref);
ret = regulator_enable(st->ref);
if (ret < 0)
return ret;
if (client->dev.platform_data) {
plat_data = ((struct iio_map *)client->dev.platform_data);
ret = iio_map_array_register(indio_dev, plat_data);
if (ret) {
dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
goto err_regulator_disable;
}
}
ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
if (ret < 0)
goto err_array_unregister;
st->addr_prev = LTC2497_CONFIG_DEFAULT;
st->time_prev = ktime_get();
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_array_unregister;
return 0;
err_array_unregister:
iio_map_array_unregister(indio_dev);
err_regulator_disable:
regulator_disable(st->ref);
return ret;
return ltc2497core_probe(dev, indio_dev);
}
static int ltc2497_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ltc2497_st *st = iio_priv(indio_dev);
iio_map_array_unregister(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(st->ref);
ltc2497core_remove(indio_dev);
return 0;
}

18
drivers/iio/adc/ltc2497.h Normal file
View file

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#define LTC2497_ENABLE 0xA0
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
#define LTC2497_CONVERSION_TIME_MS 150ULL
struct ltc2497core_driverdata {
struct regulator *ref;
ktime_t time_prev;
u8 addr_prev;
int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
u8 address, int *val);
};
int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev);
void ltc2497core_remove(struct iio_dev *indio_dev);
MODULE_IMPORT_NS(LTC2497);

View file

@ -115,22 +115,17 @@ enum max9611_conf_ids {
* where data shall be read from
*/
static const unsigned int max9611_mux_conf[][2] = {
/* CONF_SENSE_1x */
{ MAX9611_MUX_SENSE_1x, MAX9611_REG_CSA_DATA },
/* CONF_SENSE_4x */
{ MAX9611_MUX_SENSE_4x, MAX9611_REG_CSA_DATA },
/* CONF_SENSE_8x */
{ MAX9611_MUX_SENSE_8x, MAX9611_REG_CSA_DATA },
/* CONF_IN_VOLT */
{ MAX9611_INPUT_VOLT, MAX9611_REG_RS_DATA },
/* CONF_TEMP */
{ MAX9611_MUX_TEMP, MAX9611_REG_TEMP_DATA },
[CONF_SENSE_1x] = { MAX9611_MUX_SENSE_1x, MAX9611_REG_CSA_DATA },
[CONF_SENSE_4x] = { MAX9611_MUX_SENSE_4x, MAX9611_REG_CSA_DATA },
[CONF_SENSE_8x] = { MAX9611_MUX_SENSE_8x, MAX9611_REG_CSA_DATA },
[CONF_IN_VOLT] = { MAX9611_INPUT_VOLT, MAX9611_REG_RS_DATA },
[CONF_TEMP] = { MAX9611_MUX_TEMP, MAX9611_REG_TEMP_DATA },
};
enum max9611_csa_gain {
CSA_GAIN_1x,
CSA_GAIN_4x,
CSA_GAIN_8x,
CSA_GAIN_1x = CONF_SENSE_1x,
CSA_GAIN_4x = CONF_SENSE_4x,
CSA_GAIN_8x = CONF_SENSE_8x,
};
enum max9611_csa_gain_params {
@ -148,18 +143,9 @@ enum max9611_csa_gain_params {
* value; use this structure to retrieve the correct LSB and offset values.
*/
static const unsigned int max9611_gain_conf[][2] = {
{ /* [0] CSA_GAIN_1x */
MAX9611_CSA_1X_LSB_nV,
MAX9611_CSA_1X_OFFS_RAW,
},
{ /* [1] CSA_GAIN_4x */
MAX9611_CSA_4X_LSB_nV,
MAX9611_CSA_4X_OFFS_RAW,
},
{ /* [2] CSA_GAIN_8x */
MAX9611_CSA_8X_LSB_nV,
MAX9611_CSA_8X_OFFS_RAW,
},
[CSA_GAIN_1x] = { MAX9611_CSA_1X_LSB_nV, MAX9611_CSA_1X_OFFS_RAW, },
[CSA_GAIN_4x] = { MAX9611_CSA_4X_LSB_nV, MAX9611_CSA_4X_OFFS_RAW, },
[CSA_GAIN_8x] = { MAX9611_CSA_8X_LSB_nV, MAX9611_CSA_8X_OFFS_RAW, },
};
enum max9611_chan_addrs {

View file

@ -280,21 +280,21 @@ out:
static const struct stm32_adc_common_regs stm32f4_adc_common_regs = {
.csr = STM32F4_ADC_CSR,
.ccr = STM32F4_ADC_CCR,
.eoc1_msk = STM32F4_EOC1,
.eoc2_msk = STM32F4_EOC2,
.eoc3_msk = STM32F4_EOC3,
.eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1,
.eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2,
.eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3,
.ier = STM32F4_ADC_CR1,
.eocie_msk = STM32F4_EOCIE,
.eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE,
};
/* STM32H7 common registers definitions */
static const struct stm32_adc_common_regs stm32h7_adc_common_regs = {
.csr = STM32H7_ADC_CSR,
.ccr = STM32H7_ADC_CCR,
.eoc1_msk = STM32H7_EOC_MST,
.eoc2_msk = STM32H7_EOC_SLV,
.eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST,
.eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV,
.ier = STM32H7_ADC_IER,
.eocie_msk = STM32H7_EOCIE,
.eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE,
};
static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = {

View file

@ -51,10 +51,12 @@
#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04)
/* STM32F4_ADC_SR - bit fields */
#define STM32F4_OVR BIT(5)
#define STM32F4_STRT BIT(4)
#define STM32F4_EOC BIT(1)
/* STM32F4_ADC_CR1 - bit fields */
#define STM32F4_OVRIE BIT(26)
#define STM32F4_RES_SHIFT 24
#define STM32F4_RES_MASK GENMASK(25, 24)
#define STM32F4_SCAN BIT(8)
@ -72,8 +74,11 @@
#define STM32F4_ADON BIT(0)
/* STM32F4_ADC_CSR - bit fields */
#define STM32F4_OVR3 BIT(21)
#define STM32F4_EOC3 BIT(17)
#define STM32F4_OVR2 BIT(13)
#define STM32F4_EOC2 BIT(9)
#define STM32F4_OVR1 BIT(5)
#define STM32F4_EOC1 BIT(1)
/* STM32F4_ADC_CCR - bit fields */
@ -103,10 +108,12 @@
/* STM32H7_ADC_ISR - bit fields */
#define STM32MP1_VREGREADY BIT(12)
#define STM32H7_OVR BIT(4)
#define STM32H7_EOC BIT(2)
#define STM32H7_ADRDY BIT(0)
/* STM32H7_ADC_IER - bit fields */
#define STM32H7_OVRIE STM32H7_OVR
#define STM32H7_EOCIE STM32H7_EOC
/* STM32H7_ADC_CR - bit fields */
@ -155,7 +162,9 @@ enum stm32h7_adc_dmngt {
#define STM32H7_LINCALFACT_MASK GENMASK(29, 0)
/* STM32H7_ADC_CSR - bit fields */
#define STM32H7_OVR_SLV BIT(20)
#define STM32H7_EOC_SLV BIT(18)
#define STM32H7_OVR_MST BIT(4)
#define STM32H7_EOC_MST BIT(2)
/* STM32H7_ADC_CCR - bit fields */

View file

@ -117,7 +117,9 @@ struct stm32_adc_regs {
* struct stm32_adc_regspec - stm32 registers definition
* @dr: data register offset
* @ier_eoc: interrupt enable register & eocie bitfield
* @ier_ovr: interrupt enable register & overrun bitfield
* @isr_eoc: interrupt status register & eoc bitfield
* @isr_ovr: interrupt status register & overrun bitfield
* @sqr: reference to sequence registers array
* @exten: trigger control register & bitfield
* @extsel: trigger selection register & bitfield
@ -128,7 +130,9 @@ struct stm32_adc_regs {
struct stm32_adc_regspec {
const u32 dr;
const struct stm32_adc_regs ier_eoc;
const struct stm32_adc_regs ier_ovr;
const struct stm32_adc_regs isr_eoc;
const struct stm32_adc_regs isr_ovr;
const struct stm32_adc_regs *sqr;
const struct stm32_adc_regs exten;
const struct stm32_adc_regs extsel;
@ -337,7 +341,9 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
static const struct stm32_adc_regspec stm32f4_adc_regspec = {
.dr = STM32F4_ADC_DR,
.ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE },
.ier_ovr = { STM32F4_ADC_CR1, STM32F4_OVRIE },
.isr_eoc = { STM32F4_ADC_SR, STM32F4_EOC },
.isr_ovr = { STM32F4_ADC_SR, STM32F4_OVR },
.sqr = stm32f4_sq,
.exten = { STM32F4_ADC_CR2, STM32F4_EXTEN_MASK, STM32F4_EXTEN_SHIFT },
.extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK,
@ -429,7 +435,9 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = {
static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.dr = STM32H7_ADC_DR,
.ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
.ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
.isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
.isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
.sqr = stm32h7_sq,
.exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
.extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
@ -506,6 +514,18 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc)
adc->cfg->regs->ier_eoc.mask);
}
static void stm32_adc_ovr_irq_enable(struct stm32_adc *adc)
{
stm32_adc_set_bits(adc, adc->cfg->regs->ier_ovr.reg,
adc->cfg->regs->ier_ovr.mask);
}
static void stm32_adc_ovr_irq_disable(struct stm32_adc *adc)
{
stm32_adc_clr_bits(adc, adc->cfg->regs->ier_ovr.reg,
adc->cfg->regs->ier_ovr.mask);
}
static void stm32_adc_set_res(struct stm32_adc *adc)
{
const struct stm32_adc_regs *res = &adc->cfg->regs->res;
@ -1205,6 +1225,19 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
}
}
static irqreturn_t stm32_adc_threaded_isr(int irq, void *data)
{
struct stm32_adc *adc = data;
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
const struct stm32_adc_regspec *regs = adc->cfg->regs;
u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg);
if (status & regs->isr_ovr.mask)
dev_err(&indio_dev->dev, "Overrun, stopping: restart needed\n");
return IRQ_HANDLED;
}
static irqreturn_t stm32_adc_isr(int irq, void *data)
{
struct stm32_adc *adc = data;
@ -1212,6 +1245,19 @@ static irqreturn_t stm32_adc_isr(int irq, void *data)
const struct stm32_adc_regspec *regs = adc->cfg->regs;
u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg);
if (status & regs->isr_ovr.mask) {
/*
* Overrun occurred on regular conversions: data for wrong
* channel may be read. Unconditionally disable interrupts
* to stop processing data and print error message.
* Restarting the capture can be done by disabling, then
* re-enabling it (e.g. write 0, then 1 to buffer/enable).
*/
stm32_adc_ovr_irq_disable(adc);
stm32_adc_conv_irq_disable(adc);
return IRQ_WAKE_THREAD;
}
if (status & regs->isr_eoc.mask) {
/* Reading DR also clears EOC status flag */
adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr);
@ -1441,6 +1487,8 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
/* Reset adc buffer index */
adc->bufi = 0;
stm32_adc_ovr_irq_enable(adc);
if (!adc->dma_chan)
stm32_adc_conv_irq_enable(adc);
@ -1481,6 +1529,8 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
if (!adc->dma_chan)
stm32_adc_conv_irq_disable(adc);
stm32_adc_ovr_irq_disable(adc);
if (adc->dma_chan)
dmaengine_terminate_sync(adc->dma_chan);
@ -1818,8 +1868,9 @@ static int stm32_adc_probe(struct platform_device *pdev)
if (adc->irq < 0)
return adc->irq;
ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr,
0, pdev->name, adc);
ret = devm_request_threaded_irq(&pdev->dev, adc->irq, stm32_adc_isr,
stm32_adc_threaded_isr,
0, pdev->name, adc);
if (ret) {
dev_err(&pdev->dev, "failed to request IRQ\n");
return ret;

View file

@ -12,17 +12,15 @@
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/platform_data/ads1015.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/iio/sysfs.h>
@ -33,6 +31,8 @@
#define ADS1015_DRV_NAME "ads1015"
#define ADS1015_CHANNELS 8
#define ADS1015_CONV_REG 0x00
#define ADS1015_CFG_REG 0x01
#define ADS1015_LO_THRESH_REG 0x02
@ -77,6 +77,7 @@
#define ADS1015_DEFAULT_CHAN 0
enum chip_ids {
ADSXXXX = 0,
ADS1015,
ADS1115,
};
@ -219,6 +220,12 @@ static const struct iio_event_spec ads1015_events[] = {
.datasheet_name = "AIN"#_chan"-AIN"#_chan2, \
}
struct ads1015_channel_data {
bool enabled;
unsigned int pga;
unsigned int data_rate;
};
struct ads1015_thresh_data {
unsigned int comp_queue;
int high_thresh;
@ -837,65 +844,58 @@ static const struct iio_info ads1115_info = {
.attrs = &ads1115_attribute_group,
};
#ifdef CONFIG_OF
static int ads1015_get_channels_config_of(struct i2c_client *client)
static int ads1015_client_get_channels_config(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct device_node *node;
struct device *dev = &client->dev;
struct fwnode_handle *node;
int i = -1;
if (!client->dev.of_node ||
!of_get_next_child(client->dev.of_node, NULL))
return -EINVAL;
for_each_child_of_node(client->dev.of_node, node) {
device_for_each_child_node(dev, node) {
u32 pval;
unsigned int channel;
unsigned int pga = ADS1015_DEFAULT_PGA;
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
if (of_property_read_u32(node, "reg", &pval)) {
dev_err(&client->dev, "invalid reg on %pOF\n",
node);
if (fwnode_property_read_u32(node, "reg", &pval)) {
dev_err(dev, "invalid reg on %pfw\n", node);
continue;
}
channel = pval;
if (channel >= ADS1015_CHANNELS) {
dev_err(&client->dev,
"invalid channel index %d on %pOF\n",
dev_err(dev, "invalid channel index %d on %pfw\n",
channel, node);
continue;
}
if (!of_property_read_u32(node, "ti,gain", &pval)) {
if (!fwnode_property_read_u32(node, "ti,gain", &pval)) {
pga = pval;
if (pga > 6) {
dev_err(&client->dev, "invalid gain on %pOF\n",
node);
of_node_put(node);
dev_err(dev, "invalid gain on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
}
}
if (!of_property_read_u32(node, "ti,datarate", &pval)) {
if (!fwnode_property_read_u32(node, "ti,datarate", &pval)) {
data_rate = pval;
if (data_rate > 7) {
dev_err(&client->dev,
"invalid data_rate on %pOF\n",
node);
of_node_put(node);
dev_err(dev, "invalid data_rate on %pfw\n", node);
fwnode_handle_put(node);
return -EINVAL;
}
}
data->channel_data[channel].pga = pga;
data->channel_data[channel].data_rate = data_rate;
i++;
}
return 0;
return i < 0 ? -EINVAL : 0;
}
#endif
static void ads1015_get_channels_config(struct i2c_client *client)
{
@ -903,19 +903,10 @@ static void ads1015_get_channels_config(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ads1015_data *data = iio_priv(indio_dev);
struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
/* prefer platform data */
if (pdata) {
memcpy(data->channel_data, pdata->channel_data,
sizeof(data->channel_data));
if (!ads1015_client_get_channels_config(client))
return;
}
#ifdef CONFIG_OF
if (!ads1015_get_channels_config_of(client))
return;
#endif
/* fallback on default configuration */
for (k = 0; k < ADS1015_CHANNELS; ++k) {
data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
@ -953,9 +944,8 @@ static int ads1015_probe(struct i2c_client *client,
indio_dev->name = ADS1015_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
if (client->dev.of_node)
chip = (enum chip_ids)of_device_get_match_data(&client->dev);
else
chip = (enum chip_ids)device_get_match_data(&client->dev);
if (chip == ADSXXXX)
chip = id->driver_data;
switch (chip) {
case ADS1015:
@ -970,6 +960,9 @@ static int ads1015_probe(struct i2c_client *client,
indio_dev->info = &ads1115_info;
data->data_rate = (unsigned int *) &ads1115_data_rate;
break;
default:
dev_err(&client->dev, "Unknown chip %d\n", chip);
return -EINVAL;
}
data->event_channel = ADS1015_CHANNELS;

View file

@ -602,7 +602,7 @@ static int ti_ads7950_probe(struct spi_device *spi)
st->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(st->reg)) {
dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
dev_err(&spi->dev, "Failed to get regulator \"vref\"\n");
ret = PTR_ERR(st->reg);
goto error_destroy_mutex;
}

View file

@ -476,7 +476,7 @@ static struct iio_dma_buffer_block *iio_dma_buffer_dequeue(
* @n: Number of bytes to read
* @user_buffer: Userspace buffer to copy the data to
*
* Should be used as the read_first_n callback for iio_buffer_access_ops
* Should be used as the read callback for iio_buffer_access_ops
* struct for DMA buffers.
*/
int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n,

View file

@ -10,8 +10,10 @@
#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/buffer_impl.h>
#include <linux/iio/buffer-dma.h>
@ -107,7 +109,7 @@ static void iio_dmaengine_buffer_release(struct iio_buffer *buf)
}
static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
.read_first_n = iio_dma_buffer_read,
.read = iio_dma_buffer_read,
.set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum,
.set_length = iio_dma_buffer_set_length,
.request_update = iio_dma_buffer_request_update,
@ -125,6 +127,24 @@ static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = {
.abort = iio_dmaengine_buffer_abort,
};
static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct dmaengine_buffer *dmaengine_buffer =
iio_buffer_to_dmaengine_buffer(indio_dev->buffer);
return sprintf(buf, "%u\n", dmaengine_buffer->align);
}
static IIO_DEVICE_ATTR(length_align_bytes, 0444,
iio_dmaengine_buffer_get_length_align, NULL, 0);
static const struct attribute *iio_dmaengine_buffer_attrs[] = {
&iio_dev_attr_length_align_bytes.dev_attr.attr,
NULL,
};
/**
* iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
* @dev: Parent device for the buffer
@ -150,7 +170,7 @@ struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
if (!dmaengine_buffer)
return ERR_PTR(-ENOMEM);
chan = dma_request_slave_channel_reason(dev, channel);
chan = dma_request_chan(dev, channel);
if (IS_ERR(chan)) {
ret = PTR_ERR(chan);
goto err_free;
@ -178,6 +198,8 @@ struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev,
&iio_dmaengine_default_ops);
iio_buffer_set_attrs(&dmaengine_buffer->queue.buffer,
iio_dmaengine_buffer_attrs);
dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops;
@ -206,3 +228,7 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
iio_buffer_put(buffer);
}
EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("DMA buffer for the IIO framework");
MODULE_LICENSE("GPL");

View file

@ -98,8 +98,7 @@ static int iio_store_to_kfifo(struct iio_buffer *r,
return 0;
}
static int iio_read_first_n_kfifo(struct iio_buffer *r,
size_t n, char __user *buf)
static int iio_read_kfifo(struct iio_buffer *r, size_t n, char __user *buf)
{
int ret, copied;
struct iio_kfifo *kf = iio_to_kfifo(r);
@ -141,7 +140,7 @@ static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
static const struct iio_buffer_access_funcs kfifo_access_funcs = {
.store_to = &iio_store_to_kfifo,
.read_first_n = &iio_read_first_n_kfifo,
.read = &iio_read_kfifo,
.data_available = iio_kfifo_buf_data_available,
.request_update = &iio_request_update_kfifo,
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,

View file

@ -4,7 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-sensor.o
obj-$(CONFIG_BME680) += bme680_core.o
obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o

View file

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* atlas-ph-sensor.c - Support for Atlas Scientific OEM pH-SM sensor
* atlas-sensor.c - Support for Atlas Scientific OEM SM sensors
*
* Copyright (C) 2015-2018 Matt Ranostay
* Copyright (C) 2015-2019 Konsulko Group
* Author: Matt Ranostay <matt.ranostay@konsulko.com>
*/
@ -14,7 +14,6 @@
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/irq_work.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
@ -25,8 +24,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/pm_runtime.h>
#define ATLAS_REGMAP_NAME "atlas_ph_regmap"
#define ATLAS_DRV_NAME "atlas_ph"
#define ATLAS_REGMAP_NAME "atlas_regmap"
#define ATLAS_DRV_NAME "atlas"
#define ATLAS_REG_DEV_TYPE 0x00
#define ATLAS_REG_DEV_VERSION 0x01
@ -681,5 +680,5 @@ static struct i2c_driver atlas_driver = {
module_i2c_driver(atlas_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("Atlas Scientific pH-SM sensor");
MODULE_DESCRIPTION("Atlas Scientific SM sensors");
MODULE_LICENSE("GPL");

View file

@ -7,7 +7,7 @@
#define __SSP_SENSORHUB_H__
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/common/ssp_sensors.h>
#include <linux/iio/iio.h>
#include <linux/spi/spi.h>
@ -168,9 +168,9 @@ struct ssp_sensorhub_info {
* @fw_dl_state: firmware download state
* @comm_lock: lock protecting the handshake
* @pending_lock: lock protecting pending list and completion
* @mcu_reset_gpio: mcu reset line
* @ap_mcu_gpio: ap to mcu gpio line
* @mcu_ap_gpio: mcu to ap gpio line
* @mcu_reset_gpiod: mcu reset line
* @ap_mcu_gpiod: ap to mcu gpio line
* @mcu_ap_gpiod: mcu to ap gpio line
* @pending_list: pending list for messages queued to be sent/read
* @sensor_devs: registered IIO devices table
* @enable_refcount: enable reference count for wdt (watchdog timer)
@ -212,9 +212,9 @@ struct ssp_data {
struct mutex comm_lock;
struct mutex pending_lock;
int mcu_reset_gpio;
int ap_mcu_gpio;
int mcu_ap_gpio;
struct gpio_desc *mcu_reset_gpiod;
struct gpio_desc *ap_mcu_gpiod;
struct gpio_desc *mcu_ap_gpiod;
struct list_head pending_list;

View file

@ -9,7 +9,6 @@
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include "ssp.h"
@ -61,9 +60,9 @@ static const struct mfd_cell sensorhub_sensor_devs[] = {
static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)
{
gpio_set_value(data->mcu_reset_gpio, 0);
gpiod_set_value(data->mcu_reset_gpiod, 0);
usleep_range(1000, 1200);
gpio_set_value(data->mcu_reset_gpio, 1);
gpiod_set_value(data->mcu_reset_gpiod, 1);
msleep(50);
}
@ -441,7 +440,6 @@ MODULE_DEVICE_TABLE(of, ssp_of_match);
static struct ssp_data *ssp_parse_dt(struct device *dev)
{
int ret;
struct ssp_data *data;
struct device_node *node = dev->of_node;
const struct of_device_id *match;
@ -450,26 +448,17 @@ static struct ssp_data *ssp_parse_dt(struct device *dev)
if (!data)
return NULL;
data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
if (data->mcu_ap_gpio < 0)
data->mcu_ap_gpiod = devm_gpiod_get(dev, "mcu-ap", GPIOD_IN);
if (IS_ERR(data->mcu_ap_gpiod))
return NULL;
data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
if (data->ap_mcu_gpio < 0)
data->ap_mcu_gpiod = devm_gpiod_get(dev, "ap-mcu", GPIOD_OUT_HIGH);
if (IS_ERR(data->ap_mcu_gpiod))
return NULL;
data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
if (data->mcu_reset_gpio < 0)
return NULL;
ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
"ap-mcu-gpios");
if (ret)
return NULL;
ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
if (ret)
data->mcu_reset_gpiod = devm_gpiod_get(dev, "mcu-reset",
GPIOD_OUT_HIGH);
if (IS_ERR(data->mcu_reset_gpiod))
return NULL;
match = of_match_node(ssp_of_match, node);

View file

@ -155,9 +155,9 @@ static int ssp_check_lines(struct ssp_data *data, bool state)
{
int delay_cnt = 0;
gpio_set_value_cansleep(data->ap_mcu_gpio, state);
gpiod_set_value_cansleep(data->ap_mcu_gpiod, state);
while (gpio_get_value_cansleep(data->mcu_ap_gpio) != state) {
while (gpiod_get_value_cansleep(data->mcu_ap_gpiod) != state) {
usleep_range(3000, 3500);
if (data->shut_down || delay_cnt++ > 500) {
@ -165,7 +165,7 @@ static int ssp_check_lines(struct ssp_data *data, bool state)
__func__, state);
if (!state)
gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
gpiod_set_value_cansleep(data->ap_mcu_gpiod, 1);
return -ETIMEDOUT;
}
@ -197,7 +197,7 @@ static int ssp_do_transfer(struct ssp_data *data, struct ssp_msg *msg,
status = spi_write(data->spi, msg->buffer, SSP_HEADER_SIZE);
if (status < 0) {
gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
gpiod_set_value_cansleep(data->ap_mcu_gpiod, 1);
dev_err(SSP_DEV, "%s spi_write fail\n", __func__);
goto _error_locked;
}

View file

@ -19,6 +19,9 @@
/**
* st_sensors_new_samples_available() - check if more samples came in
* @indio_dev: IIO device reference.
* @sdata: Sensor data.
*
* returns:
* 0 - no new samples available
* 1 - new samples available

View file

@ -15,7 +15,6 @@
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/gpio.h>
#include <linux/property.h>
#include <dt-bindings/iio/adi,ad5592r.h>

View file

@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -202,7 +201,6 @@ static int ad7303_probe(struct spi_device *spi)
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct ad7303_state *st;
bool ext_ref;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
@ -224,24 +222,15 @@ static int ad7303_probe(struct spi_device *spi)
if (ret)
return ret;
if (spi->dev.of_node) {
ext_ref = of_property_read_bool(spi->dev.of_node,
"REF-supply");
} else {
struct ad7303_platform_data *pdata = spi->dev.platform_data;
if (pdata && pdata->use_external_ref)
ext_ref = true;
else
ext_ref = false;
st->vref_reg = devm_regulator_get_optional(&spi->dev, "REF");
if (IS_ERR(st->vref_reg)) {
ret = PTR_ERR(st->vref_reg);
if (ret != -ENODEV)
goto err_disable_vdd_reg;
st->vref_reg = NULL;
}
if (ext_ref) {
st->vref_reg = devm_regulator_get(&spi->dev, "REF");
if (IS_ERR(st->vref_reg)) {
ret = PTR_ERR(st->vref_reg);
goto err_disable_vdd_reg;
}
if (st->vref_reg) {
ret = regulator_enable(st->vref_reg);
if (ret)
goto err_disable_vdd_reg;

View file

@ -14,11 +14,10 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/gcd.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <asm/div64.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -34,6 +33,7 @@ enum {
struct adf4350_state {
struct spi_device *spi;
struct regulator *reg;
struct gpio_desc *lock_detect_gpiod;
struct adf4350_platform_data *pdata;
struct clk *clk;
unsigned long clkin;
@ -61,7 +61,6 @@ static struct adf4350_platform_data default_pdata = {
.r3_user_settings = ADF4350_REG3_12BIT_CLKDIV_MODE(0),
.r4_user_settings = ADF4350_REG4_OUTPUT_PWR(3) |
ADF4350_REG4_MUTE_TILL_LOCK_EN,
.gpio_lock_detect = -1,
};
static int adf4350_sync_config(struct adf4350_state *st)
@ -317,8 +316,8 @@ static ssize_t adf4350_read(struct iio_dev *indio_dev,
(u64)st->fpfd;
do_div(val, st->r1_mod * (1 << st->r4_rf_div_sel));
/* PLL unlocked? return error */
if (gpio_is_valid(st->pdata->gpio_lock_detect))
if (!gpio_get_value(st->pdata->gpio_lock_detect)) {
if (st->lock_detect_gpiod)
if (!gpiod_get_value(st->lock_detect_gpiod)) {
dev_dbg(&st->spi->dev, "PLL un-locked\n");
ret = -EBUSY;
}
@ -381,7 +380,6 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
struct device_node *np = dev->of_node;
struct adf4350_platform_data *pdata;
unsigned int tmp;
int ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@ -401,12 +399,6 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
of_property_read_u32(np, "adi,reference-div-factor", &tmp);
pdata->ref_div_factor = tmp;
ret = of_get_gpio(np, 0);
if (ret < 0)
pdata->gpio_lock_detect = -1;
else
pdata->gpio_lock_detect = ret;
pdata->ref_doubler_en = of_property_read_bool(np,
"adi,reference-doubler-enable");
pdata->ref_div2_en = of_property_read_bool(np,
@ -561,16 +553,10 @@ static int adf4350_probe(struct spi_device *spi)
memset(st->regs_hw, 0xFF, sizeof(st->regs_hw));
if (gpio_is_valid(pdata->gpio_lock_detect)) {
ret = devm_gpio_request(&spi->dev, pdata->gpio_lock_detect,
indio_dev->name);
if (ret) {
dev_err(&spi->dev, "fail to request lock detect GPIO-%d",
pdata->gpio_lock_detect);
goto error_disable_reg;
}
gpio_direction_input(pdata->gpio_lock_detect);
}
st->lock_detect_gpiod = devm_gpiod_get_optional(&spi->dev, NULL,
GPIOD_IN);
if (IS_ERR(st->lock_detect_gpiod))
return PTR_ERR(st->lock_detect_gpiod);
if (pdata->power_up_frequency) {
ret = adf4350_set_freq(st, pdata->power_up_frequency);

View file

@ -75,26 +75,26 @@ config BMG160_SPI
select REGMAP_SPI
config FXAS21002C
tristate "NXP FXAS21002C Gyro Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select FXAS21002C_I2C if (I2C)
select FXAS21002C_SPI if (SPI)
depends on (I2C || SPI_MASTER)
help
Say yes here to build support for NXP FXAS21002C Tri-axis Gyro
Sensor driver connected via I2C or SPI.
tristate "NXP FXAS21002C Gyro Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select FXAS21002C_I2C if (I2C)
select FXAS21002C_SPI if (SPI)
depends on (I2C || SPI_MASTER)
help
Say yes here to build support for NXP FXAS21002C Tri-axis Gyro
Sensor driver connected via I2C or SPI.
This driver can also be built as a module. If so, the module
will be called fxas21002c_i2c or fxas21002c_spi.
This driver can also be built as a module. If so, the module
will be called fxas21002c_i2c or fxas21002c_spi.
config FXAS21002C_I2C
tristate
select REGMAP_I2C
tristate
select REGMAP_I2C
config FXAS21002C_SPI
tristate
select REGMAP_SPI
tristate
select REGMAP_SPI
config HID_SENSOR_GYRO_3D
depends on HID_SENSOR_HUB

View file

@ -185,12 +185,12 @@ static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq)
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t);
}
static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
static int __adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq)
{
uint16_t t;
int ret;
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t);
if (ret)
return ret;
@ -224,10 +224,13 @@ static ssize_t adis16136_read_frequency(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
int ret;
ret = adis16136_get_freq(adis16136, &freq);
mutex_lock(slock);
ret = __adis16136_get_freq(adis16136, &freq);
mutex_unlock(slock);
if (ret)
return ret;
@ -252,42 +255,50 @@ static const unsigned adis16136_3db_divisors[] = {
static int adis16136_set_filter(struct iio_dev *indio_dev, int val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
int i, ret;
ret = adis16136_get_freq(adis16136, &freq);
mutex_lock(slock);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
return ret;
goto out_unlock;
for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) {
if (freq / adis16136_3db_divisors[i] >= val)
break;
}
return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
ret = __adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i);
out_unlock:
mutex_unlock(slock);
return ret;
}
static int adis16136_get_filter(struct iio_dev *indio_dev, int *val)
{
struct adis16136 *adis16136 = iio_priv(indio_dev);
struct mutex *slock = &adis16136->adis.state_lock;
unsigned int freq;
uint16_t val16;
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16);
ret = __adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT,
&val16);
if (ret)
goto err_unlock;
ret = adis16136_get_freq(adis16136, &freq);
ret = __adis16136_get_freq(adis16136, &freq);
if (ret)
goto err_unlock;
*val = freq / adis16136_3db_divisors[val16 & 0x07];
err_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret ? ret : IIO_VAL_INT;
}

View file

@ -293,7 +293,7 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
addr = adis16260_addresses[chan->scan_index][1];
return adis_write_reg_16(adis, addr, val);
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&indio_dev->mlock);
mutex_lock(&adis->state_lock);
if (spi_get_device_id(adis->spi)->driver_data)
t = 256 / val;
else
@ -308,9 +308,9 @@ static int adis16260_write_raw(struct iio_dev *indio_dev,
adis->spi->max_speed_hz = ADIS16260_SPI_SLOW;
else
adis->spi->max_speed_hz = ADIS16260_SPI_FAST;
ret = adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
ret = __adis_write_reg_8(adis, ADIS16260_SMPL_PRD, t);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&adis->state_lock);
return ret;
}
return -EINVAL;

View file

@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>

View file

@ -28,7 +28,7 @@
* struct st_sensors_platform_data - gyro platform data
* @drdy_int_pin: DRDY on gyros is available only on INT2 pin.
*/
static const struct st_sensors_platform_data gyro_pdata = {
static __maybe_unused const struct st_sensors_platform_data gyro_pdata = {
.drdy_int_pin = 2,
};

View file

@ -24,13 +24,6 @@
#define HTS221_REG_CNTRL1_ADDR 0x20
#define HTS221_REG_CNTRL2_ADDR 0x21
#define HTS221_REG_AVG_ADDR 0x10
#define HTS221_REG_H_OUT_L 0x28
#define HTS221_REG_T_OUT_L 0x2a
#define HTS221_HUMIDITY_AVG_MASK 0x07
#define HTS221_TEMP_AVG_MASK 0x38
#define HTS221_ODR_MASK 0x03
#define HTS221_BDU_MASK BIT(2)
#define HTS221_ENABLE_MASK BIT(7)
@ -66,8 +59,8 @@ static const struct hts221_odr hts221_odr_table[] = {
static const struct hts221_avg hts221_avg_list[] = {
{
.addr = HTS221_REG_AVG_ADDR,
.mask = HTS221_HUMIDITY_AVG_MASK,
.addr = 0x10,
.mask = 0x07,
.avg_avl = {
4, /* 0.4 %RH */
8, /* 0.3 %RH */
@ -80,8 +73,8 @@ static const struct hts221_avg hts221_avg_list[] = {
},
},
{
.addr = HTS221_REG_AVG_ADDR,
.mask = HTS221_TEMP_AVG_MASK,
.addr = 0x10,
.mask = 0x38,
.avg_avl = {
2, /* 0.08 degC */
4, /* 0.05 degC */
@ -98,7 +91,7 @@ static const struct hts221_avg hts221_avg_list[] = {
static const struct iio_chan_spec hts221_channels[] = {
{
.type = IIO_HUMIDITYRELATIVE,
.address = HTS221_REG_H_OUT_L,
.address = 0x28,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
@ -114,7 +107,7 @@ static const struct iio_chan_spec hts221_channels[] = {
},
{
.type = IIO_TEMP,
.address = HTS221_REG_T_OUT_L,
.address = 0x2a,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |

View file

@ -42,14 +42,14 @@ struct poll_table_struct;
__poll_t iio_buffer_poll(struct file *filp,
struct poll_table_struct *wait);
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps);
ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps);
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
#define iio_buffer_poll_addr (&iio_buffer_poll)
#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
#define iio_buffer_read_outer_addr (&iio_buffer_read_outer)
void iio_disable_all_buffers(struct iio_dev *indio_dev);
void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
@ -57,7 +57,7 @@ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
#else
#define iio_buffer_poll_addr NULL
#define iio_buffer_read_first_n_outer_addr NULL
#define iio_buffer_read_outer_addr NULL
static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{

View file

@ -26,7 +26,14 @@
#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
#define ADIS_GLOB_CMD_SW_RESET BIT(7)
int adis_write_reg(struct adis *adis, unsigned int reg,
/**
* __adis_write_reg() - write N bytes to register (unlocked version)
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @value: The value to write to device (up to 4 bytes)
* @size: The size of the @value (in bytes)
*/
int __adis_write_reg(struct adis *adis, unsigned int reg,
unsigned int value, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
@ -70,8 +77,6 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
},
};
mutex_lock(&adis->txrx_lock);
spi_message_init(&msg);
if (adis->current_page != page) {
@ -96,8 +101,7 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
adis->tx[3] = value & 0xff;
break;
default:
ret = -EINVAL;
goto out_unlock;
return -EINVAL;
}
xfers[size].cs_change = 0;
@ -113,20 +117,18 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
adis->current_page = page;
}
out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_write_reg);
EXPORT_SYMBOL_GPL(__adis_write_reg);
/**
* adis_read_reg() - read 2 bytes from a 16-bit register
* __adis_read_reg() - read N bytes from register (unlocked version)
* @adis: The adis device
* @reg: The address of the lower of the two registers
* @val: The value read back from the device
* @size: The size of the @val buffer
*/
int adis_read_reg(struct adis *adis, unsigned int reg,
int __adis_read_reg(struct adis *adis, unsigned int reg,
unsigned int *val, unsigned int size)
{
unsigned int page = reg / ADIS_PAGE_SIZE;
@ -166,7 +168,6 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
},
};
mutex_lock(&adis->txrx_lock);
spi_message_init(&msg);
if (adis->current_page != page) {
@ -188,15 +189,14 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
spi_message_add_tail(&xfers[3], &msg);
break;
default:
ret = -EINVAL;
goto out_unlock;
return -EINVAL;
}
ret = spi_sync(adis->spi, &msg);
if (ret) {
dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
reg, ret);
goto out_unlock;
return ret;
} else {
adis->current_page = page;
}
@ -210,12 +210,9 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
break;
}
out_unlock:
mutex_unlock(&adis->txrx_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_read_reg);
EXPORT_SYMBOL_GPL(__adis_read_reg);
#ifdef CONFIG_DEBUG_FS
@ -253,12 +250,16 @@ int adis_enable_irq(struct adis *adis, bool enable)
int ret = 0;
uint16_t msc;
if (adis->data->enable_irq)
return adis->data->enable_irq(adis, enable);
mutex_lock(&adis->state_lock);
ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (adis->data->enable_irq) {
ret = adis->data->enable_irq(adis, enable);
goto out_unlock;
}
ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
if (ret)
goto error_ret;
goto out_unlock;
msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
@ -267,26 +268,27 @@ int adis_enable_irq(struct adis *adis, bool enable)
else
msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
error_ret:
out_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL(adis_enable_irq);
/**
* adis_check_status() - Check the device for error conditions
* __adis_check_status() - Check the device for error conditions (unlocked)
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int adis_check_status(struct adis *adis)
int __adis_check_status(struct adis *adis)
{
uint16_t status;
int ret;
int i;
ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
ret = __adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
if (ret)
return ret;
@ -304,32 +306,32 @@ int adis_check_status(struct adis *adis)
return -EIO;
}
EXPORT_SYMBOL_GPL(adis_check_status);
EXPORT_SYMBOL_GPL(__adis_check_status);
/**
* adis_reset() - Reset the device
* __adis_reset() - Reset the device (unlocked version)
* @adis: The adis device
*
* Returns 0 on success, a negative error code otherwise
*/
int adis_reset(struct adis *adis)
int __adis_reset(struct adis *adis)
{
int ret;
ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg,
ADIS_GLOB_CMD_SW_RESET);
if (ret)
dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
return ret;
}
EXPORT_SYMBOL_GPL(adis_reset);
EXPORT_SYMBOL_GPL(__adis_reset);
static int adis_self_test(struct adis *adis)
{
int ret;
ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
adis->data->self_test_mask);
if (ret) {
dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
@ -339,10 +341,10 @@ static int adis_self_test(struct adis *adis)
msleep(adis->data->startup_delay);
ret = adis_check_status(adis);
ret = __adis_check_status(adis);
if (adis->data->self_test_no_autoclear)
adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
__adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
return ret;
}
@ -360,19 +362,23 @@ int adis_initial_startup(struct adis *adis)
{
int ret;
mutex_lock(&adis->state_lock);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
adis_reset(adis);
__adis_reset(adis);
msleep(adis->data->startup_delay);
ret = adis_self_test(adis);
if (ret) {
dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
return ret;
goto out_unlock;
}
}
return 0;
out_unlock:
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_initial_startup);
@ -398,15 +404,15 @@ int adis_single_conversion(struct iio_dev *indio_dev,
unsigned int uval;
int ret;
mutex_lock(&indio_dev->mlock);
mutex_lock(&adis->state_lock);
ret = adis_read_reg(adis, chan->address, &uval,
ret = __adis_read_reg(adis, chan->address, &uval,
chan->scan_type.storagebits / 8);
if (ret)
goto err_unlock;
if (uval & error_mask) {
ret = adis_check_status(adis);
ret = __adis_check_status(adis);
if (ret)
goto err_unlock;
}
@ -418,7 +424,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
ret = IIO_VAL_INT;
err_unlock:
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&adis->state_lock);
return ret;
}
EXPORT_SYMBOL_GPL(adis_single_conversion);
@ -438,7 +444,7 @@ EXPORT_SYMBOL_GPL(adis_single_conversion);
int adis_init(struct adis *adis, struct iio_dev *indio_dev,
struct spi_device *spi, const struct adis_data *data)
{
mutex_init(&adis->txrx_lock);
mutex_init(&adis->state_lock);
adis->spi = spi;
adis->data = data;
iio_device_set_drvdata(indio_dev, adis);

View file

@ -162,6 +162,7 @@ struct adis16400_chip_info {
unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
/* set_freq() & get_freq() need to avoid using ADIS lib's state lock */
int (*set_freq)(struct adis16400_state *st, unsigned int freq);
int (*get_freq)(struct adis16400_state *st);
};
@ -326,7 +327,7 @@ static int adis16334_get_freq(struct adis16400_state *st)
int ret;
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret)
return ret;
@ -350,7 +351,7 @@ static int adis16334_set_freq(struct adis16400_state *st, unsigned int freq)
t <<= ADIS16334_RATE_DIV_SHIFT;
t |= ADIS16334_RATE_INT_CLK;
return adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
return __adis_write_reg_16(&st->adis, ADIS16400_SMPL_PRD, t);
}
static int adis16400_get_freq(struct adis16400_state *st)
@ -358,7 +359,7 @@ static int adis16400_get_freq(struct adis16400_state *st)
int sps, ret;
uint16_t t;
ret = adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
ret = __adis_read_reg_16(&st->adis, ADIS16400_SMPL_PRD, &t);
if (ret)
return ret;
@ -390,7 +391,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
else
st->adis.spi->max_speed_hz = ADIS16400_SPI_FAST;
return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
return __adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
}
static const unsigned int adis16400_3db_divisors[] = {
@ -404,7 +405,7 @@ static const unsigned int adis16400_3db_divisors[] = {
[7] = 200, /* Not a valid setting */
};
static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
static int __adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
{
struct adis16400_state *st = iio_priv(indio_dev);
uint16_t val16;
@ -415,11 +416,11 @@ static int adis16400_set_filter(struct iio_dev *indio_dev, int sps, int val)
break;
}
ret = adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
ret = __adis_read_reg_16(&st->adis, ADIS16400_SENS_AVG, &val16);
if (ret)
return ret;
ret = adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
ret = __adis_write_reg_16(&st->adis, ADIS16400_SENS_AVG,
(val16 & ~0x07) | i);
return ret;
}
@ -507,32 +508,31 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
struct mutex *slock = &st->adis.state_lock;
int ret, sps;
switch (info) {
case IIO_CHAN_INFO_CALIBBIAS:
mutex_lock(&indio_dev->mlock);
ret = adis_write_reg_16(&st->adis,
adis16400_addresses[chan->scan_index], val);
mutex_unlock(&indio_dev->mlock);
return ret;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
/*
* Need to cache values so we can update if the frequency
* changes.
*/
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
st->filt_int = val;
/* Work out update to current value */
sps = st->variant->get_freq(st);
if (sps < 0) {
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return sps;
}
ret = adis16400_set_filter(indio_dev, sps,
ret = __adis16400_set_filter(indio_dev, sps,
val * 1000 + val2 / 1000);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
sps = val * 1000 + val2 / 1000;
@ -540,9 +540,9 @@ static int adis16400_write_raw(struct iio_dev *indio_dev,
if (sps <= 0)
return -EINVAL;
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
ret = st->variant->set_freq(st, sps);
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret;
default:
return -EINVAL;
@ -553,6 +553,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct adis16400_state *st = iio_priv(indio_dev);
struct mutex *slock = &st->adis.state_lock;
int16_t val16;
int ret;
@ -596,10 +597,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_CALIBBIAS:
mutex_lock(&indio_dev->mlock);
ret = adis_read_reg_16(&st->adis,
adis16400_addresses[chan->scan_index], &val16);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
val16 = sign_extend32(val16, 11);
@ -610,27 +609,27 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
*val = st->variant->temp_offset;
return IIO_VAL_INT;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
mutex_lock(&indio_dev->mlock);
mutex_lock(slock);
/* Need both the number of taps and the sampling frequency */
ret = adis_read_reg_16(&st->adis,
ret = __adis_read_reg_16(&st->adis,
ADIS16400_SENS_AVG,
&val16);
if (ret) {
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
return ret;
}
ret = st->variant->get_freq(st);
if (ret >= 0) {
ret /= adis16400_3db_divisors[val16 & 0x07];
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
}
mutex_unlock(&indio_dev->mlock);
mutex_unlock(slock);
if (ret)
return ret;
ret /= adis16400_3db_divisors[val16 & 0x07];
*val = ret / 1000;
*val2 = (ret % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(slock);
ret = st->variant->get_freq(st);
mutex_unlock(slock);
if (ret)
return ret;
*val = ret / 1000;

View file

@ -555,6 +555,7 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, unsigned int freq)
{
struct adis16480 *st = iio_priv(indio_dev);
struct mutex *slock = &st->adis.state_lock;
unsigned int enable_mask, offset, reg;
unsigned int diff, best_diff;
unsigned int i, best_freq;
@ -565,9 +566,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
offset = ad16480_filter_data[chan->scan_index][1];
enable_mask = BIT(offset + 2);
ret = adis_read_reg_16(&st->adis, reg, &val);
mutex_lock(slock);
ret = __adis_read_reg_16(&st->adis, reg, &val);
if (ret)
return ret;
goto out_unlock;
if (freq == 0) {
val &= ~enable_mask;
@ -589,7 +592,11 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
val |= enable_mask;
}
return adis_write_reg_16(&st->adis, reg, val);
ret = __adis_write_reg_16(&st->adis, reg, val);
out_unlock:
mutex_unlock(slock);
return ret;
}
static int adis16480_read_raw(struct iio_dev *indio_dev,
@ -947,14 +954,14 @@ static int adis16480_enable_irq(struct adis *adis, bool enable)
uint16_t val;
int ret;
ret = adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
ret = __adis_read_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, &val);
if (ret)
return ret;
val &= ~ADIS16480_DRDY_EN_MSK;
val |= ADIS16480_DRDY_EN(enable);
return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
return __adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL, val);
}
static int adis16480_initial_setup(struct iio_dev *indio_dev)

View file

@ -129,7 +129,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
return -ENOMEM;
if (adis->data->has_paging) {
mutex_lock(&adis->txrx_lock);
mutex_lock(&adis->state_lock);
if (adis->current_page != 0) {
adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
adis->tx[1] = 0;
@ -144,7 +144,7 @@ static irqreturn_t adis_trigger_handler(int irq, void *p)
if (adis->data->has_paging) {
adis->current_page = 0;
mutex_unlock(&adis->txrx_lock);
mutex_unlock(&adis->state_lock);
}
iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer,

View file

@ -10,11 +10,12 @@ config INV_MPU6050_IIO
config INV_MPU6050_I2C
tristate "Invensense MPU6050 devices (I2C)"
depends on I2C_MUX
depends on I2C
select I2C_MUX
select INV_MPU6050_IIO
select REGMAP_I2C
help
This driver supports the Invensense MPU6000/6050/6500/6515,
This driver supports the Invensense MPU6050/6500/6515,
MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
over I2C.
This driver can be built as a module. The module will be called
@ -26,8 +27,8 @@ config INV_MPU6050_SPI
select INV_MPU6050_IIO
select REGMAP_SPI
help
This driver supports the Invensense MPU6000/6050/6500/6515,
MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
This driver supports the Invensense MPU6000/6500/6515,
MPU9250/9255 and ICM20608/20602 motion tracking devices
over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.

View file

@ -915,6 +915,33 @@ static const unsigned long inv_mpu_scan_masks[] = {
.ext_info = inv_ext_info, \
}
static const struct iio_chan_spec inv_mpu9150_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
/*
* Note that temperature should only be via polled reading only,
* not the final scan elements output.
*/
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
| BIT(IIO_CHAN_INFO_OFFSET)
| BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1,
},
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
/* Magnetometer resolution is 13 bits */
INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 13, INV_MPU9X50_SCAN_MAGN_X),
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 13, INV_MPU9X50_SCAN_MAGN_Y),
INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 13, INV_MPU9X50_SCAN_MAGN_Z),
};
static const struct iio_chan_spec inv_mpu9250_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP),
/*
@ -1324,21 +1351,16 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
inv_mpu_bus_setup(indio_dev);
switch (chip_type) {
case INV_MPU9150:
indio_dev->channels = inv_mpu9150_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
break;
case INV_MPU9250:
case INV_MPU9255:
/*
* Use magnetometer inside the chip only if there is no i2c
* auxiliary device in use.
*/
if (!st->magn_disabled) {
indio_dev->channels = inv_mpu9250_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
} else {
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks;
}
indio_dev->channels = inv_mpu9250_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
break;
case INV_ICM20602:
indio_dev->channels = inv_icm20602_channels;
@ -1351,6 +1373,15 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
indio_dev->available_scan_masks = inv_mpu_scan_masks;
break;
}
/*
* Use magnetometer inside the chip only if there is no i2c
* auxiliary device in use. Otherwise Going back to 6-axis only.
*/
if (st->magn_disabled) {
indio_dev->channels = inv_mpu_channels;
indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
indio_dev->available_scan_masks = inv_mpu_scan_masks;
}
indio_dev->info = &mpu_info;
indio_dev->modes = INDIO_BUFFER_TRIGGERED;

View file

@ -77,6 +77,7 @@ static bool inv_mpu_i2c_aux_bus(struct device *dev)
case INV_ICM20602:
/* no i2c auxiliary bus on the chip */
return false;
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
if (st->magn_disabled)
@ -102,6 +103,7 @@ static int inv_mpu_magn_disable(struct iio_dev *indio_dev)
struct device_node *mux_node;
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
mux_node = of_get_child_by_name(dev->of_node, "i2c-gate");

View file

@ -12,7 +12,9 @@
#include "inv_mpu_magn.h"
/*
* MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus
* MPU9xxx magnetometer are AKM chips on I2C aux bus
* MPU9150 is AK8975
* MPU9250 is AK8963
*/
#define INV_MPU_MAGN_I2C_ADDR 0x0C
@ -33,10 +35,10 @@
#define INV_MPU_MAGN_BITS_MODE_PWDN 0x00
#define INV_MPU_MAGN_BITS_MODE_SINGLE 0x01
#define INV_MPU_MAGN_BITS_MODE_FUSE 0x0F
#define INV_MPU_MAGN_BIT_OUTPUT_BIT 0x10
#define INV_MPU9250_MAGN_BIT_OUTPUT_BIT 0x10
#define INV_MPU_MAGN_REG_CNTL2 0x0B
#define INV_MPU_MAGN_BIT_SRST 0x01
#define INV_MPU9250_MAGN_REG_CNTL2 0x0B
#define INV_MPU9250_MAGN_BIT_SRST 0x01
#define INV_MPU_MAGN_REG_ASAX 0x10
#define INV_MPU_MAGN_REG_ASAY 0x11
@ -48,6 +50,7 @@
static bool inv_magn_supported(const struct inv_mpu6050_state *st)
{
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
return true;
@ -61,6 +64,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
{
uint8_t val;
uint8_t asa[3];
int32_t sensitivity;
int ret;
/* check whoami */
@ -71,12 +75,19 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
if (val != INV_MPU_MAGN_BITS_WIA)
return -ENODEV;
/* reset chip */
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
INV_MPU_MAGN_REG_CNTL2,
INV_MPU_MAGN_BIT_SRST);
if (ret)
return ret;
/* software reset for MPU925x only */
switch (st->chip_type) {
case INV_MPU9250:
case INV_MPU9255:
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
INV_MPU9250_MAGN_REG_CNTL2,
INV_MPU9250_MAGN_BIT_SRST);
if (ret)
return ret;
break;
default:
break;
}
/* read fuse ROM data */
ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR,
@ -97,6 +108,25 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
if (ret)
return ret;
/*
* Sensor sentivity
* 1 uT = 0.01 G and value is in micron (1e6)
* sensitvity = x uT * 0.01 * 1e6
*/
switch (st->chip_type) {
case INV_MPU9150:
/* sensor sensitivity is 0.3 uT */
sensitivity = 3000;
break;
case INV_MPU9250:
case INV_MPU9255:
/* sensor sensitivity in 16 bits mode: 0.15 uT */
sensitivity = 1500;
break;
default:
return -EINVAL;
}
/*
* Sensitivity adjustement and scale to Gauss
*
@ -104,16 +134,11 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
* Factor simplification:
* Hadj = H * ((ASA + 128) / 256)
*
* Sensor sentivity
* 0.15 uT in 16 bits mode
* 1 uT = 0.01 G and value is in micron (1e6)
* sensitvity = 0.15 uT * 0.01 * 1e6
*
* raw_to_gauss = Hadj * 1500
* raw_to_gauss = Hadj * sensitivity
*/
st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256;
st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256;
st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256;
st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * sensitivity) / 256;
st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * sensitivity) / 256;
st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * sensitivity) / 256;
return 0;
}
@ -129,6 +154,7 @@ static int inv_magn_init(struct inv_mpu6050_state *st)
*/
int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
{
uint8_t val;
int ret;
/* quit if chip is not supported */
@ -179,10 +205,17 @@ int inv_mpu_magn_probe(struct inv_mpu6050_state *st)
if (ret)
return ret;
/* add 16 bits mode */
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1),
INV_MPU_MAGN_BITS_MODE_SINGLE |
INV_MPU_MAGN_BIT_OUTPUT_BIT);
/* add 16 bits mode for MPU925x */
val = INV_MPU_MAGN_BITS_MODE_SINGLE;
switch (st->chip_type) {
case INV_MPU9250:
case INV_MPU9255:
val |= INV_MPU9250_MAGN_BIT_OUTPUT_BIT;
break;
default:
break;
}
ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), val);
if (ret)
return ret;
@ -237,6 +270,7 @@ int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st)
/* fill magnetometer orientation */
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
/* x <- y */

View file

@ -74,7 +74,6 @@ static int inv_mpu_probe(struct spi_device *spi)
static const struct spi_device_id inv_mpu_id[] = {
{"mpu6000", INV_MPU6000},
{"mpu6500", INV_MPU6500},
{"mpu9150", INV_MPU9150},
{"mpu9250", INV_MPU9250},
{"mpu9255", INV_MPU9255},
{"icm20608", INV_ICM20608},

View file

@ -50,6 +50,7 @@ static void inv_scan_query(struct iio_dev *indio_dev)
struct inv_mpu6050_state *st = iio_priv(indio_dev);
switch (st->chip_type) {
case INV_MPU9150:
case INV_MPU9250:
case INV_MPU9255:
return inv_scan_query_mpu9x50(indio_dev);

View file

@ -176,21 +176,38 @@ struct st_lsm6dsx_hw_ts_settings {
* @pullup_en: i2c controller pull-up register info (addr + mask).
* @aux_sens: aux sensor register info (addr + mask).
* @wr_once: write_once register info (addr + mask).
* @emb_func: embedded function register info (addr + mask).
* @num_ext_dev: max number of slave devices.
* @shub_out: sensor hub first output register info.
* @slv0_addr: slave0 address in secondary page.
* @dw_slv0_addr: slave0 write register address in secondary page.
* @batch_en: Enable/disable FIFO batching.
* @pause: controller pause value.
*/
struct st_lsm6dsx_shub_settings {
struct st_lsm6dsx_reg page_mux;
struct st_lsm6dsx_reg master_en;
struct st_lsm6dsx_reg pullup_en;
struct {
bool sec_page;
u8 addr;
u8 mask;
} master_en;
struct {
bool sec_page;
u8 addr;
u8 mask;
} pullup_en;
struct st_lsm6dsx_reg aux_sens;
struct st_lsm6dsx_reg wr_once;
u8 shub_out;
struct st_lsm6dsx_reg emb_func;
u8 num_ext_dev;
struct {
bool sec_page;
u8 addr;
} shub_out;
u8 slv0_addr;
u8 dw_slv0_addr;
u8 batch_en;
u8 pause;
};
struct st_lsm6dsx_event_settings {
@ -389,14 +406,17 @@ struct st_lsm6dsx_hw {
const struct st_lsm6dsx_settings *settings;
};
static const struct iio_event_spec st_lsm6dsx_event = {
static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE)
};
static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
static __maybe_unused const unsigned long st_lsm6dsx_available_scan_masks[] = {
0x7, 0x0,
};
extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,

View file

@ -336,12 +336,13 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
*/
int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
{
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor, *ext_sensor = NULL;
int err, acc_sip, gyro_sip, ts_sip, ext_sip, read_len, offset;
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
int err, acc_sip, gyro_sip, ts_sip, read_len, offset;
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
u8 gyro_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
u8 acc_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
u8 ext_buff[ST_LSM6DSX_IIO_BUFF_SIZE];
bool reset_ts = false;
__le16 fifo_status;
s64 ts = 0;
@ -364,6 +365,8 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
if (hw->iio_devs[ST_LSM6DSX_ID_EXT0])
ext_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_EXT0]);
for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
@ -391,12 +394,13 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
* following pattern is repeated every 9 samples:
* - Gx, Gy, Gz, Ax, Ay, Az, Ts, Gx, Gy, Gz, Ts, Gx, ..
*/
ext_sip = ext_sensor ? ext_sensor->sip : 0;
gyro_sip = gyro_sensor->sip;
acc_sip = acc_sensor->sip;
ts_sip = hw->ts_sip;
offset = 0;
while (acc_sip > 0 || gyro_sip > 0) {
while (acc_sip > 0 || gyro_sip > 0 || ext_sip > 0) {
if (gyro_sip > 0) {
memcpy(gyro_buff, &hw->buff[offset],
ST_LSM6DSX_SAMPLE_SIZE);
@ -407,6 +411,11 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
ST_LSM6DSX_SAMPLE_SIZE);
offset += ST_LSM6DSX_SAMPLE_SIZE;
}
if (ext_sip > 0) {
memcpy(ext_buff, &hw->buff[offset],
ST_LSM6DSX_SAMPLE_SIZE);
offset += ST_LSM6DSX_SAMPLE_SIZE;
}
if (ts_sip-- > 0) {
u8 data[ST_LSM6DSX_SAMPLE_SIZE];
@ -440,6 +449,10 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_ACC],
acc_buff, acc_sensor->ts_ref + ts);
if (ext_sip-- > 0)
iio_push_to_buffers_with_timestamp(
hw->iio_devs[ST_LSM6DSX_ID_EXT0],
ext_buff, ext_sensor->ts_ref + ts);
}
}
@ -638,12 +651,12 @@ int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable)
err = st_lsm6dsx_sensor_set_enable(sensor, enable);
if (err < 0)
goto out;
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
goto out;
}
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
goto out;
err = st_lsm6dsx_update_decimators(hw);
if (err < 0)
goto out;

View file

@ -54,6 +54,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/bitfield.h>
@ -655,6 +656,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
[ST_LSM6DSX_ID_EXT0] = {
.addr = 0x09,
.mask = GENMASK(2, 0),
},
},
.fifo_ops = {
.update_fifo = st_lsm6dsx_update_fifo,
@ -687,6 +692,39 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.mask = GENMASK(5, 3),
},
},
.shub_settings = {
.page_mux = {
.addr = 0x01,
.mask = BIT(7),
},
.master_en = {
.addr = 0x1a,
.mask = BIT(0),
},
.pullup_en = {
.addr = 0x1a,
.mask = BIT(3),
},
.aux_sens = {
.addr = 0x04,
.mask = GENMASK(5, 4),
},
.wr_once = {
.addr = 0x07,
.mask = BIT(5),
},
.emb_func = {
.addr = 0x19,
.mask = BIT(2),
},
.num_ext_dev = 1,
.shub_out = {
.addr = 0x2e,
},
.slv0_addr = 0x02,
.dw_slv0_addr = 0x0e,
.pause = 0x7,
},
.event_settings = {
.enable_reg = {
.addr = 0x58,
@ -867,10 +905,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.mask = BIT(6),
},
.master_en = {
.sec_page = true,
.addr = 0x14,
.mask = BIT(2),
},
.pullup_en = {
.sec_page = true,
.addr = 0x14,
.mask = BIT(3),
},
@ -882,7 +922,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x14,
.mask = BIT(6),
},
.shub_out = 0x02,
.num_ext_dev = 3,
.shub_out = {
.sec_page = true,
.addr = 0x02,
},
.slv0_addr = 0x15,
.dw_slv0_addr = 0x21,
.batch_en = BIT(3),
@ -1241,10 +1285,12 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.mask = BIT(6),
},
.master_en = {
.sec_page = true,
.addr = 0x14,
.mask = BIT(2),
},
.pullup_en = {
.sec_page = true,
.addr = 0x14,
.mask = BIT(3),
},
@ -1256,7 +1302,11 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.addr = 0x14,
.mask = BIT(6),
},
.shub_out = 0x02,
.num_ext_dev = 3,
.shub_out = {
.sec_page = true,
.addr = 0x02,
},
.slv0_addr = 0x15,
.dw_slv0_addr = 0x21,
.batch_en = BIT(3),
@ -1608,11 +1658,11 @@ static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state)
}
static int st_lsm6dsx_read_event(struct iio_dev *iio_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)
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)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
struct st_lsm6dsx_hw *hw = sensor->hw;
@ -1826,14 +1876,14 @@ static const struct iio_info st_lsm6dsx_gyro_info = {
.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
};
static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
static int st_lsm6dsx_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
{
struct device_node *np = hw->dev->of_node;
struct device *dev = hw->dev;
if (!np)
if (!dev_fwnode(dev))
return -EINVAL;
return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
return device_property_read_u32(dev, "st,drdy-int-pin", drdy_pin);
}
static int
@ -1842,7 +1892,7 @@ st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw,
{
int err = 0, drdy_pin;
if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) {
if (st_lsm6dsx_get_drdy_pin(hw, &drdy_pin) < 0) {
struct st_sensors_platform_data *pdata;
struct device *dev = hw->dev;
@ -1871,26 +1921,29 @@ st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw,
static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
struct device_node *np = hw->dev->of_node;
struct st_sensors_platform_data *pdata;
struct device *dev = hw->dev;
unsigned int data;
int err = 0;
hub_settings = &hw->settings->shub_settings;
pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
if ((np && of_property_read_bool(np, "st,pullups")) ||
pdata = (struct st_sensors_platform_data *)dev->platform_data;
if ((dev_fwnode(dev) && device_property_read_bool(dev, "st,pullups")) ||
(pdata && pdata->pullups)) {
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
return err;
if (hub_settings->pullup_en.sec_page) {
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
return err;
}
data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask);
err = regmap_update_bits(hw->regmap,
hub_settings->pullup_en.addr,
hub_settings->pullup_en.mask, data);
st_lsm6dsx_set_page(hw, false);
if (hub_settings->pullup_en.sec_page)
st_lsm6dsx_set_page(hw, false);
if (err < 0)
return err;
@ -1908,6 +1961,16 @@ static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
hub_settings->aux_sens.mask, data);
st_lsm6dsx_set_page(hw, false);
if (err < 0)
return err;
}
if (hub_settings->emb_func.addr) {
data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->emb_func.mask);
err = regmap_update_bits(hw->regmap,
hub_settings->emb_func.addr,
hub_settings->emb_func.mask, data);
}
return err;
@ -2157,9 +2220,9 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
{
struct device_node *np = hw->dev->of_node;
struct st_sensors_platform_data *pdata;
const struct st_lsm6dsx_reg *reg;
struct device *dev = hw->dev;
unsigned long irq_type;
bool irq_active_low;
int err;
@ -2187,8 +2250,8 @@ static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw)
if (err < 0)
return err;
pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
if ((np && of_property_read_bool(np, "drive-open-drain")) ||
pdata = (struct st_sensors_platform_data *)dev->platform_data;
if ((dev_fwnode(dev) && device_property_read_bool(dev, "drive-open-drain")) ||
(pdata && pdata->open_drain)) {
reg = &hw->settings->irq_config.od;
err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
@ -2218,7 +2281,6 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
{
struct st_sensors_platform_data *pdata = dev->platform_data;
const struct st_lsm6dsx_shub_settings *hub_settings;
struct device_node *np = dev->of_node;
struct st_lsm6dsx_hw *hw;
const char *name = NULL;
int i, err;
@ -2281,7 +2343,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
return err;
}
if ((np && of_property_read_bool(np, "wakeup-source")) ||
if ((dev_fwnode(dev) && device_property_read_bool(dev, "wakeup-source")) ||
(pdata && pdata->wakeup_source))
device_init_wakeup(dev, true);

View file

@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "st_lsm6dsx.h"
@ -122,7 +121,7 @@ static struct i2c_driver st_lsm6dsx_driver = {
.driver = {
.name = "st_lsm6dsx_i2c",
.pm = &st_lsm6dsx_pm_ops,
.of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
.of_match_table = st_lsm6dsx_i2c_of_match,
},
.probe = st_lsm6dsx_i2c_probe,
.id_table = st_lsm6dsx_i2c_id_table,

View file

@ -30,7 +30,6 @@
#include "st_lsm6dsx.h"
#define ST_LSM6DSX_MAX_SLV_NUM 3
#define ST_LSM6DSX_SLV_ADDR(n, base) ((base) + (n) * 3)
#define ST_LSM6DSX_SLV_SUB_ADDR(n, base) ((base) + 1 + (n) * 3)
#define ST_LSM6DSX_SLV_CONFIG(n, base) ((base) + 2 + (n) * 3)
@ -102,24 +101,31 @@ static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
}
/**
* st_lsm6dsx_shub_read_reg - read i2c controller register
* st_lsm6dsx_shub_read_output - read i2c controller register
*
* Read st_lsm6dsx i2c controller register
*/
static int st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 addr,
u8 *data, int len)
static int
st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data,
int len)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
int err;
mutex_lock(&hw->page_lock);
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
goto out;
hub_settings = &hw->settings->shub_settings;
if (hub_settings->shub_out.sec_page) {
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
goto out;
}
err = regmap_bulk_read(hw->regmap, addr, data, len);
err = regmap_bulk_read(hw->regmap, hub_settings->shub_out.addr,
data, len);
st_lsm6dsx_set_page(hw, false);
if (hub_settings->shub_out.sec_page)
st_lsm6dsx_set_page(hw, false);
out:
mutex_unlock(&hw->page_lock);
@ -186,15 +192,18 @@ static int st_lsm6dsx_shub_master_enable(struct st_lsm6dsx_sensor *sensor,
mutex_lock(&hw->page_lock);
hub_settings = &hw->settings->shub_settings;
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
goto out;
if (hub_settings->master_en.sec_page) {
err = st_lsm6dsx_set_page(hw, true);
if (err < 0)
goto out;
}
data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->master_en.mask);
err = regmap_update_bits(hw->regmap, hub_settings->master_en.addr,
hub_settings->master_en.mask, data);
st_lsm6dsx_set_page(hw, false);
if (hub_settings->master_en.sec_page)
st_lsm6dsx_set_page(hw, false);
out:
mutex_unlock(&hw->page_lock);
@ -212,16 +221,21 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr,
u8 *data, int len)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
u8 config[3], slv_addr, slv_config = 0;
struct st_lsm6dsx_hw *hw = sensor->hw;
u8 config[3], slv_addr;
const struct st_lsm6dsx_reg *aux_sens;
int err;
hub_settings = &hw->settings->shub_settings;
slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
aux_sens = &hw->settings->shub_settings.aux_sens;
/* do not overwrite aux_sens */
if (slv_addr + 2 == aux_sens->addr)
slv_config = ST_LSM6DSX_SHIFT_VAL(3, aux_sens->mask);
config[0] = (sensor->ext_info.addr << 1) | 1;
config[1] = addr;
config[2] = len & ST_LS6DSX_READ_OP_MASK;
config[2] = (len & ST_LS6DSX_READ_OP_MASK) | slv_config;
err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
sizeof(config));
@ -234,12 +248,14 @@ st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr,
st_lsm6dsx_shub_wait_complete(hw);
err = st_lsm6dsx_shub_read_reg(hw, hub_settings->shub_out, data,
len & ST_LS6DSX_READ_OP_MASK);
err = st_lsm6dsx_shub_read_output(hw, data,
len & ST_LS6DSX_READ_OP_MASK);
st_lsm6dsx_shub_master_enable(sensor, false);
memset(config, 0, sizeof(config));
config[0] = hub_settings->pause;
config[1] = 0;
config[2] = slv_config;
return st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
sizeof(config));
}
@ -296,7 +312,8 @@ st_lsm6dsx_shub_write(struct st_lsm6dsx_sensor *sensor, u8 addr,
st_lsm6dsx_shub_master_enable(sensor, false);
}
memset(config, 0, sizeof(config));
config[0] = hub_settings->pause;
config[1] = 0;
return st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config));
}
@ -688,14 +705,19 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
const struct st_lsm6dsx_ext_dev_settings *settings)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
u8 config[3], data, slv_addr, slv_config = 0;
const struct st_lsm6dsx_reg *aux_sens;
struct st_lsm6dsx_sensor *sensor;
u8 config[3], data, slv_addr;
bool found = false;
int i, err;
hub_settings = &hw->settings->shub_settings;
slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
hub_settings = &hw->settings->shub_settings;
aux_sens = &hw->settings->shub_settings.aux_sens;
slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
/* do not overwrite aux_sens */
if (slv_addr + 2 == aux_sens->addr)
slv_config = ST_LSM6DSX_SHIFT_VAL(3, aux_sens->mask);
for (i = 0; i < ARRAY_SIZE(settings->i2c_addr); i++) {
if (!settings->i2c_addr[i])
@ -704,7 +726,7 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
/* read wai slave register */
config[0] = (settings->i2c_addr[i] << 1) | 0x1;
config[1] = settings->wai.addr;
config[2] = 0x1;
config[2] = 0x1 | slv_config;
err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
sizeof(config));
@ -717,9 +739,7 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
st_lsm6dsx_shub_wait_complete(hw);
err = st_lsm6dsx_shub_read_reg(hw,
hub_settings->shub_out,
&data, sizeof(data));
err = st_lsm6dsx_shub_read_output(hw, &data, sizeof(data));
st_lsm6dsx_shub_master_enable(sensor, false);
@ -735,7 +755,9 @@ st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
}
/* reset SLV0 channel */
memset(config, 0, sizeof(config));
config[0] = hub_settings->pause;
config[1] = 0;
config[2] = slv_config;
err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
sizeof(config));
if (err < 0)
@ -770,7 +792,7 @@ int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name)
if (err < 0)
return err;
if (++num_ext_dev >= ST_LSM6DSX_MAX_SLV_NUM)
if (++num_ext_dev >= hw->settings->shub_settings.num_ext_dev)
break;
id++;
}

View file

@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "st_lsm6dsx.h"
@ -122,7 +121,7 @@ static struct spi_driver st_lsm6dsx_driver = {
.driver = {
.name = "st_lsm6dsx_spi",
.pm = &st_lsm6dsx_pm_ops,
.of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
.of_match_table = st_lsm6dsx_spi_of_match,
},
.probe = st_lsm6dsx_spi_probe,
.id_table = st_lsm6dsx_spi_id_table,

View file

@ -87,7 +87,7 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
}
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
* iio_buffer_read_outer() - chrdev read for buffer access
* @filp: File structure pointer for the char device
* @buf: Destination buffer for iio buffer read
* @n: First n bytes to read
@ -99,8 +99,8 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
* Return: negative values corresponding to error codes or ret != 0
* for ending the reading activity
**/
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps)
ssize_t iio_buffer_read_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps)
{
struct iio_dev *indio_dev = filp->private_data;
struct iio_buffer *rb = indio_dev->buffer;
@ -112,7 +112,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
if (!indio_dev->info)
return -ENODEV;
if (!rb || !rb->access->read_first_n)
if (!rb || !rb->access->read)
return -EINVAL;
datum_size = rb->bytes_per_datum;
@ -147,7 +147,7 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
continue;
}
ret = rb->access->read_first_n(rb, n, buf);
ret = rb->access->read(rb, n, buf);
if (ret == 0 && (filp->f_flags & O_NONBLOCK))
ret = -EAGAIN;
} while (ret == 0);

View file

@ -161,6 +161,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time",
[IIO_CHAN_INFO_CALIBEMISSIVITY] = "calibemissivity",
[IIO_CHAN_INFO_OVERSAMPLING_RATIO] = "oversampling_ratio",
[IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type",
};
/**
@ -596,6 +597,8 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
}
return l;
}
case IIO_VAL_CHAR:
return snprintf(buf, len, "%c", (char)vals[0]);
default:
return 0;
}
@ -837,7 +840,8 @@ static ssize_t iio_write_channel_info(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, fract_mult = 100000;
int integer, fract;
int integer, fract = 0;
bool is_char = false;
/* Assumes decimal - precision based on number of digits */
if (!indio_dev->info->write_raw)
@ -855,13 +859,24 @@ static ssize_t iio_write_channel_info(struct device *dev,
case IIO_VAL_INT_PLUS_NANO:
fract_mult = 100000000;
break;
case IIO_VAL_CHAR:
is_char = true;
break;
default:
return -EINVAL;
}
ret = iio_str_to_fixpoint(buf, fract_mult, &integer, &fract);
if (ret)
return ret;
if (is_char) {
char ch;
if (sscanf(buf, "%c", &ch) != 1)
return -EINVAL;
integer = ch;
} else {
ret = iio_str_to_fixpoint(buf, fract_mult, &integer, &fract);
if (ret)
return ret;
}
ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
integer, fract, this_attr->address);
@ -1617,7 +1632,7 @@ static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
}
static const struct file_operations iio_buffer_fileops = {
.read = iio_buffer_read_first_n_outer_addr,
.read = iio_buffer_read_outer_addr,
.release = iio_chrdev_release,
.open = iio_chrdev_open,
.poll = iio_buffer_poll_addr,

View file

@ -15,7 +15,6 @@
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
@ -24,7 +23,6 @@
#include <linux/iio/events.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
#include <linux/of_gpio.h>
#define APDS9960_REGMAP_NAME "apds9960_regmap"
#define APDS9960_DRV_NAME "apds9960"

View file

@ -742,7 +742,7 @@ static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) {
dev_err(&als->pdev->dev, "invalid resistor value\n");
return -EINVAL;
};
}
ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
if (ret) {

View file

@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>

View file

@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>

View file

@ -16,8 +16,7 @@
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/acpi.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
@ -360,7 +359,7 @@ struct ak8975_data {
struct mutex lock;
u8 asa[3];
long raw_to_gauss[3];
int eoc_gpio;
struct gpio_desc *eoc_gpiod;
int eoc_irq;
wait_queue_head_t data_ready_queue;
unsigned long flags;
@ -498,15 +497,13 @@ static int ak8975_setup_irq(struct ak8975_data *data)
if (client->irq)
irq = client->irq;
else
irq = gpio_to_irq(data->eoc_gpio);
irq = gpiod_to_irq(data->eoc_gpiod);
rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&client->dev), data);
if (rc < 0) {
dev_err(&client->dev,
"irq %d request failed, (gpio %d): %d\n",
irq, data->eoc_gpio, rc);
dev_err(&client->dev, "irq %d request failed: %d\n", irq, rc);
return rc;
}
@ -549,7 +546,7 @@ static int ak8975_setup(struct i2c_client *client)
return ret;
}
if (data->eoc_gpio > 0 || client->irq > 0) {
if (data->eoc_gpiod || client->irq > 0) {
ret = ak8975_setup_irq(data);
if (ret < 0) {
dev_err(&client->dev,
@ -574,7 +571,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
/* Wait for the conversion to complete. */
while (timeout_ms) {
msleep(AK8975_CONVERSION_DONE_POLL_TIME);
if (gpio_get_value(data->eoc_gpio))
if (gpiod_get_value(data->eoc_gpiod))
break;
timeout_ms -= AK8975_CONVERSION_DONE_POLL_TIME;
}
@ -646,7 +643,7 @@ static int ak8975_start_read_axis(struct ak8975_data *data,
/* Wait for the conversion to complete. */
if (data->eoc_irq)
ret = wait_conversion_complete_interrupt(data);
else if (gpio_is_valid(data->eoc_gpio))
else if (data->eoc_gpiod)
ret = wait_conversion_complete_gpio(data);
else
ret = wait_conversion_complete_polled(data);
@ -856,36 +853,23 @@ static int ak8975_probe(struct i2c_client *client,
{
struct ak8975_data *data;
struct iio_dev *indio_dev;
int eoc_gpio;
struct gpio_desc *eoc_gpiod;
int err;
const char *name = NULL;
enum asahi_compass_chipset chipset = AK_MAX_TYPE;
const struct ak8975_platform_data *pdata =
dev_get_platdata(&client->dev);
/* Grab and set up the supplied GPIO. */
if (pdata)
eoc_gpio = pdata->eoc_gpio;
else if (client->dev.of_node)
eoc_gpio = of_get_gpio(client->dev.of_node, 0);
else
eoc_gpio = -1;
if (eoc_gpio == -EPROBE_DEFER)
return -EPROBE_DEFER;
/* We may not have a GPIO based IRQ to scan, that is fine, we will
poll if so */
if (gpio_is_valid(eoc_gpio)) {
err = devm_gpio_request_one(&client->dev, eoc_gpio,
GPIOF_IN, "ak_8975");
if (err < 0) {
dev_err(&client->dev,
"failed to request GPIO %d, error %d\n",
eoc_gpio, err);
return err;
}
}
/*
* Grab and set up the supplied GPIO.
* We may not have a GPIO based IRQ to scan, that is fine, we will
* poll if so.
*/
eoc_gpiod = devm_gpiod_get_optional(&client->dev, NULL, GPIOD_IN);
if (IS_ERR(eoc_gpiod))
return PTR_ERR(eoc_gpiod);
if (eoc_gpiod)
gpiod_set_consumer_name(eoc_gpiod, "ak_8975");
/* Register with IIO */
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
@ -896,7 +880,7 @@ static int ak8975_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->eoc_gpio = eoc_gpio;
data->eoc_gpiod = eoc_gpiod;
data->eoc_irq = 0;
if (!pdata) {

View file

@ -53,6 +53,18 @@ config IIO_CROS_EC_BARO
To compile this driver as a module, choose M here: the module
will be called cros_ec_baro.
config DLHL60D
tristate "All Sensors DLHL60D and DLHL60G low voltage digital pressure sensors"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the All Sensors DLH series
pressure sensors driver.
To compile this driver as a module, choose M here: the module
will be called dlhl60d.
config DPS310
tristate "Infineon DPS310 pressure and temperature sensor"
depends on I2C

View file

@ -9,6 +9,7 @@ obj-$(CONFIG_BMP280) += bmp280.o
bmp280-objs := bmp280-core.o bmp280-regmap.o
obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
obj-$(CONFIG_DLHL60D) += dlhl60d.o
obj-$(CONFIG_DPS310) += dps310.o
obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o

View file

@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "bmp280.h"
@ -38,16 +36,6 @@ static int bmp280_i2c_probe(struct i2c_client *client,
client->irq);
}
static const struct acpi_device_id bmp280_acpi_i2c_match[] = {
{"BMP0280", BMP280_CHIP_ID },
{"BMP0180", BMP180_CHIP_ID },
{"BMP0085", BMP180_CHIP_ID },
{"BME0280", BME280_CHIP_ID },
{ },
};
MODULE_DEVICE_TABLE(acpi, bmp280_acpi_i2c_match);
#ifdef CONFIG_OF
static const struct of_device_id bmp280_of_i2c_match[] = {
{ .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID },
{ .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID },
@ -56,9 +44,6 @@ static const struct of_device_id bmp280_of_i2c_match[] = {
{ },
};
MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
#else
#define bmp280_of_i2c_match NULL
#endif
static const struct i2c_device_id bmp280_i2c_id[] = {
{"bmp280", BMP280_CHIP_ID },
@ -72,8 +57,7 @@ MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id);
static struct i2c_driver bmp280_i2c_driver = {
.driver = {
.name = "bmp280",
.acpi_match_table = ACPI_PTR(bmp280_acpi_i2c_match),
.of_match_table = of_match_ptr(bmp280_of_i2c_match),
.of_match_table = bmp280_of_i2c_match,
.pm = &bmp280_dev_pm_ops,
},
.probe = bmp280_i2c_probe,

View file

@ -0,0 +1,375 @@
// SPDX-License-Identifier: GPL-2.0
/*
* All Sensors DLH series low voltage digital pressure sensors
*
* Copyright (c) 2019 AVL DiTEST GmbH
* Tomislav Denis <tomislav.denis@avl.com>
*
* Datasheet: http://www.allsensors.com/cad/DS-0355_Rev_B.PDF
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <asm/unaligned.h>
/* Commands */
#define DLH_START_SINGLE 0xAA
/* Status bits */
#define DLH_STATUS_OK 0x40
/* DLH data format */
#define DLH_NUM_READ_BYTES 7
#define DLH_NUM_DATA_BYTES 3
#define DLH_NUM_PR_BITS 24
#define DLH_NUM_TEMP_BITS 24
/* DLH timings */
#define DLH_SINGLE_DUT_MS 5
enum dhl_ids {
dlhl60d,
dlhl60g,
};
struct dlh_info {
u8 osdig; /* digital offset factor */
unsigned int fss; /* full scale span (inch H2O) */
};
struct dlh_state {
struct i2c_client *client;
struct dlh_info info;
bool use_interrupt;
struct completion completion;
u8 rx_buf[DLH_NUM_READ_BYTES] ____cacheline_aligned;
};
static struct dlh_info dlh_info_tbl[] = {
[dlhl60d] = {
.osdig = 2,
.fss = 120,
},
[dlhl60g] = {
.osdig = 10,
.fss = 60,
},
};
static int dlh_cmd_start_single(struct dlh_state *st)
{
int ret;
ret = i2c_smbus_write_byte(st->client, DLH_START_SINGLE);
if (ret)
dev_err(&st->client->dev,
"%s: I2C write byte failed\n", __func__);
return ret;
}
static int dlh_cmd_read_data(struct dlh_state *st)
{
int ret;
ret = i2c_master_recv(st->client, st->rx_buf, DLH_NUM_READ_BYTES);
if (ret < 0) {
dev_err(&st->client->dev,
"%s: I2C read block failed\n", __func__);
return ret;
}
if (st->rx_buf[0] != DLH_STATUS_OK) {
dev_err(&st->client->dev,
"%s: invalid status 0x%02x\n", __func__, st->rx_buf[0]);
return -EBUSY;
}
return 0;
}
static int dlh_start_capture_and_read(struct dlh_state *st)
{
int ret;
if (st->use_interrupt)
reinit_completion(&st->completion);
ret = dlh_cmd_start_single(st);
if (ret)
return ret;
if (st->use_interrupt) {
ret = wait_for_completion_timeout(&st->completion,
msecs_to_jiffies(DLH_SINGLE_DUT_MS));
if (!ret) {
dev_err(&st->client->dev,
"%s: conversion timed out\n", __func__);
return -ETIMEDOUT;
}
} else {
mdelay(DLH_SINGLE_DUT_MS);
}
return dlh_cmd_read_data(st);
}
static int dlh_read_direct(struct dlh_state *st,
unsigned int *pressure, unsigned int *temperature)
{
int ret;
ret = dlh_start_capture_and_read(st);
if (ret)
return ret;
*pressure = get_unaligned_be32(&st->rx_buf[1]) >> 8;
*temperature = get_unaligned_be32(&st->rx_buf[3]) &
GENMASK(DLH_NUM_TEMP_BITS - 1, 0);
return 0;
}
static int dlh_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *value,
int *value2, long mask)
{
struct dlh_state *st = iio_priv(indio_dev);
unsigned int pressure, temperature;
int ret;
s64 tmp;
s32 rem;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = dlh_read_direct(st, &pressure, &temperature);
iio_device_release_direct_mode(indio_dev);
if (ret)
return ret;
switch (channel->type) {
case IIO_PRESSURE:
*value = pressure;
return IIO_VAL_INT;
case IIO_TEMP:
*value = temperature;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (channel->type) {
case IIO_PRESSURE:
tmp = div_s64(125LL * st->info.fss * 24909 * 100,
1 << DLH_NUM_PR_BITS);
tmp = div_s64_rem(tmp, 1000000000LL, &rem);
*value = tmp;
*value2 = rem;
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
*value = 125 * 1000;
*value2 = DLH_NUM_TEMP_BITS;
return IIO_VAL_FRACTIONAL_LOG2;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
switch (channel->type) {
case IIO_PRESSURE:
*value = -125 * st->info.fss * 24909;
*value2 = 100 * st->info.osdig * 100000;
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
*value = -40 * 1000;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
return -EINVAL;
}
static const struct iio_info dlh_info = {
.read_raw = dlh_read_raw,
};
static const struct iio_chan_spec dlh_channels[] = {
{
.type = IIO_PRESSURE,
.indexed = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = DLH_NUM_PR_BITS,
.storagebits = 32,
.shift = 8,
.endianness = IIO_BE,
},
}, {
.type = IIO_TEMP,
.indexed = 1,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
.scan_index = 1,
.scan_type = {
.sign = 'u',
.realbits = DLH_NUM_TEMP_BITS,
.storagebits = 32,
.shift = 8,
.endianness = IIO_BE,
},
}
};
static irqreturn_t dlh_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct dlh_state *st = iio_priv(indio_dev);
int ret;
unsigned int chn, i = 0;
__be32 tmp_buf[2];
ret = dlh_start_capture_and_read(st);
if (ret)
goto out;
for_each_set_bit(chn, indio_dev->active_scan_mask,
indio_dev->masklength) {
memcpy(tmp_buf + i,
&st->rx_buf[1] + chn * DLH_NUM_DATA_BYTES,
DLH_NUM_DATA_BYTES);
i++;
}
iio_push_to_buffers(indio_dev, tmp_buf);
out:
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static irqreturn_t dlh_interrupt(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct dlh_state *st = iio_priv(indio_dev);
complete(&st->completion);
return IRQ_HANDLED;
};
static int dlh_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct dlh_state *st;
struct iio_dev *indio_dev;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE)) {
dev_err(&client->dev,
"adapter doesn't support required i2c functionality\n");
return -EOPNOTSUPP;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (!indio_dev) {
dev_err(&client->dev, "failed to allocate iio device\n");
return -ENOMEM;
}
i2c_set_clientdata(client, indio_dev);
st = iio_priv(indio_dev);
st->info = dlh_info_tbl[id->driver_data];
st->client = client;
st->use_interrupt = false;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->dev.of_node = client->dev.of_node;
indio_dev->info = &dlh_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dlh_channels;
indio_dev->num_channels = ARRAY_SIZE(dlh_channels);
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
dlh_interrupt, NULL,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
id->name, indio_dev);
if (ret) {
dev_err(&client->dev, "failed to allocate threaded irq");
return ret;
}
st->use_interrupt = true;
init_completion(&st->completion);
}
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
NULL, &dlh_trigger_handler, NULL);
if (ret) {
dev_err(&client->dev, "failed to setup iio buffer\n");
return ret;
}
ret = devm_iio_device_register(&client->dev, indio_dev);
if (ret)
dev_err(&client->dev, "failed to register iio device\n");
return ret;
}
static const struct of_device_id dlh_of_match[] = {
{ .compatible = "asc,dlhl60d" },
{ .compatible = "asc,dlhl60g" },
{}
};
MODULE_DEVICE_TABLE(of, dlh_of_match);
static const struct i2c_device_id dlh_id[] = {
{ "dlhl60d", dlhl60d },
{ "dlhl60g", dlhl60g },
{}
};
MODULE_DEVICE_TABLE(i2c, dlh_id);
static struct i2c_driver dlh_driver = {
.driver = {
.name = "dlhl60d",
.of_match_table = dlh_of_match,
},
.probe = dlh_probe,
.id_table = dlh_id,
};
module_i2c_driver(dlh_driver);
MODULE_AUTHOR("Tomislav Denis <tomislav.denis@avl.com>");
MODULE_DESCRIPTION("Driver for All Sensors DLH series pressure sensors");
MODULE_LICENSE("GPL v2");

View file

@ -37,7 +37,7 @@ enum st_press_type {
* struct st_sensors_platform_data - default press platform data
* @drdy_int_pin: default press DRDY is available on INT1 pin.
*/
static const struct st_sensors_platform_data default_press_pdata = {
static __maybe_unused const struct st_sensors_platform_data default_press_pdata = {
.drdy_int_pin = 1,
};

View file

@ -61,8 +61,6 @@ static const struct acpi_device_id st_press_acpi_match[] = {
{ },
};
MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
#else
#define st_press_acpi_match NULL
#endif
static const struct i2c_device_id st_press_id_table[] = {

View file

@ -58,6 +58,21 @@ config MB1232
To compile this driver as a module, choose M here: the
module will be called mb1232.
config PING
tristate "Parallax GPIO bitbanged ranger sensors"
depends on GPIOLIB
help
Say Y here to build a driver for GPIO bitbanged ranger sensors
with just one GPIO for the trigger and echo. This driver can be
used to measure the distance of objects.
Actually supported are:
- Parallax PING))) (ultrasonic)
- Parallax LaserPING (time-of-flight)
To compile this driver as a module, choose M here: the
module will be called ping.
config RFD77402
tristate "RFD77402 ToF sensor"
depends on I2C

View file

@ -8,6 +8,7 @@ obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_ISL29501) += isl29501.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_MB1232) += mb1232.o
obj-$(CONFIG_PING) += ping.o
obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o

View file

@ -14,7 +14,6 @@
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@ -22,8 +21,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/of_gpio.h>
#define AS3935_AFE_GAIN 0x00
#define AS3935_AFE_MASK 0x3F

View file

@ -0,0 +1,335 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* PING: ultrasonic sensor for distance measuring by using only one GPIOs
*
* Copyright (c) 2019 Andreas Klinger <ak@it-klinger.de>
*
* For details about the devices see:
* http://parallax.com/sites/default/files/downloads/28041-LaserPING-2m-Rangefinder-Guide.pdf
* http://parallax.com/sites/default/files/downloads/28015-PING-Documentation-v1.6.pdf
*
* the measurement cycle as timing diagram looks like:
*
* GPIO ___ ________________________
* ping: __/ \____________/ \________________
* ^ ^ ^ ^
* |<->| interrupt interrupt
* udelay(5) (ts_rising) (ts_falling)
* |<---------------------->|
* . pulse time measured .
* . --> one round trip of ultra sonic waves
* ultra . .
* sonic _ _ _. .
* burst: _________/ \_/ \_/ \_________________________________________
* .
* ultra .
* sonic _ _ _.
* echo: __________________________________/ \_/ \_/ \________________
*/
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
struct ping_cfg {
unsigned long trigger_pulse_us; /* length of trigger pulse */
int laserping_error; /* support error code in */
/* pulse width of laser */
/* ping sensors */
s64 timeout_ns; /* timeout in ns */
};
struct ping_data {
struct device *dev;
struct gpio_desc *gpiod_ping;
struct mutex lock;
int irqnr;
ktime_t ts_rising;
ktime_t ts_falling;
struct completion rising;
struct completion falling;
const struct ping_cfg *cfg;
};
static const struct ping_cfg pa_ping_cfg = {
.trigger_pulse_us = 5,
.laserping_error = 0,
.timeout_ns = 18500000, /* 3 meters */
};
static const struct ping_cfg pa_laser_ping_cfg = {
.trigger_pulse_us = 5,
.laserping_error = 1,
.timeout_ns = 15500000, /* 2 meters plus error codes */
};
static irqreturn_t ping_handle_irq(int irq, void *dev_id)
{
struct iio_dev *indio_dev = dev_id;
struct ping_data *data = iio_priv(indio_dev);
ktime_t now = ktime_get();
if (gpiod_get_value(data->gpiod_ping)) {
data->ts_rising = now;
complete(&data->rising);
} else {
data->ts_falling = now;
complete(&data->falling);
}
return IRQ_HANDLED;
}
static int ping_read(struct ping_data *data)
{
int ret;
ktime_t ktime_dt;
s64 dt_ns;
u32 time_ns, distance_mm;
struct platform_device *pdev = to_platform_device(data->dev);
struct iio_dev *indio_dev = iio_priv_to_dev(data);
/*
* just one read-echo-cycle can take place at a time
* ==> lock against concurrent reading calls
*/
mutex_lock(&data->lock);
reinit_completion(&data->rising);
reinit_completion(&data->falling);
gpiod_set_value(data->gpiod_ping, 1);
udelay(data->cfg->trigger_pulse_us);
gpiod_set_value(data->gpiod_ping, 0);
ret = gpiod_direction_input(data->gpiod_ping);
if (ret < 0) {
mutex_unlock(&data->lock);
return ret;
}
data->irqnr = gpiod_to_irq(data->gpiod_ping);
if (data->irqnr < 0) {
dev_err(data->dev, "gpiod_to_irq: %d\n", data->irqnr);
mutex_unlock(&data->lock);
return data->irqnr;
}
ret = request_irq(data->irqnr, ping_handle_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
pdev->name, indio_dev);
if (ret < 0) {
dev_err(data->dev, "request_irq: %d\n", ret);
mutex_unlock(&data->lock);
return ret;
}
/* it should not take more than 20 ms until echo is rising */
ret = wait_for_completion_killable_timeout(&data->rising, HZ/50);
if (ret < 0)
goto err_reset_direction;
else if (ret == 0) {
ret = -ETIMEDOUT;
goto err_reset_direction;
}
/* it cannot take more than 50 ms until echo is falling */
ret = wait_for_completion_killable_timeout(&data->falling, HZ/20);
if (ret < 0)
goto err_reset_direction;
else if (ret == 0) {
ret = -ETIMEDOUT;
goto err_reset_direction;
}
ktime_dt = ktime_sub(data->ts_falling, data->ts_rising);
free_irq(data->irqnr, indio_dev);
ret = gpiod_direction_output(data->gpiod_ping, GPIOD_OUT_LOW);
if (ret < 0) {
mutex_unlock(&data->lock);
return ret;
}
mutex_unlock(&data->lock);
dt_ns = ktime_to_ns(ktime_dt);
if (dt_ns > data->cfg->timeout_ns) {
dev_dbg(data->dev, "distance out of range: dt=%lldns\n",
dt_ns);
return -EIO;
}
time_ns = dt_ns;
/*
* read error code of laser ping sensor and give users chance to
* figure out error by using dynamic debuggging
*/
if (data->cfg->laserping_error) {
if ((time_ns > 12500000) && (time_ns <= 13500000)) {
dev_dbg(data->dev, "target too close or to far\n");
return -EIO;
}
if ((time_ns > 13500000) && (time_ns <= 14500000)) {
dev_dbg(data->dev, "internal sensor error\n");
return -EIO;
}
if ((time_ns > 14500000) && (time_ns <= 15500000)) {
dev_dbg(data->dev, "internal sensor timeout\n");
return -EIO;
}
}
/*
* the speed as function of the temperature is approximately:
*
* speed = 331,5 + 0,6 * Temp
* with Temp in °C
* and speed in m/s
*
* use 343,5 m/s as ultrasonic speed at 20 °C here in absence of the
* temperature
*
* therefore:
* time 343,5 time * 232
* distance = ------ * ------- = ------------
* 10^6 2 1350800
* with time in ns
* and distance in mm (one way)
*
* because we limit to 3 meters the multiplication with 232 just
* fits into 32 bit
*/
distance_mm = time_ns * 232 / 1350800;
return distance_mm;
err_reset_direction:
free_irq(data->irqnr, indio_dev);
mutex_unlock(&data->lock);
if (gpiod_direction_output(data->gpiod_ping, GPIOD_OUT_LOW))
dev_dbg(data->dev, "error in gpiod_direction_output\n");
return ret;
}
static int ping_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long info)
{
struct ping_data *data = iio_priv(indio_dev);
int ret;
if (channel->type != IIO_DISTANCE)
return -EINVAL;
switch (info) {
case IIO_CHAN_INFO_RAW:
ret = ping_read(data);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/*
* maximum resolution in datasheet is 1 mm
* 1 LSB is 1 mm
*/
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static const struct iio_info ping_iio_info = {
.read_raw = ping_read_raw,
};
static const struct iio_chan_spec ping_chan_spec[] = {
{
.type = IIO_DISTANCE,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static const struct of_device_id of_ping_match[] = {
{ .compatible = "parallax,ping", .data = &pa_ping_cfg},
{ .compatible = "parallax,laserping", .data = &pa_ping_cfg},
{},
};
MODULE_DEVICE_TABLE(of, of_ping_match);
static int ping_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ping_data *data;
struct iio_dev *indio_dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(struct ping_data));
if (!indio_dev) {
dev_err(dev, "failed to allocate IIO device\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
data->dev = dev;
data->cfg = of_device_get_match_data(dev);
mutex_init(&data->lock);
init_completion(&data->rising);
init_completion(&data->falling);
data->gpiod_ping = devm_gpiod_get(dev, "ping", GPIOD_OUT_LOW);
if (IS_ERR(data->gpiod_ping)) {
dev_err(dev, "failed to get ping-gpios: err=%ld\n",
PTR_ERR(data->gpiod_ping));
return PTR_ERR(data->gpiod_ping);
}
if (gpiod_cansleep(data->gpiod_ping)) {
dev_err(data->dev, "cansleep-GPIOs not supported\n");
return -ENODEV;
}
platform_set_drvdata(pdev, indio_dev);
indio_dev->name = "ping";
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &ping_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ping_chan_spec;
indio_dev->num_channels = ARRAY_SIZE(ping_chan_spec);
return devm_iio_device_register(dev, indio_dev);
}
static struct platform_driver ping_driver = {
.probe = ping_probe,
.driver = {
.name = "ping-gpio",
.of_match_table = of_ping_match,
},
};
module_platform_driver(ping_driver);
MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
MODULE_DESCRIPTION("PING sensors for distance measuring using one GPIOs");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ping");

View file

@ -10,7 +10,6 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/mutex.h>

View file

@ -6,12 +6,14 @@
* Copyright (C) 2018-2019 Rockwell Collins
*/
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/util_macros.h>
#include <dt-bindings/iio/temperature/thermocouple.h>
/*
* The MSB of the register value determines whether the following byte will
@ -23,6 +25,9 @@
#define MAX31856_CR0_1SHOT BIT(6)
#define MAX31856_CR0_OCFAULT BIT(4)
#define MAX31856_CR0_OCFAULT_MASK GENMASK(5, 4)
#define MAX31856_CR0_FILTER_50HZ BIT(0)
#define MAX31856_AVERAGING_MASK GENMASK(6, 4)
#define MAX31856_AVERAGING_SHIFT 4
#define MAX31856_TC_TYPE_MASK GENMASK(3, 0)
#define MAX31856_FAULT_OVUV BIT(1)
#define MAX31856_FAULT_OPEN BIT(0)
@ -49,7 +54,10 @@ static const struct iio_chan_spec max31856_channels[] = {
{ /* Thermocouple Temperature */
.type = IIO_TEMP,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)
},
{ /* Cold Junction Temperature */
.type = IIO_TEMP,
@ -57,12 +65,20 @@ static const struct iio_chan_spec max31856_channels[] = {
.modified = 1,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_type =
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO)
},
};
struct max31856_data {
struct spi_device *spi;
u32 thermocouple_type;
bool filter_50hz;
int averaging;
};
static const char max31856_tc_types[] = {
'B', 'E', 'J', 'K', 'N', 'R', 'S', 'T'
};
static int max31856_read(struct max31856_data *data, u8 reg,
@ -107,6 +123,10 @@ static int max31856_init(struct max31856_data *data)
reg_cr1_val &= ~MAX31856_TC_TYPE_MASK;
reg_cr1_val |= data->thermocouple_type;
reg_cr1_val &= ~MAX31856_AVERAGING_MASK;
reg_cr1_val |= data->averaging << MAX31856_AVERAGING_SHIFT;
ret = max31856_write(data, MAX31856_CR1_REG, reg_cr1_val);
if (ret)
return ret;
@ -123,6 +143,11 @@ static int max31856_init(struct max31856_data *data)
reg_cr0_val &= ~MAX31856_CR0_1SHOT;
reg_cr0_val |= MAX31856_CR0_AUTOCONVERT;
if (data->filter_50hz)
reg_cr0_val |= MAX31856_CR0_FILTER_50HZ;
else
reg_cr0_val &= ~MAX31856_CR0_FILTER_50HZ;
return max31856_write(data, MAX31856_CR0_REG, reg_cr0_val);
}
@ -210,6 +235,12 @@ static int max31856_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO;
}
break;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = 1 << data->averaging;
return IIO_VAL_INT;
case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
*val = max31856_tc_types[data->thermocouple_type];
return IIO_VAL_CHAR;
default:
ret = -EINVAL;
break;
@ -218,6 +249,62 @@ static int max31856_read_raw(struct iio_dev *indio_dev,
return ret;
}
static int max31856_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
return IIO_VAL_CHAR;
default:
return IIO_VAL_INT;
}
}
static int max31856_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct max31856_data *data = iio_priv(indio_dev);
int msb;
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
if (val > 16 || val < 1)
return -EINVAL;
msb = fls(val) - 1;
/* Round up to next 2pow if needed */
if (BIT(msb) < val)
msb++;
data->averaging = msb;
max31856_init(data);
break;
case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
{
int tc_type = -1;
int i;
for (i = 0; i < ARRAY_SIZE(max31856_tc_types); i++) {
if (max31856_tc_types[i] == toupper(val)) {
tc_type = i;
break;
}
}
if (tc_type < 0)
return -EINVAL;
data->thermocouple_type = tc_type;
max31856_init(data);
break;
}
default:
return -EINVAL;
}
return 0;
}
static ssize_t show_fault(struct device *dev, u8 faultbit, char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@ -249,12 +336,54 @@ static ssize_t show_fault_oc(struct device *dev,
return show_fault(dev, MAX31856_FAULT_OPEN, buf);
}
static ssize_t show_filter(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max31856_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->filter_50hz ? 50 : 60);
}
static ssize_t set_filter(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max31856_data *data = iio_priv(indio_dev);
unsigned int freq;
int ret;
ret = kstrtouint(buf, 10, &freq);
if (ret)
return ret;
switch (freq) {
case 50:
data->filter_50hz = true;
break;
case 60:
data->filter_50hz = false;
break;
default:
return -EINVAL;
}
max31856_init(data);
return len;
}
static IIO_DEVICE_ATTR(fault_ovuv, 0444, show_fault_ovuv, NULL, 0);
static IIO_DEVICE_ATTR(fault_oc, 0444, show_fault_oc, NULL, 0);
static IIO_DEVICE_ATTR(in_temp_filter_notch_center_frequency, 0644,
show_filter, set_filter, 0);
static struct attribute *max31856_attributes[] = {
&iio_dev_attr_fault_ovuv.dev_attr.attr,
&iio_dev_attr_fault_oc.dev_attr.attr,
&iio_dev_attr_in_temp_filter_notch_center_frequency.dev_attr.attr,
NULL,
};
@ -264,6 +393,8 @@ static const struct attribute_group max31856_group = {
static const struct iio_info max31856_info = {
.read_raw = max31856_read_raw,
.write_raw = max31856_write_raw,
.write_raw_get_fmt = max31856_write_raw_get_fmt,
.attrs = &max31856_group,
};
@ -280,6 +411,7 @@ static int max31856_probe(struct spi_device *spi)
data = iio_priv(indio_dev);
data->spi = spi;
data->filter_50hz = false;
spi_set_drvdata(spi, indio_dev);

View file

@ -14,6 +14,7 @@
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
@ -24,13 +25,25 @@
enum {
MAX6675,
MAX31855,
MAX31855K,
MAX31855J,
MAX31855N,
MAX31855S,
MAX31855T,
MAX31855E,
MAX31855R,
};
static const char maxim_tc_types[] = {
'K', '?', 'K', 'J', 'N', 'S', 'T', 'E', 'R'
};
static const struct iio_chan_spec max6675_channels[] = {
{ /* thermocouple temperature */
.type = IIO_TEMP,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE),
.scan_index = 0,
.scan_type = {
.sign = 's',
@ -48,7 +61,8 @@ static const struct iio_chan_spec max31855_channels[] = {
.type = IIO_TEMP,
.address = 2,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_THERMOCOUPLE_TYPE),
.scan_index = 0,
.scan_type = {
.sign = 's',
@ -110,6 +124,7 @@ struct maxim_thermocouple_data {
const struct maxim_thermocouple_chip *chip;
u8 buffer[16] ____cacheline_aligned;
char tc_type;
};
static int maxim_thermocouple_read(struct maxim_thermocouple_data *data,
@ -196,6 +211,10 @@ static int maxim_thermocouple_read_raw(struct iio_dev *indio_dev,
ret = IIO_VAL_INT;
}
break;
case IIO_CHAN_INFO_THERMOCOUPLE_TYPE:
*val = data->tc_type;
ret = IIO_VAL_CHAR;
break;
}
return ret;
@ -210,8 +229,9 @@ static int maxim_thermocouple_probe(struct spi_device *spi)
const struct spi_device_id *id = spi_get_device_id(spi);
struct iio_dev *indio_dev;
struct maxim_thermocouple_data *data;
const int chip_type = (id->driver_data == MAX6675) ? MAX6675 : MAX31855;
const struct maxim_thermocouple_chip *chip =
&maxim_thermocouple_chips[id->driver_data];
&maxim_thermocouple_chips[chip_type];
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
@ -229,6 +249,7 @@ static int maxim_thermocouple_probe(struct spi_device *spi)
data = iio_priv(indio_dev);
data->spi = spi;
data->chip = chip;
data->tc_type = maxim_tc_types[id->driver_data];
ret = devm_iio_triggered_buffer_setup(&spi->dev,
indio_dev, NULL,
@ -236,12 +257,22 @@ static int maxim_thermocouple_probe(struct spi_device *spi)
if (ret)
return ret;
if (id->driver_data == MAX31855)
dev_warn(&spi->dev, "generic max31855 ID is deprecated\nplease use more specific part type");
return devm_iio_device_register(&spi->dev, indio_dev);
}
static const struct spi_device_id maxim_thermocouple_id[] = {
{"max6675", MAX6675},
{"max31855", MAX31855},
{"max31855k", MAX31855K},
{"max31855j", MAX31855J},
{"max31855n", MAX31855N},
{"max31855s", MAX31855S},
{"max31855t", MAX31855T},
{"max31855e", MAX31855E},
{"max31855r", MAX31855R},
{},
};
MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
@ -249,6 +280,13 @@ MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
static const struct of_device_id maxim_thermocouple_of_match[] = {
{ .compatible = "maxim,max6675" },
{ .compatible = "maxim,max31855" },
{ .compatible = "maxim,max31855k" },
{ .compatible = "maxim,max31855j" },
{ .compatible = "maxim,max31855n" },
{ .compatible = "maxim,max31855s" },
{ .compatible = "maxim,max31855t" },
{ .compatible = "maxim,max31855e" },
{ .compatible = "maxim,max31855r" },
{ },
};
MODULE_DEVICE_TABLE(of, maxim_thermocouple_of_match);

View file

@ -297,9 +297,6 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
strlen(master_mode_table[i]))) {
regmap_update_bits(priv->regmap, TIM_CR2, mask,
i << shift);
/* Make sure that registers are updated */
regmap_update_bits(priv->regmap, TIM_EGR,
TIM_EGR_UG, TIM_EGR_UG);
return len;
}
}

View file

@ -399,6 +399,13 @@ static int adis16240_probe(struct spi_device *spi)
indio_dev->num_channels = ARRAY_SIZE(adis16240_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
spi->mode = SPI_MODE_3;
ret = spi_setup(spi);
if (ret) {
dev_err(&spi->dev, "spi_setup failed!\n");
return ret;
}
ret = adis_init(st, indio_dev, spi, &adis16240_data);
if (ret)
return ret;

View file

@ -18,7 +18,7 @@ struct iio_buffer;
/**
* struct iio_buffer_access_funcs - access functions for buffers.
* @store_to: actually store stuff to the buffer
* @read_first_n: try to get a specified number of bytes (must exist)
* @read: try to get a specified number of bytes (must exist)
* @data_available: indicates how much data is available for reading from
* the buffer.
* @request_update: if a parameter change has been marked, update underlying
@ -45,9 +45,7 @@ struct iio_buffer;
**/
struct iio_buffer_access_funcs {
int (*store_to)(struct iio_buffer *buffer, const void *data);
int (*read_first_n)(struct iio_buffer *buffer,
size_t n,
char __user *buf);
int (*read)(struct iio_buffer *buffer, size_t n, char __user *buf);
size_t (*data_available)(struct iio_buffer *buffer);
int (*request_update)(struct iio_buffer *buffer);

View file

@ -103,9 +103,6 @@
* @r2_user_settings: User defined settings for ADF4350/1 REGISTER_2.
* @r3_user_settings: User defined settings for ADF4350/1 REGISTER_3.
* @r4_user_settings: User defined settings for ADF4350/1 REGISTER_4.
* @gpio_lock_detect: Optional, if set with a valid GPIO number,
* pll lock state is tested upon read.
* If not used - set to -1.
*/
struct adf4350_platform_data {
@ -121,7 +118,6 @@ struct adf4350_platform_data {
unsigned r2_user_settings;
unsigned r3_user_settings;
unsigned r4_user_settings;
int gpio_lock_detect;
};
#endif /* IIO_PLL_ADF4350_H_ */

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