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:
Greg Kroah-Hartman 2024-03-02 20:02:18 +01:00
commit e0014ce72e
39 changed files with 3377 additions and 125 deletions

View 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.

View File

@ -22,7 +22,6 @@ properties:
maxItems: 1
label:
$ref: /schemas/types.yaml#/definitions/string
description: Unique name to identify which channel this is.
bipolar:

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

View File

@ -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 = <&reg_vref_1v8>;

View File

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

View File

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

View File

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

View File

@ -27,6 +27,9 @@ properties:
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg

View File

@ -21,6 +21,7 @@ properties:
required:
- compatible
- reg
- vdd-supply
additionalProperties: false

View File

@ -0,0 +1,60 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/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 = <&reg_dldo1>;
dvdd-supply = <&reg_dldo1>;
reset-gpios = <&pio 1 1 GPIO_ACTIVE_LOW>;
};
};

View File

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

View File

@ -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,.*":

View 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

View 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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@ -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)&ltc2983_chip_info_data },
{ "ltc2984", (kernel_ulong_t)&ltc2984_chip_info_data },
{ "ltc2986", (kernel_ulong_t)&ltc2986_chip_info_data },
{ "ltm2985", (kernel_ulong_t)&ltc2986_chip_info_data },
{ "ltm2985", (kernel_ulong_t)&ltm2985_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 = &ltc2983_chip_info_data },
{ .compatible = "adi,ltc2984", .data = &ltc2984_chip_info_data },
{ .compatible = "adi,ltc2986", .data = &ltc2986_chip_info_data },
{ .compatible = "adi,ltm2985", .data = &ltc2986_chip_info_data },
{ .compatible = "adi,ltm2985", .data = &ltm2985_chip_info_data },
{},
};
MODULE_DEVICE_TABLE(of, ltc2983_of_match);

View File

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