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:
commit
821f7ce79f
@ -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.
|
||||
|
19
Documentation/ABI/testing/sysfs-bus-iio-dma-buffer
Normal file
19
Documentation/ABI/testing/sysfs-bus-iio-dma-buffer
Normal 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.
|
@ -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>;
|
||||
};
|
||||
};
|
@ -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:
|
||||
|
@ -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>;
|
||||
};
|
||||
};
|
54
Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
Normal file
54
Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
...
|
47
Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml
Normal file
47
Documentation/devicetree/bindings/iio/adc/lltc,ltc2496.yaml
Normal 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 = <<c2496_reg>;
|
||||
spi-max-frequency = <2000000>;
|
||||
};
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
||||
|
||||
...
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
||||
|
@ -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,.*":
|
||||
|
32
MAINTAINERS
32
MAINTAINERS
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
99
drivers/iio/accel/bma400.h
Normal file
99
drivers/iio/accel/bma400.h
Normal 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
|
852
drivers/iio/accel/bma400_core.c
Normal file
852
drivers/iio/accel/bma400_core.c
Normal 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");
|
61
drivers/iio/accel/bma400_i2c.c
Normal file
61
drivers/iio/accel/bma400_i2c.c
Normal 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");
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
298
drivers/iio/adc/ad7091r-base.c
Normal file
298
drivers/iio/adc/ad7091r-base.c
Normal 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");
|
26
drivers/iio/adc/ad7091r-base.h
Normal file
26
drivers/iio/adc/ad7091r-base.h
Normal 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
113
drivers/iio/adc/ad7091r5.c
Normal 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");
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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
108
drivers/iio/adc/ltc2496.c
Normal 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");
|
243
drivers/iio/adc/ltc2497-core.c
Normal file
243
drivers/iio/adc/ltc2497-core.c
Normal 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 = <c2497core_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");
|
@ -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 = <c2497_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
18
drivers/iio/adc/ltc2497.h
Normal 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);
|
@ -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 {
|
||||
|
@ -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] = {
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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");
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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) |
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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 */
|
||||
|
@ -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},
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
375
drivers/iio/pressure/dlhl60d.c
Normal file
375
drivers/iio/pressure/dlhl60d.c
Normal 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");
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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[] = {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
335
drivers/iio/proximity/ping.c
Normal file
335
drivers/iio/proximity/ping.c
Normal 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");
|
@ -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>
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user