IIO: 2nd set of new device support, cleanups and features for 6.9
New device support ================= adi,hmc425a - Add support for LTC6373 Instrumentation Amplifier. microchip,pac1934 - New driver supporting PAC1931, PAC1932, PAC1933 and PAC1934 power monitoring chips with accumulators. voltafield,af8133j - New driver for the AF8133J 3 axis magnetometer. Docs ==== New general documentation of device buffers, and a specific section on the adi,adis16475 IMU Features ======== kionix,kxcjk-1013 - Add support for ACPI ROTM (Microsoft defined ACPI method) to get rotation matrix. ti,tmp117 - Add missing vcc-supply control and binding. Cleanups and minor fixes ======================== Tree-wide - Corrected headers to remove linux/of.h from a bunch of drivers that only had it to get to linux/mod_devicetable.h - dt binding cleanup to drop redundant type from label properties. adi,hmc425a - Fix constraints on GPIO array sizes for different devices. adi,ltc2983 - Use spi_get_device_match_data instead of open coding similar. - Update naming of fw parsing function to reflect that it is not longer dt only. - Set the chip name explicitly to reduce fragility resulting from different entries in the various ID tables. bosch,bmg160 - Add spi-max-frequency property and limit to dt-binding. microchip,mcp320x - Use devm_* to simplify device removal and error handling. nxp,imx93 - Drop a non existent 4th interrupt from bindings. qcom,mp8xxx-xoadc - Drop unused kerneldoc renesas,isl29501 - Actually use the of_match table. rockchip,saradc - Fix channel bitmask - Fix write masks - Replace custom handling of optional reset control with how it should be done. ti,ads1298 - Fix error code to not return a successfully obtained regulator. - Avoid a divide by zero when setting frequency. ti,hdc2010 - Add missing interrupts dt binding property vishay,veml6075 - Make vdd-supply required in the dt-binding. -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAmXg4XsRHGppYzIzQGtl cm5lbC5vcmcACgkQVIU0mcT0FohHeQ/+K0311HpyObnlWdD4157NltaVlbLqg8OM +N7OmVzFOySJKd4nmISpHDXkSnSYCDD6O/0HfzrmcrPaP1MPxgo3L4WcQ9JbJokW 5hwalY3Mx9Ueds1mpAulNai3veREqqF5Ak/sobBoZTZv20YwJCr2n+6HsgolXI7n 40RzoMeW+GZinKatXPrt4/IRj14n4I2B0z/ykotA1kXl11vVbTDu26OZ5yqePRBB P6EnFhgqvMfjsnNytCkp7id8yiDKFPeRDEZjHbDaMai7Iwu5/HdA2OjgKIf4ybLo 7b+C/XjoY9e9Dze/7DCN/yF7kFsqe1CTeb8vbx8S+bcbJq/a4IqUh9f5eMivtoC5 /ml8f+uer9Fji6SASGgqRCEf/GkVnCweKTGTMkQglJ5TDQpjW6HkgTa8ttCiYTy8 Pfk0s3FtIjbYEyl+W5PXmyNhAnJsUUUUFvXBG+ePzEVbamhJvelI8rfNCrUHFe0M P99ordhaYkaQdxHvc63abvU8XldSKJHeevGkYrGntGYOiQoaUZr6kfr3nqRgQPq4 T35T6wy2guPbkmtClEAPQvYNlFOsz3Liqv52tPDHE+WAbSffKr1loOU2hn0tOLfc wXHpKD2YTkFuC6aDCE8JMtzFfCfbFM8AfKVEnoN6LaoCzunQKS7D7l93rxRs6zh/ cFppD34t8do= =WVBs -----END PGP SIGNATURE----- Merge tag 'iio-for-6.9b' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next Jonathan writes: IIO: 2nd set of new device support, cleanups and features for 6.9 New device support ================= adi,hmc425a - Add support for LTC6373 Instrumentation Amplifier. microchip,pac1934 - New driver supporting PAC1931, PAC1932, PAC1933 and PAC1934 power monitoring chips with accumulators. voltafield,af8133j - New driver for the AF8133J 3 axis magnetometer. Docs ==== New general documentation of device buffers, and a specific section on the adi,adis16475 IMU Features ======== kionix,kxcjk-1013 - Add support for ACPI ROTM (Microsoft defined ACPI method) to get rotation matrix. ti,tmp117 - Add missing vcc-supply control and binding. Cleanups and minor fixes ======================== Tree-wide - Corrected headers to remove linux/of.h from a bunch of drivers that only had it to get to linux/mod_devicetable.h - dt binding cleanup to drop redundant type from label properties. adi,hmc425a - Fix constraints on GPIO array sizes for different devices. adi,ltc2983 - Use spi_get_device_match_data instead of open coding similar. - Update naming of fw parsing function to reflect that it is not longer dt only. - Set the chip name explicitly to reduce fragility resulting from different entries in the various ID tables. bosch,bmg160 - Add spi-max-frequency property and limit to dt-binding. microchip,mcp320x - Use devm_* to simplify device removal and error handling. nxp,imx93 - Drop a non existent 4th interrupt from bindings. qcom,mp8xxx-xoadc - Drop unused kerneldoc renesas,isl29501 - Actually use the of_match table. rockchip,saradc - Fix channel bitmask - Fix write masks - Replace custom handling of optional reset control with how it should be done. ti,ads1298 - Fix error code to not return a successfully obtained regulator. - Avoid a divide by zero when setting frequency. ti,hdc2010 - Add missing interrupts dt binding property vishay,veml6075 - Make vdd-supply required in the dt-binding. * tag 'iio-for-6.9b' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (42 commits) dt-bindings: iio: gyroscope: bosch,bmg160: add spi-max-frequency dt-bindings: iio: adc: imx93: drop the 4th interrupt iio: proximity: isl29501: make use of of_device_id table iio: adc: qcom-pm8xxx-xoadc: drop unused kerneldoc struct pm8xxx_chan_info member dt-bindings: iio: adc: drop redundant type from label dt-bindings: iio: ti,tmp117: add optional label property MAINTAINERS: Add an entry for AF8133J driver iio: magnetometer: add a driver for Voltafield AF8133J magnetometer dt-bindings: iio: magnetometer: Add Voltafield AF8133J dt-bindings: vendor-prefix: Add prefix for Voltafield iio: adc: rockchip_saradc: replace custom logic with devm_reset_control_get_optional_exclusive iio: adc: rockchip_saradc: use mask for write_enable bitfield iio: adc: rockchip_saradc: fix bitmask for channels on SARADCv2 dt-bindings: iio: light: vishay,veml6075: make vdd-supply required iio: adc: adding support for PAC193x dt-bindings: iio: adc: adding support for PAC193X iio: temperature: ltc2983: explicitly set the name in chip_info iio: temperature: ltc2983: rename ltc2983_parse_dt() iio: temperature: ltc2983: make use of spi_get_device_match_data() iio: adc: ti-ads1298: prevent divide by zero in ads1298_set_samp_freq() ...
This commit is contained in:
commit
e0014ce72e
9
Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934
Normal file
9
Documentation/ABI/testing/sysfs-bus-iio-adc-pac1934
Normal file
@ -0,0 +1,9 @@
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_shunt_resistorY
|
||||
KernelVersion: 6.7
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
Description:
|
||||
The value of the shunt resistor may be known only at runtime
|
||||
and set by a client application. This attribute allows to
|
||||
set its value in micro-ohms. X is the IIO index of the device.
|
||||
Y is the channel number. The value is used to calculate
|
||||
current, power and accumulated energy.
|
@ -22,7 +22,6 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
label:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: Unique name to identify which channel this is.
|
||||
|
||||
bipolar:
|
||||
|
120
Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
Normal file
120
Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
Normal file
@ -0,0 +1,120 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/adc/microchip,pac1934.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip PAC1934 Power Monitors with Accumulator
|
||||
|
||||
maintainers:
|
||||
- Marius Cristea <marius.cristea@microchip.com>
|
||||
|
||||
description: |
|
||||
This device is part of the Microchip family of Power Monitors with
|
||||
Accumulator.
|
||||
The datasheet for PAC1931, PAC1932, PAC1933 and PAC1934 can be found here:
|
||||
https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/PAC1931-Family-Data-Sheet-DS20005850E.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- microchip,pac1931
|
||||
- microchip,pac1932
|
||||
- microchip,pac1933
|
||||
- microchip,pac1934
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#address-cells":
|
||||
const: 1
|
||||
|
||||
"#size-cells":
|
||||
const: 0
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
slow-io-gpios:
|
||||
description:
|
||||
A GPIO used to trigger a change is sampling rate (lowering the chip power
|
||||
consumption). If configured in SLOW mode, if this pin is forced high,
|
||||
sampling rate is forced to eight samples/second. When it is forced low,
|
||||
the sampling rate is 1024 samples/second unless a different sample rate
|
||||
has been programmed.
|
||||
|
||||
patternProperties:
|
||||
"^channel@[1-4]+$":
|
||||
type: object
|
||||
$ref: adc.yaml
|
||||
description:
|
||||
Represents the external channels which are connected to the ADC.
|
||||
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
minimum: 1
|
||||
maximum: 4
|
||||
|
||||
shunt-resistor-micro-ohms:
|
||||
description:
|
||||
Value in micro Ohms of the shunt resistor connected between
|
||||
the SENSE+ and SENSE- inputs, across which the current is measured.
|
||||
Value is needed to compute the scaling of the measured current.
|
||||
|
||||
required:
|
||||
- reg
|
||||
- shunt-resistor-micro-ohms
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#address-cells"
|
||||
- "#size-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
power-monitor@10 {
|
||||
compatible = "microchip,pac1934";
|
||||
reg = <0x10>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel@1 {
|
||||
reg = <0x1>;
|
||||
shunt-resistor-micro-ohms = <24900000>;
|
||||
label = "CPU";
|
||||
};
|
||||
|
||||
channel@2 {
|
||||
reg = <0x2>;
|
||||
shunt-resistor-micro-ohms = <49900000>;
|
||||
label = "GPU";
|
||||
};
|
||||
|
||||
channel@3 {
|
||||
reg = <0x3>;
|
||||
shunt-resistor-micro-ohms = <75000000>;
|
||||
label = "MEM";
|
||||
bipolar;
|
||||
};
|
||||
|
||||
channel@4 {
|
||||
reg = <0x4>;
|
||||
shunt-resistor-micro-ohms = <100000000>;
|
||||
label = "NET";
|
||||
bipolar;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
@ -31,7 +31,6 @@ properties:
|
||||
- description: normal conversion, include EOC (End of Conversion),
|
||||
ECH (End of Chain), JEOC (End of Injected Conversion) and
|
||||
JECH (End of injected Chain).
|
||||
- description: Self-testing Interrupts.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
@ -70,8 +69,7 @@ examples:
|
||||
reg = <0x44530000 0x10000>;
|
||||
interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
|
||||
<GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk IMX93_CLK_ADC1_GATE>;
|
||||
clock-names = "ipg";
|
||||
vref-supply = <®_vref_1v8>;
|
||||
|
@ -75,7 +75,6 @@ patternProperties:
|
||||
in the PMIC-specific files in include/dt-bindings/iio/.
|
||||
|
||||
label:
|
||||
$ref: /schemas/types.yaml#/definitions/string
|
||||
description: |
|
||||
ADC input of the platform as seen in the schematics.
|
||||
For thermistor inputs connected to generic AMUX or GPIO inputs
|
||||
|
@ -21,6 +21,8 @@ description: |
|
||||
HMC540S 1 dB LSB Silicon MMIC 4-Bit Digital Positive Control Attenuator, 0.1 - 8 GHz
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/hmc540s.pdf
|
||||
|
||||
LTC6373 is a 3-Bit precision instrumentation amplifier with fully differential outputs
|
||||
https://www.analog.com/media/en/technical-documentation/data-sheets/ltc6373.pdf
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -28,16 +30,55 @@ properties:
|
||||
- adi,adrf5740
|
||||
- adi,hmc425a
|
||||
- adi,hmc540s
|
||||
- adi,ltc6373
|
||||
|
||||
vcc-supply: true
|
||||
|
||||
ctrl-gpios:
|
||||
description:
|
||||
Must contain an array of 6 GPIO specifiers, referring to the GPIO pins
|
||||
connected to the control pins V1-V6.
|
||||
minItems: 6
|
||||
Must contain an array of GPIO specifiers, referring to the GPIO pins
|
||||
connected to the control pins.
|
||||
ADRF5740 - 4 GPIO connected to D2-D5
|
||||
HMC540S - 4 GPIO connected to V1-V4
|
||||
HMC425A - 6 GPIO connected to V1-V6
|
||||
LTC6373 - 3 GPIO connected to A0-A2
|
||||
minItems: 1
|
||||
maxItems: 6
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,hmc425a
|
||||
then:
|
||||
properties:
|
||||
ctrl-gpios:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
anyOf:
|
||||
- const: adi,adrf5740
|
||||
- const: adi,hmc540s
|
||||
then:
|
||||
properties:
|
||||
ctrl-gpios:
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: adi,ltc6373
|
||||
then:
|
||||
properties:
|
||||
ctrl-gpios:
|
||||
minItems: 3
|
||||
maxItems: 3
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- ctrl-gpios
|
||||
|
@ -22,6 +22,9 @@ properties:
|
||||
vdd-supply: true
|
||||
vddio-supply: true
|
||||
|
||||
spi-max-frequency:
|
||||
maximum: 10000000
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
@ -33,7 +36,10 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
allOf:
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
@ -27,6 +27,9 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -21,6 +21,7 @@ properties:
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/iio/magnetometer/voltafield,af8133j.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Voltafield AF8133J magnetometer sensor
|
||||
|
||||
maintainers:
|
||||
- Ondřej Jirman <megi@xff.cz>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: voltafield,af8133j
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
A signal for active low reset input of the sensor. (optional; if not
|
||||
used, software reset over I2C will be used instead)
|
||||
|
||||
avdd-supply:
|
||||
description:
|
||||
A regulator that provides AVDD power (Working power, usually 3.3V) to
|
||||
the sensor.
|
||||
|
||||
dvdd-supply:
|
||||
description:
|
||||
A regulator that provides DVDD power (Digital IO power, 1.8V - AVDD)
|
||||
to the sensor.
|
||||
|
||||
mount-matrix:
|
||||
description: An optional 3x3 mounting rotation matrix.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- avdd-supply
|
||||
- dvdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
magnetometer@1c {
|
||||
compatible = "voltafield,af8133j";
|
||||
reg = <0x1c>;
|
||||
avdd-supply = <®_dldo1>;
|
||||
dvdd-supply = <®_dldo1>;
|
||||
reset-gpios = <&pio 1 1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
@ -24,9 +24,16 @@ properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
vcc-supply:
|
||||
description: provide VCC power to the sensor.
|
||||
|
||||
label:
|
||||
description: Unique name to identify which device this is.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- vcc-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -39,5 +46,6 @@ examples:
|
||||
tmp117@48 {
|
||||
compatible = "ti,tmp117";
|
||||
reg = <0x48>;
|
||||
vcc-supply = <&pmic_reg_3v3>;
|
||||
};
|
||||
};
|
||||
|
@ -1534,6 +1534,8 @@ patternProperties:
|
||||
description: VoCore Studio
|
||||
"^voipac,.*":
|
||||
description: Voipac Technologies s.r.o.
|
||||
"^voltafield,.*":
|
||||
description: Voltafield Technology Corp.
|
||||
"^vot,.*":
|
||||
description: Vision Optical Technology Co., Ltd.
|
||||
"^vxt,.*":
|
||||
|
407
Documentation/iio/adis16475.rst
Normal file
407
Documentation/iio/adis16475.rst
Normal file
@ -0,0 +1,407 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
================
|
||||
ADIS16475 driver
|
||||
================
|
||||
|
||||
This driver supports Analog Device's IMUs on SPI bus.
|
||||
|
||||
1. Supported devices
|
||||
====================
|
||||
|
||||
* `ADIS16465 <https://www.analog.com/ADIS16465>`_
|
||||
* `ADIS16467 <https://www.analog.com/ADIS16467>`_
|
||||
* `ADIS16470 <https://www.analog.com/ADIS16470>`_
|
||||
* `ADIS16475 <https://www.analog.com/ADIS16475>`_
|
||||
* `ADIS16477 <https://www.analog.com/ADIS16477>`_
|
||||
* `ADIS16500 <https://www.analog.com/ADIS16500>`_
|
||||
* `ADIS16505 <https://www.analog.com/ADIS16505>`_
|
||||
* `ADIS16507 <https://www.analog.com/ADIS16507>`_
|
||||
|
||||
Each supported device is a precision, miniature microelectromechanical system
|
||||
(MEMS) inertial measurement unit (IMU) that includes a triaxial gyroscope and a
|
||||
triaxial accelerometer. Each inertial sensor in the IMU device combines with
|
||||
signal conditioning that optimizes dynamic performance. The factory calibration
|
||||
characterizes each sensor for sensitivity, bias, alignment, linear acceleration
|
||||
(gyroscope bias), and point of percussion (accelerometer location). As a result,
|
||||
each sensor has dynamic compensation formulas that provide accurate sensor
|
||||
measurements over a broad set of conditions.
|
||||
|
||||
2. Device attributes
|
||||
====================
|
||||
|
||||
Accelerometer, gyroscope measurements are always provided. Furthermore, the
|
||||
driver offers the capability to retrieve the delta angle and the delta velocity
|
||||
measurements computed by the device.
|
||||
|
||||
The delta angle measurements represent a calculation of angular displacement
|
||||
between each sample update, while the delta velocity measurements represent a
|
||||
calculation of linear velocity change between each sample update.
|
||||
|
||||
Finally, temperature data are provided which show a coarse measurement of
|
||||
the temperature inside of the IMU device. This data is most useful for
|
||||
monitoring relative changes in the thermal environment.
|
||||
|
||||
The signal chain of each inertial sensor (accelerometers and gyroscopes)
|
||||
includes the application of unique correction formulas, which are derived from
|
||||
extensive characterization of bias, sensitivity, alignment, response to linear
|
||||
acceleration (gyroscopes), and point of percussion (accelerometer location)
|
||||
over a temperature range of −40°C to +85°C, for each ADIS device. These
|
||||
correction formulas are not accessible, but users do have the opportunity to
|
||||
adjust the bias for each sensor individually through the calibbias attribute.
|
||||
|
||||
Each IIO device, has a device folder under ``/sys/bus/iio/devices/iio:deviceX``,
|
||||
where X is the IIO index of the device. Under these folders reside a set of
|
||||
device files, depending on the characteristics and features of the hardware
|
||||
device in questions. These files are consistently generalized and documented in
|
||||
the IIO ABI documentation.
|
||||
|
||||
The following tables show the adis16475 related device files, found in the
|
||||
specific device folder path ``/sys/bus/iio/devices/iio:deviceX``.
|
||||
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| 3-Axis Accelerometer related device files | Description |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_scale | Scale for the accelerometer channels. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_calibbias | Calibration offset for the X-axis accelerometer channel. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_calibbias_x | x-axis acceleration offset correction |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_x_raw | Raw X-axis accelerometer channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_calibbias_y | y-axis acceleration offset correction |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_y_raw | Raw Y-axis accelerometer channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_z_calibbias | Calibration offset for the Z-axis accelerometer channel. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_accel_z_raw | Raw Z-axis accelerometer channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_deltavelocity_scale | Scale for delta velocity channels. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_deltavelocity_x_raw | Raw X-axis delta velocity channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_deltavelocity_y_raw | Raw Y-axis delta velocity channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
| in_deltavelocity_z_raw | Raw Z-axis delta velocity channel value. |
|
||||
+-------------------------------------------+----------------------------------------------------------+
|
||||
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| 3-Axis Gyroscope related device files | Description |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_scale | Scale for the gyroscope channels. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_x_calibbias | Calibration offset for the X-axis gyroscope channel. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_calibbias_x | x-axis gyroscope offset correction |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_x_raw | Raw X-axis gyroscope channel value. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_calibbias_y | y-axis gyroscope offset correction |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_y_raw | Raw Y-axis gyroscope channel value. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_z_calibbias | Calibration offset for the Z-axis gyroscope channel. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_anglvel_z_raw | Raw Z-axis gyroscope channel value. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_deltaangl_scale | Scale for delta angle channels. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_deltaangl_x_raw | Raw X-axis delta angle channel value. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_deltaangl_y_raw | Raw Y-axis delta angle channel value. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
| in_deltaangl_z_raw | Raw Z-axis delta angle channel value. |
|
||||
+---------------------------------------+------------------------------------------------------+
|
||||
|
||||
+----------------------------------+-------------------------------------------+
|
||||
| Temperature sensor related files | Description |
|
||||
+----------------------------------+-------------------------------------------+
|
||||
| in_temp0_raw | Raw temperature channel value. |
|
||||
+----------------------------------+-------------------------------------------+
|
||||
| in_temp0_scale | Scale for the temperature sensor channel. |
|
||||
+----------------------------------+-------------------------------------------+
|
||||
|
||||
+-------------------------------+---------------------------------------------------------+
|
||||
| Miscellaneous device files | Description |
|
||||
+-------------------------------+---------------------------------------------------------+
|
||||
| name | Name of the IIO device. |
|
||||
+-------------------------------+---------------------------------------------------------+
|
||||
| sampling_frequency | Currently selected sample rate. |
|
||||
+-------------------------------+---------------------------------------------------------+
|
||||
| filter_low_pass_3db_frequency | Bandwidth for the accelerometer and gyroscope channels. |
|
||||
+-------------------------------+---------------------------------------------------------+
|
||||
|
||||
The following table shows the adis16475 related device debug files, found in the
|
||||
specific device debug folder path ``/sys/kernel/debug/iio/iio:deviceX``.
|
||||
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
| Debugfs device files | Description |
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
| serial_number | The serial number of the chip in hexadecimal format. |
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
| product_id | Chip specific product id (e.g. 16475, 16500, 16505, etc.). |
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
| flash_count | The number of flash writes performed on the device. |
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
| firmware_revision | String containing the firmware revision in the following format ##.##. |
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
| firmware_date | String containing the firmware date in the following format mm-dd-yyyy. |
|
||||
+----------------------+-------------------------------------------------------------------------+
|
||||
|
||||
Channels processed values
|
||||
-------------------------
|
||||
|
||||
A channel value can be read from its _raw attribute. The value returned is the
|
||||
raw value as reported by the devices. To get the processed value of the channel,
|
||||
apply the following formula:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
processed value = (_raw + _offset) * _scale
|
||||
|
||||
Where _offset and _scale are device attributes. If no _offset attribute is
|
||||
present, simply assume its value is 0.
|
||||
|
||||
The adis16475 driver offers data for 5 types of channels, the table below shows
|
||||
the measurement units for the processed value, which are defined by the IIO
|
||||
framework:
|
||||
|
||||
+-------------------------------------+---------------------------+
|
||||
| Channel type | Measurement unit |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Acceleration on X, Y, and Z axis | Meters per Second squared |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Angular velocity on X, Y and Z axis | Radians per second |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Delta velocity on X. Y, and Z axis | Meters per Second |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Delta angle on X, Y, and Z axis | Radians |
|
||||
+-------------------------------------+---------------------------+
|
||||
| Temperature | Millidegrees Celsius |
|
||||
+-------------------------------------+---------------------------+
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
Show device name:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat name
|
||||
adis16505-2
|
||||
|
||||
Show accelerometer channels value:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_raw
|
||||
-275924
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_y_raw
|
||||
-30142222
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_z_raw
|
||||
261265769
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_scale
|
||||
0.000000037
|
||||
|
||||
- X-axis acceleration = in_accel_x_raw * in_accel_scale = −0.010209188 m/s^2
|
||||
- Y-axis acceleration = in_accel_y_raw * in_accel_scale = −1.115262214 m/s^2
|
||||
- Z-axis acceleration = in_accel_z_raw * in_accel_scale = 9.666833453 m/s^2
|
||||
|
||||
Show gyroscope channels value:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_x_raw
|
||||
-3324626
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_raw
|
||||
1336980
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_z_raw
|
||||
-602983
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_scale
|
||||
0.000000006
|
||||
|
||||
- X-axis angular velocity = in_anglvel_x_raw * in_anglvel_scale = −0.019947756 rad/s
|
||||
- Y-axis angular velocity = in_anglvel_y_raw * in_anglvel_scale = 0.00802188 rad/s
|
||||
- Z-axis angular velocity = in_anglvel_z_raw * in_anglvel_scale = −0.003617898 rad/s
|
||||
|
||||
Set calibration offset for accelerometer channels:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
|
||||
0
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 5000 > in_accel_x_calibbias
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_accel_x_calibbias
|
||||
5000
|
||||
|
||||
Set calibration offset for gyroscope channels:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
|
||||
0
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo -5000 > in_anglvel_y_calibbias
|
||||
root:/sys/bus/iio/devices/iio:device0> cat in_anglvel_y_calibbias
|
||||
-5000
|
||||
|
||||
Set sampling frequency:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat sampling_frequency
|
||||
2000.000000
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1000 > sampling_frequency
|
||||
1000.000000
|
||||
|
||||
Set bandwidth for accelerometer and gyroscope:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency
|
||||
720
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 360 > filter_low_pass_3db_frequency
|
||||
root:/sys/bus/iio/devices/iio:device0> cat filter_low_pass_3db_frequency
|
||||
360
|
||||
|
||||
Show serial number:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/kernel/debug/iio/iio:device0> cat serial_number
|
||||
0x04f9
|
||||
|
||||
Show product id:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/kernel/debug/iio/iio:device0> cat product_id
|
||||
16505
|
||||
|
||||
Show flash count:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/kernel/debug/iio/iio:device0> cat flash_count
|
||||
150
|
||||
|
||||
Show firmware revision:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/kernel/debug/iio/iio:device0> cat firmware_revision
|
||||
1.6
|
||||
|
||||
Show firmware date:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/kernel/debug/iio/iio:device0> cat firmware_date
|
||||
06-27-2019
|
||||
|
||||
3. Device buffers
|
||||
=================
|
||||
|
||||
This driver supports IIO buffers.
|
||||
|
||||
All devices support retrieving the raw acceleration, gyroscope and temperature
|
||||
measurements using buffers.
|
||||
|
||||
The following device families also support retrieving the delta velocity, delta
|
||||
angle and temperature measurements using buffers:
|
||||
|
||||
- ADIS16477
|
||||
- ADIS16500
|
||||
- ADIS16505
|
||||
- ADIS16507
|
||||
|
||||
However, when retrieving acceleration or gyroscope data using buffers, delta
|
||||
readings will not be available and vice versa.
|
||||
|
||||
Usage examples
|
||||
--------------
|
||||
|
||||
Set device trigger in current_trigger, if not already set:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo adis16505-2-dev0 > trigger/current_trigger
|
||||
root:/sys/bus/iio/devices/iio:device0> cat trigger/current_trigger
|
||||
adis16505-2-dev0
|
||||
|
||||
Select channels for buffer read:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_x_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_y_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_deltavelocity_z_en
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > scan_elements/in_temp0_en
|
||||
|
||||
Set the number of samples to be stored in the buffer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 10 > buffer/length
|
||||
|
||||
Enable buffer readings:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> echo 1 > buffer/enable
|
||||
|
||||
Obtain buffered data:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
root:/sys/bus/iio/devices/iio:device0> hexdump -C /dev/iio\:device0
|
||||
...
|
||||
00001680 01 1f 00 00 ff ff fe ef 00 00 47 bf 00 03 35 55 |..........G...5U|
|
||||
00001690 01 1f 00 00 ff ff ff d9 00 00 46 f1 00 03 35 35 |..........F...55|
|
||||
000016a0 01 1f 00 00 ff ff fe fc 00 00 46 cb 00 03 35 7b |..........F...5{|
|
||||
000016b0 01 1f 00 00 ff ff fe 41 00 00 47 0d 00 03 35 8b |.......A..G...5.|
|
||||
000016c0 01 1f 00 00 ff ff fe 37 00 00 46 b4 00 03 35 90 |.......7..F...5.|
|
||||
000016d0 01 1d 00 00 ff ff fe 5a 00 00 45 d7 00 03 36 08 |.......Z..E...6.|
|
||||
000016e0 01 1b 00 00 ff ff fe fb 00 00 45 e7 00 03 36 60 |..........E...6`|
|
||||
000016f0 01 1a 00 00 ff ff ff 17 00 00 46 bc 00 03 36 de |..........F...6.|
|
||||
00001700 01 1a 00 00 ff ff fe 59 00 00 46 d7 00 03 37 b8 |.......Y..F...7.|
|
||||
00001710 01 1a 00 00 ff ff fe ae 00 00 46 95 00 03 37 ba |..........F...7.|
|
||||
00001720 01 1a 00 00 ff ff fe c5 00 00 46 63 00 03 37 9f |..........Fc..7.|
|
||||
00001730 01 1a 00 00 ff ff fe 55 00 00 46 89 00 03 37 c1 |.......U..F...7.|
|
||||
00001740 01 1a 00 00 ff ff fe 31 00 00 46 aa 00 03 37 f7 |.......1..F...7.|
|
||||
...
|
||||
|
||||
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
|
||||
data is structured.
|
||||
|
||||
4. IIO Interfacing Tools
|
||||
========================
|
||||
|
||||
Linux Kernel Tools
|
||||
------------------
|
||||
|
||||
Linux Kernel provides some userspace tools that can be used to retrieve data
|
||||
from IIO sysfs:
|
||||
|
||||
* lsiio: example application that provides a list of IIO devices and triggers
|
||||
* iio_event_monitor: example application that reads events from an IIO device
|
||||
and prints them
|
||||
* iio_generic_buffer: example application that reads data from buffer
|
||||
* iio_utils: set of APIs, typically used to access sysfs files.
|
||||
|
||||
LibIIO
|
||||
------
|
||||
|
||||
LibIIO is a C/C++ library that provides generic access to IIO devices. The
|
||||
library abstracts the low-level details of the hardware, and provides a simple
|
||||
yet complete programming interface that can be used for advanced projects.
|
||||
|
||||
For more information about LibIIO, please see:
|
||||
https://github.com/analogdevicesinc/libiio
|
152
Documentation/iio/iio_devbuf.rst
Normal file
152
Documentation/iio/iio_devbuf.rst
Normal file
@ -0,0 +1,152 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=============================
|
||||
Industrial IIO device buffers
|
||||
=============================
|
||||
|
||||
1. Overview
|
||||
===========
|
||||
|
||||
The Industrial I/O core offers a way for continuous data capture based on a
|
||||
trigger source. Multiple data channels can be read at once from
|
||||
``/dev/iio:deviceX`` character device node, thus reducing the CPU load.
|
||||
|
||||
Devices with buffer support feature an additional sub-directory in the
|
||||
``/sys/bus/iio/devices/iio:deviceX/`` directory hierarchy, called bufferY, where
|
||||
Y defaults to 0, for devices with a single buffer.
|
||||
|
||||
2. Buffer attributes
|
||||
====================
|
||||
|
||||
An IIO buffer has an associated attributes directory under
|
||||
``/sys/bus/iio/iio:deviceX/bufferY/``. The attributes are described below.
|
||||
|
||||
``length``
|
||||
----------
|
||||
|
||||
Read / Write attribute which states the total number of data samples (capacity)
|
||||
that can be stored by the buffer.
|
||||
|
||||
``enable``
|
||||
----------
|
||||
|
||||
Read / Write attribute which starts / stops the buffer capture. This file should
|
||||
be written last, after length and selection of scan elements. Writing a non-zero
|
||||
value may result in an error, such as EINVAL, if, for example, an unsupported
|
||||
combination of channels is given.
|
||||
|
||||
``watermark``
|
||||
-------------
|
||||
|
||||
Read / Write positive integer attribute specifying the maximum number of scan
|
||||
elements to wait for.
|
||||
|
||||
Poll will block until the watermark is reached.
|
||||
|
||||
Blocking read will wait until the minimum between the requested read amount or
|
||||
the low watermark is available.
|
||||
|
||||
Non-blocking read will retrieve the available samples from the buffer even if
|
||||
there are less samples than the watermark level. This allows the application to
|
||||
block on poll with a timeout and read the available samples after the timeout
|
||||
expires and thus have a maximum delay guarantee.
|
||||
|
||||
Data available
|
||||
--------------
|
||||
|
||||
Read-only attribute indicating the bytes of data available in the buffer. In the
|
||||
case of an output buffer, this indicates the amount of empty space available to
|
||||
write data to. In the case of an input buffer, this indicates the amount of data
|
||||
available for reading.
|
||||
|
||||
Scan elements
|
||||
-------------
|
||||
|
||||
The meta information associated with a channel data placed in a buffer is called
|
||||
a scan element. The scan elements attributes are presented below.
|
||||
|
||||
**_en**
|
||||
|
||||
Read / Write attribute used for enabling a channel. If and only if its value
|
||||
is non-zero, then a triggered capture will contain data samples for this
|
||||
channel.
|
||||
|
||||
**_index**
|
||||
|
||||
Read-only unsigned integer attribute specifying the position of the channel in
|
||||
the buffer. Note these are not dependent on what is enabled and may not be
|
||||
contiguous. Thus for userspace to establish the full layout these must be used
|
||||
in conjunction with all _en attributes to establish which channels are present,
|
||||
and the relevant _type attributes to establish the data storage format.
|
||||
|
||||
**_type**
|
||||
|
||||
Read-only attribute containing the description of the scan element data storage
|
||||
within the buffer and hence the form in which it is read from userspace. Format
|
||||
is [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift], where:
|
||||
|
||||
- **be** or **le** specifies big or little-endian.
|
||||
- **s** or **u** specifies if signed (2's complement) or unsigned.
|
||||
- **bits** is the number of valid data bits.
|
||||
- **storagebits** is the number of bits (after padding) that it occupies in the
|
||||
buffer.
|
||||
- **repeat** specifies the number of bits/storagebits repetitions. When the
|
||||
repeat element is 0 or 1, then the repeat value is omitted.
|
||||
- **shift** if specified, is the shift that needs to be applied prior to
|
||||
masking out unused bits.
|
||||
|
||||
For example, a driver for a 3-axis accelerometer with 12-bit resolution where
|
||||
data is stored in two 8-bit registers is as follows::
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06)
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07)
|
||||
+---+---+---+---+---+---+---+---+
|
||||
|
||||
will have the following scan element type for each axis:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cat /sys/bus/iio/devices/iio:device0/buffer0/in_accel_y_type
|
||||
le:s12/16>>4
|
||||
|
||||
A userspace application will interpret data samples read from the buffer as
|
||||
two-byte little-endian signed data, that needs a 4 bits right shift before
|
||||
masking out the 12 valid bits of data.
|
||||
|
||||
It is also worth mentioning that the data in the buffer will be naturally
|
||||
aligned, so the userspace application has to handle the buffers accordingly.
|
||||
|
||||
Take for example, a driver with four channels with the following description:
|
||||
- channel0: index: 0, type: be:u16/16>>0
|
||||
- channel1: index: 1, type: be:u32/32>>0
|
||||
- channel2: index: 2, type: be:u32/32>>0
|
||||
- channel3: index: 3, type: be:u64/64>>0
|
||||
|
||||
If all channels are enabled, the data will be aligned in the buffer as follows::
|
||||
|
||||
0-1 2 3 4-7 8-11 12 13 14 15 16-23 -> buffer byte number
|
||||
+-----+---+---+-----+-----+---+---+---+---+-----+
|
||||
|CHN_0|PAD|PAD|CHN_1|CHN_2|PAD|PAD|PAD|PAD|CHN_3| -> buffer content
|
||||
+-----+---+---+-----+-----+---+---+---+---+-----+
|
||||
|
||||
If only channel0 and channel3 are enabled, the data will be aligned in the
|
||||
buffer as follows::
|
||||
|
||||
0-1 2 3 4 5 6 7 8-15 -> buffer byte number
|
||||
+-----+---+---+---+---+---+---+-----+
|
||||
|CHN_0|PAD|PAD|PAD|PAD|PAD|PAD|CHN_3| -> buffer content
|
||||
+-----+---+---+---+---+---+---+-----+
|
||||
|
||||
Typically the buffered data is found in raw format (unscaled with no offset
|
||||
applied), however there are corner cases in which the buffered data may be found
|
||||
in a processed form. Please note that these corner cases are not addressed by
|
||||
this documentation.
|
||||
|
||||
Please see ``Documentation/ABI/testing/sysfs-bus-iio`` for a complete
|
||||
description of the attributes.
|
@ -8,7 +8,14 @@ Industrial I/O
|
||||
:maxdepth: 1
|
||||
|
||||
iio_configfs
|
||||
iio_devbuf
|
||||
|
||||
ep93xx_adc
|
||||
Industrial I/O Kernel Drivers
|
||||
=============================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
adis16475
|
||||
bno055
|
||||
ep93xx_adc
|
||||
|
13
MAINTAINERS
13
MAINTAINERS
@ -579,6 +579,12 @@ F: drivers/iio/accel/adxl372.c
|
||||
F: drivers/iio/accel/adxl372_i2c.c
|
||||
F: drivers/iio/accel/adxl372_spi.c
|
||||
|
||||
AF8133J THREE-AXIS MAGNETOMETER DRIVER
|
||||
M: Ondřej Jirman <megi@xff.cz>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/magnetometer/voltafield,af8133j.yaml
|
||||
F: drivers/iio/magnetometer/af8133j.c
|
||||
|
||||
AF9013 MEDIA DRIVER
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Orphan
|
||||
@ -14426,6 +14432,13 @@ F: Documentation/devicetree/bindings/nvmem/microchip,sama7g5-otpc.yaml
|
||||
F: drivers/nvmem/microchip-otpc.c
|
||||
F: include/dt-bindings/nvmem/microchip,sama7g5-otpc.h
|
||||
|
||||
MICROCHIP PAC1934 POWER/ENERGY MONITOR DRIVER
|
||||
M: Marius Cristea <marius.cristea@microchip.com>
|
||||
L: linux-iio@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/iio/adc/microchip,pac1934.yaml
|
||||
F: drivers/iio/adc/pac1934.c
|
||||
|
||||
MICROCHIP PCI1XXXX GP DRIVER
|
||||
M: Vaibhaav Ram T.L <vaibhaavram.tl@microchip.com>
|
||||
M: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>
|
||||
|
@ -6,8 +6,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include "adxl372.h"
|
||||
|
@ -13,10 +13,10 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -636,6 +636,84 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static bool kxj_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
char *str;
|
||||
union acpi_object *obj, *elements;
|
||||
acpi_status status;
|
||||
int i, j, val[3];
|
||||
bool ret = false;
|
||||
|
||||
if (!acpi_has_method(adev->handle, "ROTM"))
|
||||
return false;
|
||||
|
||||
status = acpi_evaluate_object(adev->handle, "ROTM", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "Failed to get ACPI mount matrix: %d\n", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = buffer.pointer;
|
||||
if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) {
|
||||
dev_err(dev, "Unknown ACPI mount matrix package format\n");
|
||||
goto out_free_buffer;
|
||||
}
|
||||
|
||||
elements = obj->package.elements;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (elements[i].type != ACPI_TYPE_STRING) {
|
||||
dev_err(dev, "Unknown ACPI mount matrix element format\n");
|
||||
goto out_free_buffer;
|
||||
}
|
||||
|
||||
str = elements[i].string.pointer;
|
||||
if (sscanf(str, "%d %d %d", &val[0], &val[1], &val[2]) != 3) {
|
||||
dev_err(dev, "Incorrect ACPI mount matrix string format\n");
|
||||
goto out_free_buffer;
|
||||
}
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
switch (val[j]) {
|
||||
case -1: str = "-1"; break;
|
||||
case 0: str = "0"; break;
|
||||
case 1: str = "1"; break;
|
||||
default:
|
||||
dev_err(dev, "Invalid value in ACPI mount matrix: %d\n", val[j]);
|
||||
goto out_free_buffer;
|
||||
}
|
||||
orientation->rotation[i * 3 + j] = str;
|
||||
}
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
||||
out_free_buffer:
|
||||
kfree(buffer.pointer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool kxj1009_apply_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
if (adev && acpi_dev_hid_uid_match(adev, "KIOX000A", NULL))
|
||||
return kxj_acpi_orientation(dev, orientation);
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
static bool kxj1009_apply_acpi_orientation(struct device *dev,
|
||||
struct iio_mount_matrix *orientation)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
|
||||
{
|
||||
int ret;
|
||||
@ -1466,9 +1544,12 @@ static int kxcjk1013_probe(struct i2c_client *client)
|
||||
} else {
|
||||
data->active_high_intr = true; /* default polarity */
|
||||
|
||||
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!kxj1009_apply_acpi_orientation(&client->dev, &data->orientation)) {
|
||||
ret = iio_read_mount_matrix(&client->dev, &data->orientation);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ret = devm_regulator_bulk_get_enable(&client->dev,
|
||||
|
@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
@ -930,6 +930,17 @@ config NPCM_ADC
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called npcm_adc.
|
||||
|
||||
config PAC1934
|
||||
tristate "Microchip Technology PAC1934 driver"
|
||||
depends on I2C
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's PAC1931,
|
||||
PAC1932, PAC1933, PAC1934 Single/Multi-Channel Power Monitor with
|
||||
Accumulator.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called pac1934.
|
||||
|
||||
config PALMAS_GPADC
|
||||
tristate "TI Palmas General Purpose ADC"
|
||||
depends on MFD_PALMAS
|
||||
|
@ -86,6 +86,7 @@ obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
|
||||
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
|
||||
obj-$(CONFIG_NAU7802) += nau7802.o
|
||||
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
|
||||
obj-$(CONFIG_PAC1934) += pac1934.o
|
||||
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
|
||||
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
|
||||
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
|
||||
|
@ -371,6 +371,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static void mcp320x_regulator_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int mcp320x_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
@ -388,7 +393,6 @@ static int mcp320x_probe(struct spi_device *spi)
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->info = &mcp320x_info;
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
|
||||
device_index = spi_get_device_id(spi)->driver_data;
|
||||
chip_info = &mcp320x_chip_infos[device_index];
|
||||
@ -445,27 +449,13 @@ static int mcp320x_probe(struct spi_device *spi)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, mcp320x_regulator_disable, adc->reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0)
|
||||
goto reg_disable;
|
||||
|
||||
return 0;
|
||||
|
||||
reg_disable:
|
||||
regulator_disable(adc->reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcp320x_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct mcp320x *adc = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
regulator_disable(adc->reg);
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id mcp320x_dt_ids[] = {
|
||||
@ -520,7 +510,6 @@ static struct spi_driver mcp320x_driver = {
|
||||
.of_match_table = mcp320x_dt_ids,
|
||||
},
|
||||
.probe = mcp320x_probe,
|
||||
.remove = mcp320x_remove,
|
||||
.id_table = mcp320x_id,
|
||||
};
|
||||
module_spi_driver(mcp320x_driver);
|
||||
|
1636
drivers/iio/adc/pac1934.c
Normal file
1636
drivers/iio/adc/pac1934.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -372,7 +372,6 @@ static const struct xoadc_channel pm8921_xoadc_channels[] = {
|
||||
* @name: name of this channel
|
||||
* @hwchan: pointer to hardware channel information (muxing & scaling settings)
|
||||
* @calibration: whether to use absolute or ratiometric calibration
|
||||
* @scale_fn_type: scaling function type
|
||||
* @decimation: 0,1,2,3
|
||||
* @amux_ip_rsv: ratiometric scale value if using ratiometric
|
||||
* calibration: 0, 1, 2, 4, 5.
|
||||
|
@ -52,7 +52,7 @@
|
||||
#define SARADC2_START BIT(4)
|
||||
#define SARADC2_SINGLE_MODE BIT(5)
|
||||
|
||||
#define SARADC2_CONV_CHANNELS GENMASK(15, 0)
|
||||
#define SARADC2_CONV_CHANNELS GENMASK(3, 0)
|
||||
|
||||
struct rockchip_saradc;
|
||||
|
||||
@ -102,12 +102,12 @@ static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn)
|
||||
writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC);
|
||||
writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC);
|
||||
val = FIELD_PREP(SARADC2_EN_END_INT, 1);
|
||||
val |= val << 16;
|
||||
val |= SARADC2_EN_END_INT << 16;
|
||||
writel_relaxed(val, info->regs + SARADC2_END_INT_EN);
|
||||
val = FIELD_PREP(SARADC2_START, 1) |
|
||||
FIELD_PREP(SARADC2_SINGLE_MODE, 1) |
|
||||
FIELD_PREP(SARADC2_CONV_CHANNELS, chn);
|
||||
val |= val << 16;
|
||||
val |= (SARADC2_START | SARADC2_SINGLE_MODE | SARADC2_CONV_CHANNELS) << 16;
|
||||
writel(val, info->regs + SARADC2_CONV_CON);
|
||||
}
|
||||
|
||||
@ -450,16 +450,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
|
||||
* The reset should be an optional property, as it should work
|
||||
* with old devicetrees as well
|
||||
*/
|
||||
info->reset = devm_reset_control_get_exclusive(&pdev->dev,
|
||||
"saradc-apb");
|
||||
info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"saradc-apb");
|
||||
if (IS_ERR(info->reset)) {
|
||||
ret = PTR_ERR(info->reset);
|
||||
if (ret != -ENOENT)
|
||||
return dev_err_probe(&pdev->dev, ret,
|
||||
"failed to get saradc-apb\n");
|
||||
|
||||
dev_dbg(&pdev->dev, "no reset control found\n");
|
||||
info->reset = NULL;
|
||||
return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
|
||||
}
|
||||
|
||||
init_completion(&info->completion);
|
||||
|
@ -258,6 +258,8 @@ static int ads1298_set_samp_freq(struct ads1298_private *priv, int val)
|
||||
rate = ADS1298_CLK_RATE_HZ;
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
if (val <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
factor = (rate >> ADS1298_SHIFT_DR_HR) / val;
|
||||
if (factor >= BIT(ADS1298_SHIFT_DR_LP))
|
||||
@ -657,7 +659,7 @@ static int ads1298_probe(struct spi_device *spi)
|
||||
priv->reg_vref = devm_regulator_get_optional(dev, "vref");
|
||||
if (IS_ERR(priv->reg_vref)) {
|
||||
if (PTR_ERR(priv->reg_vref) != -ENODEV)
|
||||
return dev_err_probe(dev, PTR_ERR(priv->reg_avdd),
|
||||
return dev_err_probe(dev, PTR_ERR(priv->reg_vref),
|
||||
"Failed to get vref regulator\n");
|
||||
|
||||
priv->reg_vref = NULL;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
|
@ -2,9 +2,10 @@
|
||||
/*
|
||||
* HMC425A and similar Gain Amplifiers
|
||||
*
|
||||
* Copyright 2020 Analog Devices Inc.
|
||||
* Copyright 2020, 2024 Analog Devices Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
@ -12,6 +13,7 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -20,10 +22,24 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/*
|
||||
* The LTC6373 amplifier supports configuring gain using GPIO's with the following
|
||||
* values (OUTPUT_V / INPUT_V): 0(shutdown), 0.25, 0.5, 1, 2, 4, 8, 16
|
||||
*
|
||||
* Except for the shutdown value, all can be converted to dB using 20 * log10(x)
|
||||
* From here, it is observed that all values are multiples of the '2' gain setting,
|
||||
* with the correspondent of 6.020dB.
|
||||
*/
|
||||
#define LTC6373_CONVERSION_CONSTANT 6020
|
||||
#define LTC6373_MIN_GAIN_CODE 0x6
|
||||
#define LTC6373_CONVERSION_MASK GENMASK(2, 0)
|
||||
#define LTC6373_SHUTDOWN GENMASK(2, 0)
|
||||
|
||||
enum hmc425a_type {
|
||||
ID_HMC425A,
|
||||
ID_HMC540S,
|
||||
ID_ADRF5740
|
||||
ID_ADRF5740,
|
||||
ID_LTC6373,
|
||||
};
|
||||
|
||||
struct hmc425a_chip_info {
|
||||
@ -34,16 +50,110 @@ struct hmc425a_chip_info {
|
||||
int gain_min;
|
||||
int gain_max;
|
||||
int default_gain;
|
||||
int powerdown_val;
|
||||
bool has_powerdown;
|
||||
|
||||
int (*gain_dB_to_code)(int gain, int *code);
|
||||
int (*code_to_gain_dB)(int code, int *val, int *val2);
|
||||
};
|
||||
|
||||
struct hmc425a_state {
|
||||
struct mutex lock; /* protect sensor state */
|
||||
struct hmc425a_chip_info *chip_info;
|
||||
const struct hmc425a_chip_info *chip_info;
|
||||
struct gpio_descs *gpios;
|
||||
enum hmc425a_type type;
|
||||
u32 gain;
|
||||
bool powerdown;
|
||||
};
|
||||
|
||||
static int gain_dB_to_code(struct hmc425a_state *st, int val, int val2, int *code)
|
||||
{
|
||||
const struct hmc425a_chip_info *inf = st->chip_info;
|
||||
int gain;
|
||||
|
||||
if (val < 0)
|
||||
gain = (val * 1000) - (val2 / 1000);
|
||||
else
|
||||
gain = (val * 1000) + (val2 / 1000);
|
||||
|
||||
if (gain > inf->gain_max || gain < inf->gain_min)
|
||||
return -EINVAL;
|
||||
if (st->powerdown)
|
||||
return -EPERM;
|
||||
|
||||
return st->chip_info->gain_dB_to_code(gain, code);
|
||||
}
|
||||
|
||||
static int hmc425a_gain_dB_to_code(int gain, int *code)
|
||||
{
|
||||
*code = ~((abs(gain) / 500) & 0x3F);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hmc540s_gain_dB_to_code(int gain, int *code)
|
||||
{
|
||||
*code = ~((abs(gain) / 1000) & 0xF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adrf5740_gain_dB_to_code(int gain, int *code)
|
||||
{
|
||||
int temp = (abs(gain) / 2000) & 0xF;
|
||||
|
||||
/* Bit [0-3]: 2dB 4dB 8dB 8dB */
|
||||
*code = temp & BIT(3) ? temp | BIT(2) : temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc6373_gain_dB_to_code(int gain, int *code)
|
||||
{
|
||||
*code = ~(DIV_ROUND_CLOSEST(gain, LTC6373_CONVERSION_CONSTANT) + 3)
|
||||
& LTC6373_CONVERSION_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int code_to_gain_dB(struct hmc425a_state *st, int *val, int *val2)
|
||||
{
|
||||
if (st->powerdown)
|
||||
return -EPERM;
|
||||
return st->chip_info->code_to_gain_dB(st->gain, val, val2);
|
||||
}
|
||||
|
||||
static int hmc425a_code_to_gain_dB(int code, int *val, int *val2)
|
||||
{
|
||||
*val = (~code * -500) / 1000;
|
||||
*val2 = ((~code * -500) % 1000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hmc540s_code_to_gain_dB(int code, int *val, int *val2)
|
||||
{
|
||||
*val = (~code * -1000) / 1000;
|
||||
*val2 = ((~code * -1000) % 1000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adrf5740_code_to_gain_dB(int code, int *val, int *val2)
|
||||
{
|
||||
/*
|
||||
* Bit [0-3]: 2dB 4dB 8dB 8dB
|
||||
* When BIT(3) is set, unset BIT(2) and use 3 as double the place value
|
||||
*/
|
||||
code = code & BIT(3) ? code & ~BIT(2) : code;
|
||||
*val = (code * -2000) / 1000;
|
||||
*val2 = ((code * -2000) % 1000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ltc6373_code_to_gain_dB(int code, int *val, int *val2)
|
||||
{
|
||||
int gain = ((~code & LTC6373_CONVERSION_MASK) - 3) *
|
||||
LTC6373_CONVERSION_CONSTANT;
|
||||
|
||||
*val = gain / 1000;
|
||||
*val2 = (gain % 1000) * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hmc425a_write(struct iio_dev *indio_dev, u32 value)
|
||||
{
|
||||
struct hmc425a_state *st = iio_priv(indio_dev);
|
||||
@ -61,30 +171,14 @@ static int hmc425a_read_raw(struct iio_dev *indio_dev,
|
||||
int *val2, long m)
|
||||
{
|
||||
struct hmc425a_state *st = iio_priv(indio_dev);
|
||||
int code, gain = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
switch (m) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
code = st->gain;
|
||||
|
||||
switch (st->type) {
|
||||
case ID_HMC425A:
|
||||
gain = ~code * -500;
|
||||
ret = code_to_gain_dB(st, val, val2);
|
||||
if (ret)
|
||||
break;
|
||||
case ID_HMC540S:
|
||||
gain = ~code * -1000;
|
||||
break;
|
||||
case ID_ADRF5740:
|
||||
code = code & BIT(3) ? code & ~BIT(2) : code;
|
||||
gain = code * -2000;
|
||||
break;
|
||||
}
|
||||
|
||||
*val = gain / 1000;
|
||||
*val2 = (gain % 1000) * 1000;
|
||||
|
||||
ret = IIO_VAL_INT_PLUS_MICRO_DB;
|
||||
break;
|
||||
default:
|
||||
@ -100,34 +194,14 @@ static int hmc425a_write_raw(struct iio_dev *indio_dev,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct hmc425a_state *st = iio_priv(indio_dev);
|
||||
struct hmc425a_chip_info *inf = st->chip_info;
|
||||
int code = 0, gain;
|
||||
int ret;
|
||||
|
||||
if (val < 0)
|
||||
gain = (val * 1000) - (val2 / 1000);
|
||||
else
|
||||
gain = (val * 1000) + (val2 / 1000);
|
||||
|
||||
if (gain > inf->gain_max || gain < inf->gain_min)
|
||||
return -EINVAL;
|
||||
|
||||
switch (st->type) {
|
||||
case ID_HMC425A:
|
||||
code = ~((abs(gain) / 500) & 0x3F);
|
||||
break;
|
||||
case ID_HMC540S:
|
||||
code = ~((abs(gain) / 1000) & 0xF);
|
||||
break;
|
||||
case ID_ADRF5740:
|
||||
code = (abs(gain) / 2000) & 0xF;
|
||||
code = code & BIT(3) ? code | BIT(2) : code;
|
||||
break;
|
||||
}
|
||||
int code = 0, ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
ret = gain_dB_to_code(st, val, val2, &code);
|
||||
if (ret)
|
||||
break;
|
||||
st->gain = code;
|
||||
|
||||
ret = hmc425a_write(indio_dev, st->gain);
|
||||
@ -158,6 +232,48 @@ static const struct iio_info hmc425a_info = {
|
||||
.write_raw_get_fmt = &hmc425a_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static ssize_t ltc6373_read_powerdown(struct iio_dev *indio_dev,
|
||||
uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
char *buf)
|
||||
{
|
||||
struct hmc425a_state *st = iio_priv(indio_dev);
|
||||
|
||||
return sysfs_emit(buf, "%d\n", st->powerdown);
|
||||
}
|
||||
|
||||
static ssize_t ltc6373_write_powerdown(struct iio_dev *indio_dev,
|
||||
uintptr_t private,
|
||||
const struct iio_chan_spec *chan,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct hmc425a_state *st = iio_priv(indio_dev);
|
||||
bool powerdown;
|
||||
int code, ret;
|
||||
|
||||
ret = kstrtobool(buf, &powerdown);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&st->lock);
|
||||
st->powerdown = powerdown;
|
||||
code = (powerdown) ? LTC6373_SHUTDOWN : st->gain;
|
||||
hmc425a_write(indio_dev, code);
|
||||
mutex_unlock(&st->lock);
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info ltc6373_ext_info[] = {
|
||||
{
|
||||
.name = "powerdown",
|
||||
.read = ltc6373_read_powerdown,
|
||||
.write = ltc6373_write_powerdown,
|
||||
.shared = IIO_SEPARATE,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
#define HMC425A_CHAN(_channel) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
@ -167,20 +283,25 @@ static const struct iio_info hmc425a_info = {
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
|
||||
}
|
||||
|
||||
#define LTC6373_CHAN(_channel) \
|
||||
{ \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.output = 1, \
|
||||
.indexed = 1, \
|
||||
.channel = _channel, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
|
||||
.ext_info = ltc6373_ext_info, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec hmc425a_channels[] = {
|
||||
HMC425A_CHAN(0),
|
||||
};
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id hmc425a_of_match[] = {
|
||||
{ .compatible = "adi,hmc425a", .data = (void *)ID_HMC425A },
|
||||
{ .compatible = "adi,hmc540s", .data = (void *)ID_HMC540S },
|
||||
{ .compatible = "adi,adrf5740", .data = (void *)ID_ADRF5740 },
|
||||
{},
|
||||
static const struct iio_chan_spec ltc6373_channels[] = {
|
||||
LTC6373_CHAN(0),
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
|
||||
|
||||
static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
|
||||
static const struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
|
||||
[ID_HMC425A] = {
|
||||
.name = "hmc425a",
|
||||
.channels = hmc425a_channels,
|
||||
@ -189,6 +310,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
|
||||
.gain_min = -31500,
|
||||
.gain_max = 0,
|
||||
.default_gain = -0x40, /* set default gain -31.5db*/
|
||||
.gain_dB_to_code = hmc425a_gain_dB_to_code,
|
||||
.code_to_gain_dB = hmc425a_code_to_gain_dB,
|
||||
},
|
||||
[ID_HMC540S] = {
|
||||
.name = "hmc540s",
|
||||
@ -198,6 +321,8 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
|
||||
.gain_min = -15000,
|
||||
.gain_max = 0,
|
||||
.default_gain = -0x10, /* set default gain -15.0db*/
|
||||
.gain_dB_to_code = hmc540s_gain_dB_to_code,
|
||||
.code_to_gain_dB = hmc540s_code_to_gain_dB,
|
||||
},
|
||||
[ID_ADRF5740] = {
|
||||
.name = "adrf5740",
|
||||
@ -207,6 +332,21 @@ static struct hmc425a_chip_info hmc425a_chip_info_tbl[] = {
|
||||
.gain_min = -22000,
|
||||
.gain_max = 0,
|
||||
.default_gain = 0xF, /* set default gain -22.0db*/
|
||||
.gain_dB_to_code = adrf5740_gain_dB_to_code,
|
||||
.code_to_gain_dB = adrf5740_code_to_gain_dB,
|
||||
},
|
||||
[ID_LTC6373] = {
|
||||
.name = "ltc6373",
|
||||
.channels = ltc6373_channels,
|
||||
.num_channels = ARRAY_SIZE(ltc6373_channels),
|
||||
.num_gpios = 3,
|
||||
.gain_min = -12041, /* gain setting x0.25*/
|
||||
.gain_max = 24082, /* gain setting x16 */
|
||||
.default_gain = LTC6373_MIN_GAIN_CODE,
|
||||
.powerdown_val = LTC6373_SHUTDOWN,
|
||||
.has_powerdown = true,
|
||||
.gain_dB_to_code = ltc6373_gain_dB_to_code,
|
||||
.code_to_gain_dB = ltc6373_code_to_gain_dB,
|
||||
},
|
||||
};
|
||||
|
||||
@ -221,9 +361,8 @@ static int hmc425a_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
st->type = (uintptr_t)device_get_match_data(&pdev->dev);
|
||||
|
||||
st->chip_info = &hmc425a_chip_info_tbl[st->type];
|
||||
st->chip_info = device_get_match_data(&pdev->dev);
|
||||
indio_dev->num_channels = st->chip_info->num_channels;
|
||||
indio_dev->channels = st->chip_info->channels;
|
||||
indio_dev->name = st->chip_info->name;
|
||||
@ -249,12 +388,31 @@ static int hmc425a_probe(struct platform_device *pdev)
|
||||
indio_dev->info = &hmc425a_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
/* Set default gain */
|
||||
hmc425a_write(indio_dev, st->gain);
|
||||
if (st->chip_info->has_powerdown) {
|
||||
st->powerdown = true;
|
||||
hmc425a_write(indio_dev, st->chip_info->powerdown_val);
|
||||
} else {
|
||||
/* Set default gain */
|
||||
hmc425a_write(indio_dev, st->gain);
|
||||
}
|
||||
|
||||
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id hmc425a_of_match[] = {
|
||||
{ .compatible = "adi,hmc425a",
|
||||
.data = &hmc425a_chip_info_tbl[ID_HMC425A]},
|
||||
{ .compatible = "adi,hmc540s",
|
||||
.data = &hmc425a_chip_info_tbl[ID_HMC540S]},
|
||||
{ .compatible = "adi,adrf5740",
|
||||
.data = &hmc425a_chip_info_tbl[ID_ADRF5740]},
|
||||
{ .compatible = "adi,ltc6373",
|
||||
.data = &hmc425a_chip_info_tbl[ID_LTC6373]},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hmc425a_of_match);
|
||||
|
||||
static struct platform_driver hmc425a_driver = {
|
||||
.driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
|
@ -6,6 +6,18 @@
|
||||
|
||||
menu "Magnetometer sensors"
|
||||
|
||||
config AF8133J
|
||||
tristate "Voltafield AF8133J 3-Axis Magnetometer"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to build support for Voltafield AF8133J I2C-based
|
||||
3-axis magnetometer chip.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called af8133j.
|
||||
|
||||
config AK8974
|
||||
tristate "Asahi Kasei AK8974 3-Axis Magnetometer"
|
||||
depends on I2C
|
||||
|
@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
# When adding new entries keep the list in alphabetical order
|
||||
obj-$(CONFIG_AF8133J) += af8133j.o
|
||||
obj-$(CONFIG_AK8974) += ak8974.o
|
||||
obj-$(CONFIG_AK8975) += ak8975.o
|
||||
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o
|
||||
|
528
drivers/iio/magnetometer/af8133j.c
Normal file
528
drivers/iio/magnetometer/af8133j.c
Normal file
@ -0,0 +1,528 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* af8133j.c - Voltafield AF8133J magnetometer driver
|
||||
*
|
||||
* Copyright 2021 Icenowy Zheng <icenowy@aosc.io>
|
||||
* Copyright 2024 Ondřej Jirman <megi@xff.cz>
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define AF8133J_REG_OUT 0x03
|
||||
#define AF8133J_REG_PCODE 0x00
|
||||
#define AF8133J_REG_PCODE_VAL 0x5e
|
||||
#define AF8133J_REG_STATUS 0x02
|
||||
#define AF8133J_REG_STATUS_ACQ BIT(0)
|
||||
#define AF8133J_REG_STATE 0x0a
|
||||
#define AF8133J_REG_STATE_STBY 0x00
|
||||
#define AF8133J_REG_STATE_WORK 0x01
|
||||
#define AF8133J_REG_RANGE 0x0b
|
||||
#define AF8133J_REG_RANGE_22G 0x12
|
||||
#define AF8133J_REG_RANGE_12G 0x34
|
||||
#define AF8133J_REG_SWR 0x11
|
||||
#define AF8133J_REG_SWR_PERFORM 0x81
|
||||
|
||||
static const char * const af8133j_supply_names[] = {
|
||||
"avdd",
|
||||
"dvdd",
|
||||
};
|
||||
|
||||
struct af8133j_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
/*
|
||||
* Protect device internal state between starting a measurement
|
||||
* and reading the result.
|
||||
*/
|
||||
struct mutex mutex;
|
||||
struct iio_mount_matrix orientation;
|
||||
|
||||
struct gpio_desc *reset_gpiod;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(af8133j_supply_names)];
|
||||
|
||||
u8 range;
|
||||
};
|
||||
|
||||
enum af8133j_axis {
|
||||
AXIS_X = 0,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
};
|
||||
|
||||
static struct iio_mount_matrix *
|
||||
af8133j_get_mount_matrix(struct iio_dev *indio_dev,
|
||||
const struct iio_chan_spec *chan)
|
||||
{
|
||||
struct af8133j_data *data = iio_priv(indio_dev);
|
||||
|
||||
return &data->orientation;
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec_ext_info af8133j_ext_info[] = {
|
||||
IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, af8133j_get_mount_matrix),
|
||||
{ }
|
||||
};
|
||||
|
||||
#define AF8133J_CHANNEL(_si, _axis) { \
|
||||
.type = IIO_MAGN, \
|
||||
.modified = 1, \
|
||||
.channel2 = IIO_MOD_ ## _axis, \
|
||||
.address = AXIS_ ## _axis, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.ext_info = af8133j_ext_info, \
|
||||
.scan_index = _si, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 16, \
|
||||
.storagebits = 16, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec af8133j_channels[] = {
|
||||
AF8133J_CHANNEL(0, X),
|
||||
AF8133J_CHANNEL(1, Y),
|
||||
AF8133J_CHANNEL(2, Z),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(3),
|
||||
};
|
||||
|
||||
static int af8133j_product_check(struct af8133j_data *data)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(data->regmap, AF8133J_REG_PCODE, &val);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error reading product code (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (val != AF8133J_REG_PCODE_VAL) {
|
||||
dev_warn(dev, "Invalid product code (0x%02x)\n", val);
|
||||
return 0; /* Allow unknown ID so fallback compatibles work */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af8133j_reset(struct af8133j_data *data)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
int ret;
|
||||
|
||||
if (data->reset_gpiod) {
|
||||
/* If we have GPIO reset line, use it */
|
||||
gpiod_set_value_cansleep(data->reset_gpiod, 1);
|
||||
udelay(10);
|
||||
gpiod_set_value_cansleep(data->reset_gpiod, 0);
|
||||
} else {
|
||||
/* Otherwise use software reset */
|
||||
ret = regmap_write(data->regmap, AF8133J_REG_SWR,
|
||||
AF8133J_REG_SWR_PERFORM);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to reset the chip\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for reset to finish */
|
||||
usleep_range(1000, 1100);
|
||||
|
||||
/* Restore range setting */
|
||||
if (data->range == AF8133J_REG_RANGE_22G) {
|
||||
ret = regmap_write(data->regmap, AF8133J_REG_RANGE, data->range);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void af8133j_power_down(struct af8133j_data *data)
|
||||
{
|
||||
gpiod_set_value_cansleep(data->reset_gpiod, 1);
|
||||
regulator_bulk_disable(ARRAY_SIZE(data->supplies), data->supplies);
|
||||
}
|
||||
|
||||
static int af8133j_power_up(struct af8133j_data *data)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies), data->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not enable regulators\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(data->reset_gpiod, 0);
|
||||
|
||||
/* Wait for power on reset */
|
||||
usleep_range(15000, 16000);
|
||||
|
||||
ret = af8133j_reset(data);
|
||||
if (ret) {
|
||||
af8133j_power_down(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af8133j_take_measurement(struct af8133j_data *data)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(data->regmap,
|
||||
AF8133J_REG_STATE, AF8133J_REG_STATE_WORK);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* The datasheet says "Mesaure Time <1.5ms" */
|
||||
ret = regmap_read_poll_timeout(data->regmap, AF8133J_REG_STATUS, val,
|
||||
val & AF8133J_REG_STATUS_ACQ,
|
||||
500, 1500);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(data->regmap,
|
||||
AF8133J_REG_STATE, AF8133J_REG_STATE_STBY);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af8133j_read_measurement(struct af8133j_data *data, __le16 buf[3])
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_resume_and_get(dev);
|
||||
if (ret) {
|
||||
/*
|
||||
* Ignore EACCES because that happens when RPM is disabled
|
||||
* during system sleep, while userspace leave eg. hrtimer
|
||||
* trigger attached and IIO core keeps trying to do measurements.
|
||||
*/
|
||||
if (ret != -EACCES)
|
||||
dev_err(dev, "Failed to power on (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
scoped_guard(mutex, &data->mutex) {
|
||||
ret = af8133j_take_measurement(data);
|
||||
if (ret)
|
||||
goto out_rpm_put;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, AF8133J_REG_OUT,
|
||||
buf, sizeof(__le16) * 3);
|
||||
}
|
||||
|
||||
out_rpm_put:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const int af8133j_scales[][2] = {
|
||||
[0] = { 0, 366210 }, /* 12 gauss */
|
||||
[1] = { 0, 671386 }, /* 22 gauss */
|
||||
};
|
||||
|
||||
static int af8133j_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct af8133j_data *data = iio_priv(indio_dev);
|
||||
__le16 buf[3];
|
||||
int ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = af8133j_read_measurement(data, buf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*val = sign_extend32(le16_to_cpu(buf[chan->address]),
|
||||
chan->scan_type.realbits - 1);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
*val = 0;
|
||||
|
||||
if (data->range == AF8133J_REG_RANGE_12G)
|
||||
*val2 = af8133j_scales[0][1];
|
||||
else
|
||||
*val2 = af8133j_scales[1][1];
|
||||
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int af8133j_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:
|
||||
*vals = (const int *)af8133j_scales;
|
||||
*length = ARRAY_SIZE(af8133j_scales) * 2;
|
||||
*type = IIO_VAL_INT_PLUS_NANO;
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int af8133j_set_scale(struct af8133j_data *data,
|
||||
unsigned int val, unsigned int val2)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
u8 range;
|
||||
int ret = 0;
|
||||
|
||||
if (af8133j_scales[0][0] == val && af8133j_scales[0][1] == val2)
|
||||
range = AF8133J_REG_RANGE_12G;
|
||||
else if (af8133j_scales[1][0] == val && af8133j_scales[1][1] == val2)
|
||||
range = AF8133J_REG_RANGE_22G;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
/*
|
||||
* When suspended, just store the new range to data->range to be
|
||||
* applied later during power up.
|
||||
*/
|
||||
if (!pm_runtime_status_suspended(dev))
|
||||
scoped_guard(mutex, &data->mutex)
|
||||
ret = regmap_write(data->regmap,
|
||||
AF8133J_REG_RANGE, range);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
data->range = range;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int af8133j_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int val, int val2, long mask)
|
||||
{
|
||||
struct af8133j_data *data = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return af8133j_set_scale(data, val, val2);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int af8133j_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
long mask)
|
||||
{
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
|
||||
static const struct iio_info af8133j_info = {
|
||||
.read_raw = af8133j_read_raw,
|
||||
.read_avail = af8133j_read_avail,
|
||||
.write_raw = af8133j_write_raw,
|
||||
.write_raw_get_fmt = af8133j_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static irqreturn_t af8133j_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct af8133j_data *data = iio_priv(indio_dev);
|
||||
s64 timestamp = iio_get_time_ns(indio_dev);
|
||||
struct {
|
||||
__le16 values[3];
|
||||
s64 timestamp __aligned(8);
|
||||
} sample;
|
||||
int ret;
|
||||
|
||||
memset(&sample, 0, sizeof(sample));
|
||||
|
||||
ret = af8133j_read_measurement(data, sample.values);
|
||||
if (ret)
|
||||
goto out_done;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &sample, timestamp);
|
||||
|
||||
out_done:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct regmap_config af8133j_regmap_config = {
|
||||
.name = "af8133j_regmap",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = AF8133J_REG_SWR,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
};
|
||||
|
||||
static void af8133j_power_down_action(void *ptr)
|
||||
{
|
||||
struct af8133j_data *data = ptr;
|
||||
|
||||
if (!pm_runtime_status_suspended(&data->client->dev))
|
||||
af8133j_power_down(data);
|
||||
}
|
||||
|
||||
static int af8133j_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct af8133j_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
struct regmap *regmap;
|
||||
int ret, i;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &af8133j_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap),
|
||||
"regmap initialization failed\n");
|
||||
|
||||
data = iio_priv(indio_dev);
|
||||
i2c_set_clientdata(client, indio_dev);
|
||||
data->client = client;
|
||||
data->regmap = regmap;
|
||||
data->range = AF8133J_REG_RANGE_12G;
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
data->reset_gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(data->reset_gpiod))
|
||||
return dev_err_probe(dev, PTR_ERR(data->reset_gpiod),
|
||||
"Failed to get reset gpio\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(af8133j_supply_names); i++)
|
||||
data->supplies[i].supply = af8133j_supply_names[i];
|
||||
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
|
||||
data->supplies);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_read_mount_matrix(dev, &data->orientation);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to read mount matrix\n");
|
||||
|
||||
ret = af8133j_power_up(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, af8133j_power_down_action, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = af8133j_product_check(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_get_noresume(dev);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_autosuspend_delay(dev, 500);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
indio_dev->info = &af8133j_info;
|
||||
indio_dev->name = "af8133j";
|
||||
indio_dev->channels = af8133j_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(af8133j_channels);
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
&af8133j_trigger_handler, NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"Failed to setup iio triggered buffer\n");
|
||||
|
||||
ret = devm_iio_device_register(dev, indio_dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to register iio device");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af8133j_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct af8133j_data *data = iio_priv(indio_dev);
|
||||
|
||||
af8133j_power_down(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int af8133j_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct af8133j_data *data = iio_priv(indio_dev);
|
||||
|
||||
return af8133j_power_up(data);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops af8133j_pm_ops = {
|
||||
SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
|
||||
RUNTIME_PM_OPS(af8133j_runtime_suspend, af8133j_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id af8133j_of_match[] = {
|
||||
{ .compatible = "voltafield,af8133j", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, af8133j_of_match);
|
||||
|
||||
static const struct i2c_device_id af8133j_id[] = {
|
||||
{ "af8133j", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, af8133j_id);
|
||||
|
||||
static struct i2c_driver af8133j_driver = {
|
||||
.driver = {
|
||||
.name = "af8133j",
|
||||
.of_match_table = af8133j_of_match,
|
||||
.pm = pm_ptr(&af8133j_pm_ops),
|
||||
},
|
||||
.probe = af8133j_probe,
|
||||
.id_table = af8133j_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(af8133j_driver);
|
||||
|
||||
MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
|
||||
MODULE_AUTHOR("Ondřej Jirman <megi@xff.cz>");
|
||||
MODULE_DESCRIPTION("Voltafield AF8133J magnetic sensor driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -995,17 +995,16 @@ static const struct i2c_device_id isl29501_id[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, isl29501_id);
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static const struct of_device_id isl29501_i2c_matches[] = {
|
||||
{ .compatible = "renesas,isl29501" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, isl29501_i2c_matches);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver isl29501_driver = {
|
||||
.driver = {
|
||||
.name = "isl29501",
|
||||
.of_match_table = isl29501_i2c_matches,
|
||||
},
|
||||
.id_table = isl29501_id,
|
||||
.probe = isl29501_probe,
|
||||
|
@ -207,6 +207,7 @@ enum {
|
||||
container_of(_sensor, struct ltc2983_temp, sensor)
|
||||
|
||||
struct ltc2983_chip_info {
|
||||
const char *name;
|
||||
unsigned int max_channels_nr;
|
||||
bool has_temp;
|
||||
bool has_eeprom;
|
||||
@ -1346,7 +1347,7 @@ static irqreturn_t ltc2983_irq_handler(int irq, void *data)
|
||||
__chan; \
|
||||
})
|
||||
|
||||
static int ltc2983_parse_dt(struct ltc2983_data *st)
|
||||
static int ltc2983_parse_fw(struct ltc2983_data *st)
|
||||
{
|
||||
struct device *dev = &st->spi->dev;
|
||||
struct fwnode_handle *child;
|
||||
@ -1605,7 +1606,6 @@ static int ltc2983_probe(struct spi_device *spi)
|
||||
struct ltc2983_data *st;
|
||||
struct iio_dev *indio_dev;
|
||||
struct gpio_desc *gpio;
|
||||
const char *name = spi_get_device_id(spi)->name;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
@ -1614,9 +1614,7 @@ static int ltc2983_probe(struct spi_device *spi)
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
st->info = device_get_match_data(&spi->dev);
|
||||
if (!st->info)
|
||||
st->info = (void *)spi_get_device_id(spi)->driver_data;
|
||||
st->info = spi_get_device_match_data(spi);
|
||||
if (!st->info)
|
||||
return -ENODEV;
|
||||
|
||||
@ -1632,7 +1630,7 @@ static int ltc2983_probe(struct spi_device *spi)
|
||||
st->eeprom_key = cpu_to_be32(LTC2983_EEPROM_KEY);
|
||||
spi_set_drvdata(spi, st);
|
||||
|
||||
ret = ltc2983_parse_dt(st);
|
||||
ret = ltc2983_parse_fw(st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1657,7 +1655,7 @@ static int ltc2983_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler,
|
||||
IRQF_TRIGGER_RISING, name, st);
|
||||
IRQF_TRIGGER_RISING, st->info->name, st);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to request an irq, %d", ret);
|
||||
return ret;
|
||||
@ -1672,7 +1670,7 @@ static int ltc2983_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->name = name;
|
||||
indio_dev->name = st->info->name;
|
||||
indio_dev->num_channels = st->iio_channels;
|
||||
indio_dev->channels = st->iio_chan;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
@ -1703,15 +1701,25 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend,
|
||||
ltc2983_resume);
|
||||
|
||||
static const struct ltc2983_chip_info ltc2983_chip_info_data = {
|
||||
.name = "ltc2983",
|
||||
.max_channels_nr = 20,
|
||||
};
|
||||
|
||||
static const struct ltc2983_chip_info ltc2984_chip_info_data = {
|
||||
.name = "ltc2984",
|
||||
.max_channels_nr = 20,
|
||||
.has_eeprom = true,
|
||||
};
|
||||
|
||||
static const struct ltc2983_chip_info ltc2986_chip_info_data = {
|
||||
.name = "ltc2986",
|
||||
.max_channels_nr = 10,
|
||||
.has_temp = true,
|
||||
.has_eeprom = true,
|
||||
};
|
||||
|
||||
static const struct ltc2983_chip_info ltm2985_chip_info_data = {
|
||||
.name = "ltm2985",
|
||||
.max_channels_nr = 10,
|
||||
.has_temp = true,
|
||||
.has_eeprom = true,
|
||||
@ -1721,7 +1729,7 @@ static const struct spi_device_id ltc2983_id_table[] = {
|
||||
{ "ltc2983", (kernel_ulong_t)<c2983_chip_info_data },
|
||||
{ "ltc2984", (kernel_ulong_t)<c2984_chip_info_data },
|
||||
{ "ltc2986", (kernel_ulong_t)<c2986_chip_info_data },
|
||||
{ "ltm2985", (kernel_ulong_t)<c2986_chip_info_data },
|
||||
{ "ltm2985", (kernel_ulong_t)<m2985_chip_info_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, ltc2983_id_table);
|
||||
@ -1730,7 +1738,7 @@ static const struct of_device_id ltc2983_of_match[] = {
|
||||
{ .compatible = "adi,ltc2983", .data = <c2983_chip_info_data },
|
||||
{ .compatible = "adi,ltc2984", .data = <c2984_chip_info_data },
|
||||
{ .compatible = "adi,ltc2986", .data = <c2986_chip_info_data },
|
||||
{ .compatible = "adi,ltm2985", .data = <c2986_chip_info_data },
|
||||
{ .compatible = "adi,ltm2985", .data = <m2985_chip_info_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2983_of_match);
|
||||
|
@ -9,6 +9,7 @@
|
||||
* Note: This driver assumes that the sensor has been calibrated beforehand.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
@ -17,6 +18,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
|
||||
@ -148,10 +150,17 @@ static int tmp117_probe(struct i2c_client *client)
|
||||
struct tmp117_data *data;
|
||||
struct iio_dev *indio_dev;
|
||||
int dev_id;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
ret = devm_regulator_get_enable(&client->dev, "vcc");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
fsleep(1500);
|
||||
|
||||
dev_id = i2c_smbus_read_word_swapped(client, TMP117_REG_DEVICE_ID);
|
||||
if (dev_id < 0)
|
||||
return dev_id;
|
||||
|
Loading…
x
Reference in New Issue
Block a user