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

Note includes a merge from i3c tree to get support needed for stm_lsm6dsx driver
 support for l3c devices.  Done from immutable branch.
 
 A counter subsystem patche in here as well.
 
 Alongside the new device support (which is always good), Chuhong's work
 on using devres managed APIs has cleaned up a number of drivers.
 
 New device support
 * adis16460
   - New driver based on ADIS framework which needed addition of support
     for cs_change_delay. Includes device tree binding.
 * cros_ec
   - Support fo the veyron-minnie which uses an older interface.
 * lsm6dsx
   - Support for LSM6DSTR-C gyro + magnetometer sensor (new IDs mainly)
   - Support for ISM330DHCX acc + gyro sensor (extensive rework needed!)
 * Maxim 5432
   - New driver support MAX5432-MAX5435 family of potentiometers.
 * noa1305
   - New driver for this ON Semiconductor Ambient light sensor.
 
 Features and cleanups
 * tree wide
   - Drop error prints after platform_get_irq as already prints errors
     internally if any occur.
 * docs
   - Document mounting matrix.
   - Fix a missing newline at end of file.
 * ad2s1210
   - Switch to device managed APIs for all of probe and drop explicit remove.
 * ad7192
   - Add of_device_id array to explicity handling DT bindings.
 * ad7606
   - Lots of rework leading to support for software configure modes in ad7616
     parts.
   - Debugfs register access support.
 * am2315
   - Switch to device managed APIs for all of probe and drop explicit remove.
 * apds9960
   - Typo in module description.
 * cm36651
   - Convert to i2c_new_dummy_device.
   - Swithc to device managed APIs for all of probe adn drop explicit remove.
 * cros_ec
   - Calibscale support for accel, gyro and magnetometer.
   - Tidy up some error codes to return the error from the stack rather than
     -EIO.
   - Determine protocol version.
   - Add a sign vector to the core to fix sensor rotation if necessary.
     Cannot just be done with mount matrix as already in use in many devices.
   - Tidy up INFO_SCALE being in both the separate and shared lists.
   - Drop a lot of dplicate code from the cros-ec-accel-legacy driver
     and use the core provided code instead.
   - Make frequency range available to userspace.
 * counter / ftm-quaddec
   - Switch to device managed APIs for all of probe adn drop explicit remove.
 * hdc100x
   - Switch to device managed APIs for all of probe and drop explicit remove.
 * hi8435
   - Use gpiod_set_value_cansleep as we don't care here and there is a
     board out there where it needs to sleep.
   - Switch to device managed APIs for all of probe and drop explict remove.
 * hp03
   - Convert to i2c_new_dummy_device.
 * maxim thermocouple
   - Switch to device managed APIs for all of probe and drop explicit remove.
 * mmc35240
   - Fix typo in constant naming.
 * mpu6050
   - Use devm_add_action_or_reset in place of explicit error handling.
   - Make text in Kconfig more explicit about which parts are supported.
 * mxc4005
   - Switch to device managed APIs for all of probe and drop explicit remove.
 * pms7003
   - Convert device tree bindings to yaml.
   - Add a MAINTAINERS entry
 * sc27xx
   - Introduce a local struct device *dev pointer to avoid lots of deref.
   - Use devm_add_action_or_reset in place of explicit error handling.
 * sca3000
   - Typo fix in naming.
 * si1145
   - Switch to device managed APIs for all of probe and drop explicit remove.
 * st_sensors
   - Lots of rework to enable switch to regmap.
   - Regmap conversion at the end.
   - Tidy up some inconsistencies in buffer setup ops.
   - Tidy up an oddity by dropping get_irq_data_ready function in favour
     of direct access.
   - Stop allocating buffer in buffer enable in favour of just embedding
     a large enough constant size buffer in the iio_priv accessed structure.
 * st_lsm6dsx
   - l3c device support (LSM6DSO and LSM6DSR)
   - tidy up irq return logic which was strangely written.
   - fix up an ABI quirk where this driver used separate scale
     attributes, even though they were always shared by type.
 * stk33xx
   - Device tree bindings include manufacturer ID.
 * stm32-adc
   - Add control for supply to analog switches including DT bindings.
 * stm32 timer
   - Drop the quadrature mode support.  Believed there were no users so
     take this opportunity to drop this unwanted ABI.
 * tsl2772
   - Switch to device mangage APIs for all of probe and drop explicit remove.
   - Use regulator_bulk_* APIs to reduce repitition.
 * veml6070
   - Convert to i2c_new_dummy_device.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAl1RxVQRHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FohP8xAAjbWf431vsHQSt0Lmn4coh0XCBT26R9ys
 ybIga540Mcy1q91H+biBenShLVImCBtXEBJ57YdVjtLgkr1HJAJjvxCXdE79TJet
 Ak39CmTcTGrRyzYin2MOpWJJgCFc4Fg+E/kB8K7KIcperzQ48GDCzL5aJE/PksME
 Ay/rZDno+vPKGLmvxYCuSpmINq1YhVMQu/IPYO5sc6zRdDtEV29TAdZ/x8aaD2oM
 r1E22hm0h2wVLQRpbLUA5XUgoetQGmIYaUgbJPkpvxhuQYIlbLavODP7S0xDqAbT
 VCRzrzeR8eHxA+EeZDE8IWC5xbmFTUBdUHhHfCDETONOi5CjaPC/QnowNOi1IC0H
 k5XgBAO6Zju5QWpu+nHVdjwdJ1RftLVeCPatXorHLWWJv6UP8j/cNNKDAvBTlvhq
 yfG/zW1VMTr/Q2VkokHnr2D8JxcARf/+AcR1BOu+pVszJ/+kgnXVNu3QLMilCTnN
 +fzEfbErL7BfUBh19IqdB40XOojppuavyzAruiOjLGVrFRk3lwFP8FvVDy8MtPbO
 /roYxohwc1M/kK3+Sl+4LfY2mX7orStZ5NNAYcu9yzg/6vv3Oh5Pxw2UsDto4MCC
 ikDffzIGxXnJUzi3uIBthyvTHMX2y/EykikbjMkfsGOtCiFdcPGUl4iirsWkpebj
 zrpff+V1vXM=
 =aez5
 -----END PGP SIGNATURE-----

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

Jonathan writes:

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

Note includes a merge from i3c tree to get support needed for stm_lsm6dsx driver
support for l3c devices.  Done from immutable branch.

A counter subsystem patche in here as well.

Alongside the new device support (which is always good), Chuhong's work
on using devres managed APIs has cleaned up a number of drivers.

New device support
* adis16460
  - New driver based on ADIS framework which needed addition of support
    for cs_change_delay. Includes device tree binding.
* cros_ec
  - Support fo the veyron-minnie which uses an older interface.
* lsm6dsx
  - Support for LSM6DSTR-C gyro + magnetometer sensor (new IDs mainly)
  - Support for ISM330DHCX acc + gyro sensor (extensive rework needed!)
* Maxim 5432
  - New driver support MAX5432-MAX5435 family of potentiometers.
* noa1305
  - New driver for this ON Semiconductor Ambient light sensor.

Features and cleanups
* tree wide
  - Drop error prints after platform_get_irq as already prints errors
    internally if any occur.
* docs
  - Document mounting matrix.
  - Fix a missing newline at end of file.
* ad2s1210
  - Switch to device managed APIs for all of probe and drop explicit remove.
* ad7192
  - Add of_device_id array to explicity handling DT bindings.
* ad7606
  - Lots of rework leading to support for software configure modes in ad7616
    parts.
  - Debugfs register access support.
* am2315
  - Switch to device managed APIs for all of probe and drop explicit remove.
* apds9960
  - Typo in module description.
* cm36651
  - Convert to i2c_new_dummy_device.
  - Swithc to device managed APIs for all of probe adn drop explicit remove.
* cros_ec
  - Calibscale support for accel, gyro and magnetometer.
  - Tidy up some error codes to return the error from the stack rather than
    -EIO.
  - Determine protocol version.
  - Add a sign vector to the core to fix sensor rotation if necessary.
    Cannot just be done with mount matrix as already in use in many devices.
  - Tidy up INFO_SCALE being in both the separate and shared lists.
  - Drop a lot of dplicate code from the cros-ec-accel-legacy driver
    and use the core provided code instead.
  - Make frequency range available to userspace.
* counter / ftm-quaddec
  - Switch to device managed APIs for all of probe adn drop explicit remove.
* hdc100x
  - Switch to device managed APIs for all of probe and drop explicit remove.
* hi8435
  - Use gpiod_set_value_cansleep as we don't care here and there is a
    board out there where it needs to sleep.
  - Switch to device managed APIs for all of probe and drop explict remove.
* hp03
  - Convert to i2c_new_dummy_device.
* maxim thermocouple
  - Switch to device managed APIs for all of probe and drop explicit remove.
* mmc35240
  - Fix typo in constant naming.
* mpu6050
  - Use devm_add_action_or_reset in place of explicit error handling.
  - Make text in Kconfig more explicit about which parts are supported.
* mxc4005
  - Switch to device managed APIs for all of probe and drop explicit remove.
* pms7003
  - Convert device tree bindings to yaml.
  - Add a MAINTAINERS entry
* sc27xx
  - Introduce a local struct device *dev pointer to avoid lots of deref.
  - Use devm_add_action_or_reset in place of explicit error handling.
* sca3000
  - Typo fix in naming.
* si1145
  - Switch to device managed APIs for all of probe and drop explicit remove.
* st_sensors
  - Lots of rework to enable switch to regmap.
  - Regmap conversion at the end.
  - Tidy up some inconsistencies in buffer setup ops.
  - Tidy up an oddity by dropping get_irq_data_ready function in favour
    of direct access.
  - Stop allocating buffer in buffer enable in favour of just embedding
    a large enough constant size buffer in the iio_priv accessed structure.
* st_lsm6dsx
  - l3c device support (LSM6DSO and LSM6DSR)
  - tidy up irq return logic which was strangely written.
  - fix up an ABI quirk where this driver used separate scale
    attributes, even though they were always shared by type.
* stk33xx
  - Device tree bindings include manufacturer ID.
* stm32-adc
  - Add control for supply to analog switches including DT bindings.
* stm32 timer
  - Drop the quadrature mode support.  Believed there were no users so
    take this opportunity to drop this unwanted ABI.
* tsl2772
  - Switch to device mangage APIs for all of probe and drop explicit remove.
  - Use regulator_bulk_* APIs to reduce repitition.
* veml6070
  - Convert to i2c_new_dummy_device.

* tag 'iio-for-5.4a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (84 commits)
  iio: hi8435: Drop hi8435_remove() by using devres for remaining elements
  iio: hi8435: Use gpiod_set_value_cansleep()
  iio:st_sensors: remove buffer allocation at each buffer enable
  iio: imu: inv_mpu6050: be more explicit on supported chips
  iio: light: noa1305: Add support for NOA1305
  dt-bindings: Add binding document for NOA1305
  iio: remove get_irq_data_ready() function pointer and use IRQ number directly
  iio: imu: st_lsm6dsx: make IIO_CHAN_INFO_SCALE shared by type
  iio: tsl2772: Use regulator_bulk_() APIs
  iio: tsl2772: Use devm_iio_device_register
  iio: tsl2772: Use devm_add_action_or_reset for tsl2772_chip_off
  iio: tsl2772: Use devm_add_action_or_reset
  iio: Remove dev_err() usage after platform_get_irq()
  iio: light: si1145: Use device-managed APIs
  iio:pressure: preenable/postenable/predisable fixup for ST press buffer
  iio:magn: preenable/postenable/predisable fixup for ST magn buffer
  iio:gyro: preenable/postenable/predisable fixup for ST gyro buffer
  iio:accel: preenable/postenable/predisable fixup for ST accel buffer
  dt-bindings: iio: imu: st_lsm6dsx: add ism330dhcx device bindings
  iio: imu: st_lsm6dsx: add support to ISM330DHCX
  ...
This commit is contained in:
Greg Kroah-Hartman 2019-08-12 22:52:44 +02:00
commit 6aed51d891
114 changed files with 3482 additions and 1544 deletions

View File

@ -13,4 +13,4 @@ Description:
error on writing
If DFSDM input is SPI Slave:
Reading returns value previously set.
Writing value before starting conversions.
Writing value before starting conversions.

View File

@ -91,29 +91,6 @@ Description:
When counting down the counter start from preset value
and fire event when reach 0.
What: /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available
KernelVersion: 4.12
Contact: benjamin.gaignard@st.com
Description:
Reading returns the list possible quadrature modes.
What: /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode
KernelVersion: 4.12
Contact: benjamin.gaignard@st.com
Description:
Configure the device counter quadrature modes:
channel_A:
Encoder A input servers as the count input and B as
the UP/DOWN direction control input.
channel_B:
Encoder B input serves as the count input and A as
the UP/DOWN direction control input.
quadrature:
Encoder A and B inputs are mixed to get direction
and count with a scale of 0.25.
What: /sys/bus/iio/devices/iio:deviceX/in_count_enable_mode_available
KernelVersion: 4.12
Contact: benjamin.gaignard@st.com

View File

@ -47,6 +47,12 @@ Required properties:
Optional properties:
- A pinctrl state named "default" for each ADC channel may be defined to set
inX ADC pins in mode of operation for analog input on external pin.
- booster-supply: Phandle to the embedded booster regulator that can be used
to supply ADC analog input switches on stm32h7 and stm32mp1.
- vdd-supply: Phandle to the vdd input voltage. It can be used to supply ADC
analog input switches on stm32mp1.
- st,syscfg: Phandle to system configuration controller. It can be used to
control the analog circuitry on stm32mp1.
Contents of a stm32 adc child node:
-----------------------------------

View File

@ -1,26 +0,0 @@
* Plantower PMS7003 particulate matter sensor
Required properties:
- compatible: must one of:
"plantower,pms1003"
"plantower,pms3003"
"plantower,pms5003"
"plantower,pms6003"
"plantower,pms7003"
"plantower,pmsa003"
- vcc-supply: phandle to the regulator that provides power to the sensor
Optional properties:
- plantower,set-gpios: phandle to the GPIO connected to the SET line
- reset-gpios: phandle to the GPIO connected to the RESET line
Refer to serial/slave-device.txt for generic serial attached device bindings.
Example:
&uart0 {
air-pollution-sensor {
compatible = "plantower,pms7003";
vcc-supply = <&reg_vcc5v0>;
};
};

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/chemical/plantower,pms7003.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Plantower PMS7003 air pollution sensor
maintainers:
- Tomasz Duszynski <tduszyns@gmail.com>
description: |
Air pollution sensor capable of measuring mass concentration of dust
particles.
properties:
compatible:
enum:
- plantower,pms1003
- plantower,pms3003
- plantower,pms5003
- plantower,pms6003
- plantower,pms7003
- plantower,pmsa003
vcc-supply:
description: regulator that provides power to the sensor
maxItems: 1
plantower,set-gpios:
description: GPIO connected to the SET line
maxItems: 1
reset-gpios:
description: GPIO connected to the RESET line
maxItems: 1
required:
- compatible
- vcc-supply
examples:
- |
serial {
air-pollution-sensor {
compatible = "plantower,pms7003";
vcc-supply = <&reg_vcc5v0>;
};
};
...

View File

@ -0,0 +1,53 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/adi,adis16460.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices ADIS16460 and similar IMUs
maintainers:
- Dragos Bogdan <dragos.bogdan@analog.com>
description: |
Analog Devices ADIS16460 and similar IMUs
https://www.analog.com/media/en/technical-documentation/data-sheets/ADIS16460.pdf
properties:
compatible:
enum:
- adi,adis16460
reg:
maxItems: 1
spi-cpha: true
spi-cpol: true
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
imu@0 {
compatible = "adi,adis16460";
reg = <0>;
spi-max-frequency = <5000000>;
spi-cpol;
spi-cpha;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
};
};

View File

@ -11,6 +11,8 @@ Required properties:
"st,asm330lhh"
"st,lsm6dsox"
"st,lsm6dsr"
"st,lsm6ds3tr-c"
"st,ism330dhcx"
- reg: i2c address of the sensor / spi cs line
Optional properties:

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/noa1305.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ON Semiconductor NOA1305 Ambient Light Sensor
maintainers:
- Martyn Welch <martyn.welch@collabora.com>
description: |
Ambient sensing with an i2c interface.
https://www.onsemi.com/pub/Collateral/NOA1305-D.PDF
properties:
compatible:
enum:
- onnn,noa1305
reg:
maxItems: 1
vin-supply:
description: Regulator that provides power to the sensor
required:
- compatible
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
light@39 {
compatible = "onnn,noa1305";
reg = <0x39>;
};
};
...

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/light/stk33xx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: |
Sensortek STK33xx I2C Ambient Light and Proximity sensor
maintainers:
- Jonathan Cameron <jic23@kernel.org>
description: |
Ambient light and proximity sensor over an i2c interface.
properties:
compatible:
enum:
- sensortek,stk3310
- sensortek,stk3311
- sensortek,stk3335
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
stk3310@48 {
compatible = "sensortek,stk3310";
reg = <0x48>;
interrupt-parent = <&gpio1>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
};
};
...

View File

@ -0,0 +1,203 @@
For discussion. Unclear are:
* is the definition of +/- values practical or counterintuitive?
* are the definitions unambiguous and easy to follow?
* are the examples correct?
* should we have HOWTO engineer a correct matrix for a new device (without comparing to a different one)?
====
Mounting matrix
The mounting matrix is a device tree property used to orient any device
that produce three-dimensional data in relation to the world where it is
deployed.
The purpose of the mounting matrix is to translate the sensor frame of
reference into the device frame of reference using a translation matrix as
defined in linear algebra.
The typical usecase is that where a component has an internal representation
of the (x,y,z) triplets, such as different registers to read these coordinates,
and thus implying that the component should be mounted in a certain orientation
relative to some specific device frame of reference.
For example a device with some kind of screen, where the user is supposed to
interact with the environment using an accelerometer, gyroscope or magnetometer
mounted on the same chassis as this screen, will likely take the screen as
reference to (x,y,z) orientation, with (x,y) corresponding to these axes on the
screen and (z) being depth, the axis perpendicular to the screen.
For a screen you probably want (x) coordinates to go from negative on the left
to positive on the right, (y) from negative on the bottom to positive on top
and (z) depth to be negative under the screen and positive in front of it,
toward the face of the user.
A sensor can be mounted in any angle along the axes relative to the frame of
reference. This means that the sensor may be flipped upside-down, left-right,
or tilted at any angle relative to the frame of reference.
Another frame of reference is how the device with its sensor relates to the
external world, the environment where the device is deployed. Usually the data
from the sensor is used to figure out how the device is oriented with respect
to this world. When using the mounting matrix, the sensor and device orientation
becomes identical and we can focus on the data as it relates to the surrounding
world.
Device-to-world examples for some three-dimensional sensor types:
- Accelerometers have their world frame of reference toward the center of
gravity, usually to the core of the planet. A reading of the (x,y,z) values
from the sensor will give a projection of the gravity vector through the
device relative to the center of the planet, i.e. relative to its surface at
this point. Up and down in the world relative to the device frame of
reference can thus be determined. and users would likely expect a value of
9.81 m/s^2 upwards along the (z) axis, i.e. out of the screen when the device
is held with its screen flat on the planets surface and 0 on the other axes,
as the gravity vector is projected 1:1 onto the sensors (z)-axis.
If you tilt the device, the g vector virtually coming out of the display
is projected onto the (x,y) plane of the display panel.
Example:
^ z: +g ^ z: > 0
! /!
! x=y=0 / ! x: > 0
+--------+ +--------+
! ! ! !
+--------+ +--------+
! /
! /
v v
center of center of
gravity gravity
If the device is tilted to the left, you get a positive x value. If you point
its top towards surface, you get a negative y axis.
(---------)
! ! y: -g
! ! ^
! ! !
! !
! ! x: +g <- z: +g -> x: -g
! 1 2 3 !
! 4 5 6 ! !
! 7 8 9 ! v
! * 0 # ! y: +g
(---------)
- Magnetometers (compasses) have their world frame of reference relative to the
geomagnetic field. The system orientation vis-a-vis the world is defined with
respect to the local earth geomagnetic reference frame where (y) is in the
ground plane and positive towards magnetic North, (x) is in the ground plane,
perpendicular to the North axis and positive towards the East and (z) is
perpendicular to the ground plane and positive upwards.
^^^ North: y > 0
(---------)
! !
! !
! !
! ! >
! ! > North: x > 0
! 1 2 3 ! >
! 4 5 6 !
! 7 8 9 !
! * 0 # !
(---------)
Since the geomagnetic field is not uniform this definition fails if we come
closer to the poles.
Sensors and driver can not and should not take care of this because there
are complex calculations and empirical data to be taken care of. We leave
this up to user space.
The definition we take:
If the device is placed at the equator and the top is pointing north, the
display is readable by a person standing upright on the earth surface, this
defines a positive y value.
- Gyroscopes detects the movement relative the device itself. The angular
velocity is defined as orthogonal to the plane of rotation, so if you put the
device on a flat surface and spin it around the z axis (such as rotating a
device with a screen lying flat on a table), you should get a negative value
along the (z) axis if rotated clockwise, and a positive value if rotated
counter-clockwise according to the right-hand rule.
(---------) y > 0
! ! v---\
! !
! !
! ! <--\
! ! ! z > 0
! 1 2 3 ! --/
! 4 5 6 !
! 7 8 9 !
! * 0 # !
(---------)
So unless the sensor is ideally mounted, we need a means to indicate the
relative orientation of any given sensor of this type with respect to the
frame of reference.
To achieve this, use the device tree property "mount-matrix" for the sensor.
This supplies a 3x3 rotation matrix in the strict linear algebraic sense,
to orient the senor axes relative to a desired point of reference. This means
the resulting values from the sensor, after scaling to proper units, should be
multiplied by this matrix to give the proper vectors values in three-dimensional
space, relative to the device or world point of reference.
For more information, consult:
https://en.wikipedia.org/wiki/Rotation_matrix
The mounting matrix has the layout:
(mxx, myx, mzx)
(mxy, myy, mzy)
(mxz, myz, mzz)
Values are intended to be multiplied as:
x' = mxx * x + myx * y + mzx * z
y' = mxy * x + myy * y + mzy * z
z' = mxz * x + myz * y + mzz * z
It is represented as an array of strings containing the real values for
producing the transformation matrix.
Examples:
Identity matrix (nothing happens to the coordinates, which means the device was
mechanically mounted in an ideal way and we need no transformation):
mount-matrix = "1", "0", "0",
"0", "1", "0",
"0", "0", "1";
The sensor is mounted 30 degrees (Pi/6 radians) tilted along the X axis, so we
compensate by performing a -30 degrees rotation around the X axis:
mount-matrix = "1", "0", "0",
"0", "0.866", "0.5",
"0", "-0.5", "0.866";
The sensor is flipped 180 degrees (Pi radians) around the Z axis, i.e. mounted
upside-down:
mount-matrix = "0.998", "0.054", "0",
"-0.054", "0.998", "0",
"0", "0", "1";
???: this does not match "180 degrees" - factors indicate ca. 3 degrees compensation

View File

@ -0,0 +1,44 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/potentiometer/max5432.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Maxim Integrated MAX5432-MAX5435 Digital Potentiometers
maintainers:
- Martin Kaiser <martin@kaiser.cx>
description: |
Maxim Integrated MAX5432-MAX5435 Digital Potentiometers connected via I2C
Datasheet:
https://datasheets.maximintegrated.com/en/ds/MAX5432-MAX5435.pdf
properties:
compatible:
enum:
- maxim,max5432
- maxim,max5433
- maxim,max5434
- maxim,max5435
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
max5434@28 {
compatible = "maxim,max5434";
reg = <0x28>;
};
};

View File

@ -813,6 +813,8 @@ patternProperties:
description: Semtech Corporation
"^sensirion,.*":
description: Sensirion AG
"^sensortek,.*":
description: Sensortek Technology Corporation
"^sff,.*":
description: Small Form Factor Committee
"^sgd,.*":

View File

@ -945,6 +945,14 @@ L: linux-iio@vger.kernel.org
F: include/linux/iio/imu/adis.h
F: drivers/iio/imu/adis.c
ANALOG DEVICES INC ADIS16460 DRIVER
M: Dragos Bogdan <dragos.bogdan@analog.com>
S: Supported
L: linux-iio@vger.kernel.org
W: http://ez.analog.com/community/linux-device-drivers
F: drivers/iio/imu/adis16460.c
F: Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml
ANALOG DEVICES INC ADP5061 DRIVER
M: Stefan Popa <stefan.popa@analog.com>
L: linux-pm@vger.kernel.org
@ -12776,6 +12784,12 @@ F: drivers/i2c/busses/i2c-puv3.c
F: drivers/video/fbdev/fb-puv3.c
F: drivers/rtc/rtc-puv3.c
PLANTOWER PMS7003 AIR POLLUTION SENSOR DRIVER
M: Tomasz Duszynski <tduszyns@gmail.com>
S: Maintained
F: drivers/iio/chemical/pms7003.c
F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml
PMBUS HARDWARE MONITORING DRIVERS
M: Guenter Roeck <linux@roeck-us.net>
L: linux-hwmon@vger.kernel.org

View File

@ -100,16 +100,18 @@ static void ftm_quaddec_init(struct ftm_quaddec *ftm)
ftm_set_write_protection(ftm);
}
static void ftm_quaddec_disable(struct ftm_quaddec *ftm)
static void ftm_quaddec_disable(void *ftm)
{
ftm_clear_write_protection(ftm);
ftm_write(ftm, FTM_MODE, 0);
ftm_write(ftm, FTM_QDCTRL, 0);
struct ftm_quaddec *ftm_qua = ftm;
ftm_clear_write_protection(ftm_qua);
ftm_write(ftm_qua, FTM_MODE, 0);
ftm_write(ftm_qua, FTM_QDCTRL, 0);
/*
* This is enough to disable the counter. No clock has been
* selected by writing to FTM_SC in init()
*/
ftm_set_write_protection(ftm);
ftm_set_write_protection(ftm_qua);
}
static int ftm_quaddec_get_prescaler(struct counter_device *counter,
@ -317,20 +319,13 @@ static int ftm_quaddec_probe(struct platform_device *pdev)
ftm_quaddec_init(ftm);
ret = counter_register(&ftm->counter);
ret = devm_add_action_or_reset(&pdev->dev, ftm_quaddec_disable, ftm);
if (ret)
ftm_quaddec_disable(ftm);
return ret;
return ret;
}
static int ftm_quaddec_remove(struct platform_device *pdev)
{
struct ftm_quaddec *ftm = platform_get_drvdata(pdev);
counter_unregister(&ftm->counter);
ftm_quaddec_disable(ftm);
ret = devm_counter_register(&pdev->dev, &ftm->counter);
if (ret)
return ret;
return 0;
}
@ -346,7 +341,6 @@ static struct platform_driver ftm_quaddec_driver = {
.of_match_table = ftm_quaddec_match,
},
.probe = ftm_quaddec_probe,
.remove = ftm_quaddec_remove,
};
module_platform_driver(ftm_quaddec_driver);

View File

@ -200,6 +200,59 @@ struct i3c_device *dev_to_i3cdev(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_to_i3cdev);
/**
* i3c_device_match_id() - Returns the i3c_device_id entry matching @i3cdev
* @i3cdev: I3C device
* @id_table: I3C device match table
*
* Return: a pointer to an i3c_device_id object or NULL if there's no match.
*/
const struct i3c_device_id *
i3c_device_match_id(struct i3c_device *i3cdev,
const struct i3c_device_id *id_table)
{
struct i3c_device_info devinfo;
const struct i3c_device_id *id;
i3c_device_get_info(i3cdev, &devinfo);
/*
* The lower 32bits of the provisional ID is just filled with a random
* value, try to match using DCR info.
*/
if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
u16 part = I3C_PID_PART_ID(devinfo.pid);
u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
/* First try to match by manufacturer/part ID. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
I3C_MATCH_MANUF_AND_PART)
continue;
if (manuf != id->manuf_id || part != id->part_id)
continue;
if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
ext_info != id->extra_info)
continue;
return id;
}
}
/* Fallback to DCR match. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_DCR) &&
id->dcr == devinfo.dcr)
return id;
}
return NULL;
}
EXPORT_SYMBOL_GPL(i3c_device_match_id);
/**
* i3c_driver_register_with_owner() - register an I3C device driver
*

View File

@ -276,51 +276,6 @@ static const struct device_type i3c_device_type = {
.uevent = i3c_device_uevent,
};
static const struct i3c_device_id *
i3c_device_match_id(struct i3c_device *i3cdev,
const struct i3c_device_id *id_table)
{
struct i3c_device_info devinfo;
const struct i3c_device_id *id;
i3c_device_get_info(i3cdev, &devinfo);
/*
* The lower 32bits of the provisional ID is just filled with a random
* value, try to match using DCR info.
*/
if (!I3C_PID_RND_LOWER_32BITS(devinfo.pid)) {
u16 manuf = I3C_PID_MANUF_ID(devinfo.pid);
u16 part = I3C_PID_PART_ID(devinfo.pid);
u16 ext_info = I3C_PID_EXTRA_INFO(devinfo.pid);
/* First try to match by manufacturer/part ID. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_MANUF_AND_PART) !=
I3C_MATCH_MANUF_AND_PART)
continue;
if (manuf != id->manuf_id || part != id->part_id)
continue;
if ((id->match_flags & I3C_MATCH_EXTRA_INFO) &&
ext_info != id->extra_info)
continue;
return id;
}
}
/* Fallback to DCR match. */
for (id = id_table; id->match_flags != 0; id++) {
if ((id->match_flags & I3C_MATCH_DCR) &&
id->dcr == devinfo.dcr)
return id;
}
return NULL;
}
static int i3c_device_match(struct device *dev, struct device_driver *drv)
{
struct i3c_device *i3cdev;

View File

@ -202,9 +202,7 @@ config HID_SENSOR_ACCEL_3D
config IIO_CROS_EC_ACCEL_LEGACY
tristate "ChromeOS EC Legacy Accelerometer Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select CROS_EC_LPC_REGISTER_DEVICE
depends on IIO_CROS_EC_SENSORS_CORE
help
Say yes here to get support for accelerometers on Chromebook using
legacy EC firmware.

View File

@ -5,13 +5,14 @@
* Copyright 2017 Google, Inc
*
* This driver uses the memory mapper cros-ec interface to communicate
* with the Chrome OS EC about accelerometer data.
* with the Chrome OS EC about accelerometer data or older commands.
* Accelerometer access is presented through iio sysfs.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/iio/buffer.h>
#include <linux/iio/common/cros_ec_sensors_core.h>
#include <linux/iio/iio.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
@ -25,160 +26,41 @@
#define DRV_NAME "cros-ec-accel-legacy"
#define CROS_EC_SENSOR_LEGACY_NUM 2
/*
* Sensor scale hard coded at 10 bits per g, computed as:
* g / (2^10 - 1) = 0.009586168; with g = 9.80665 m.s^-2
*/
#define ACCEL_LEGACY_NSCALE 9586168
/* Indices for EC sensor values. */
enum {
X,
Y,
Z,
MAX_AXIS,
};
/* State data for cros_ec_accel_legacy iio driver. */
struct cros_ec_accel_legacy_state {
struct cros_ec_device *ec;
/*
* Array holding data from a single capture. 2 bytes per channel
* for the 3 channels plus the timestamp which is always last and
* 8-bytes aligned.
*/
s16 capture_data[8];
s8 sign[MAX_AXIS];
u8 sensor_num;
};
static int ec_cmd_read_u8(struct cros_ec_device *ec, unsigned int offset,
u8 *dest)
static int cros_ec_accel_legacy_read_cmd(struct iio_dev *indio_dev,
unsigned long scan_mask, s16 *data)
{
return ec->cmd_readmem(ec, offset, 1, dest);
}
static int ec_cmd_read_u16(struct cros_ec_device *ec, unsigned int offset,
u16 *dest)
{
__le16 tmp;
int ret = ec->cmd_readmem(ec, offset, 2, &tmp);
*dest = le16_to_cpu(tmp);
return ret;
}
/**
* read_ec_until_not_busy() - Read from EC status byte until it reads not busy.
* @st: Pointer to state information for device.
*
* This function reads EC status until its busy bit gets cleared. It does not
* wait indefinitely and returns -EIO if the EC status is still busy after a
* few hundreds milliseconds.
*
* Return: 8-bit status if ok, -EIO on error
*/
static int read_ec_until_not_busy(struct cros_ec_accel_legacy_state *st)
{
struct cros_ec_device *ec = st->ec;
u8 status;
int attempts = 0;
ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status);
while (status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) {
/* Give up after enough attempts, return error. */
if (attempts++ >= 50)
return -EIO;
/* Small delay every so often. */
if (attempts % 5 == 0)
msleep(25);
ec_cmd_read_u8(ec, EC_MEMMAP_ACC_STATUS, &status);
}
return status;
}
/**
* read_ec_accel_data_unsafe() - Read acceleration data from EC shared memory.
* @st: Pointer to state information for device.
* @scan_mask: Bitmap of the sensor indices to scan.
* @data: Location to store data.
*
* This is the unsafe function for reading the EC data. It does not guarantee
* that the EC will not modify the data as it is being read in.
*/
static void read_ec_accel_data_unsafe(struct cros_ec_accel_legacy_state *st,
unsigned long scan_mask, s16 *data)
{
int i = 0;
int num_enabled = bitmap_weight(&scan_mask, MAX_AXIS);
/* Read all sensors enabled in scan_mask. Each value is 2 bytes. */
while (num_enabled--) {
i = find_next_bit(&scan_mask, MAX_AXIS, i);
ec_cmd_read_u16(st->ec,
EC_MEMMAP_ACC_DATA +
sizeof(s16) *
(1 + i + st->sensor_num * MAX_AXIS),
data);
*data *= st->sign[i];
i++;
data++;
}
}
/**
* read_ec_accel_data() - Read acceleration data from EC shared memory.
* @st: Pointer to state information for device.
* @scan_mask: Bitmap of the sensor indices to scan.
* @data: Location to store data.
*
* This is the safe function for reading the EC data. It guarantees that
* the data sampled was not modified by the EC while being read.
*
* Return: 0 if ok, -ve on error
*/
static int read_ec_accel_data(struct cros_ec_accel_legacy_state *st,
unsigned long scan_mask, s16 *data)
{
u8 samp_id = 0xff;
u8 status = 0;
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
int ret;
int attempts = 0;
unsigned int i;
u8 sensor_num;
/*
* Continually read all data from EC until the status byte after
* all reads reflects that the EC is not busy and the sample id
* matches the sample id from before all reads. This guarantees
* that data read in was not modified by the EC while reading.
* Read all sensor data through a command.
* Save sensor_num, it is assumed to stay.
*/
while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT |
EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) {
/* If we have tried to read too many times, return error. */
if (attempts++ >= 5)
return -EIO;
sensor_num = st->param.info.sensor_num;
st->param.cmd = MOTIONSENSE_CMD_DUMP;
st->param.dump.max_sensor_count = CROS_EC_SENSOR_LEGACY_NUM;
ret = cros_ec_motion_send_host_cmd(st,
sizeof(st->resp->dump) + CROS_EC_SENSOR_LEGACY_NUM *
sizeof(struct ec_response_motion_sensor_data));
st->param.info.sensor_num = sensor_num;
if (ret != 0) {
dev_warn(&indio_dev->dev, "Unable to read sensor data\n");
return ret;
}
/* Read status byte until EC is not busy. */
ret = read_ec_until_not_busy(st);
if (ret < 0)
return ret;
status = ret;
/*
* Store the current sample id so that we can compare to the
* sample id after reading the data.
*/
samp_id = status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK;
/* Read all EC data, format it, and store it into data. */
read_ec_accel_data_unsafe(st, scan_mask, data);
/* Read status byte. */
ec_cmd_read_u8(st->ec, EC_MEMMAP_ACC_STATUS, &status);
for_each_set_bit(i, &scan_mask, indio_dev->masklength) {
*data = st->resp->dump.sensor[sensor_num].data[i] *
st->sign[i];
data++;
}
return 0;
@ -188,28 +70,40 @@ static int cros_ec_accel_legacy_read(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
struct cros_ec_sensors_core_state *st = iio_priv(indio_dev);
s16 data = 0;
int ret = IIO_VAL_INT;
int ret;
int idx = chan->scan_index;
mutex_lock(&st->cmd_lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = read_ec_accel_data(st, (1 << chan->scan_index), &data);
if (ret)
return ret;
ret = st->read_ec_sensors_data(indio_dev, 1 << idx, &data);
if (ret < 0)
break;
ret = IIO_VAL_INT;
*val = data;
return IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
WARN_ON(st->type != MOTIONSENSE_TYPE_ACCEL);
*val = 0;
*val2 = ACCEL_LEGACY_NSCALE;
return IIO_VAL_INT_PLUS_NANO;
ret = IIO_VAL_INT_PLUS_NANO;
break;
case IIO_CHAN_INFO_CALIBBIAS:
/* Calibration not supported. */
*val = 0;
return IIO_VAL_INT;
ret = IIO_VAL_INT;
break;
default:
return -EINVAL;
ret = cros_ec_sensors_core_read(st, chan, val, val2,
mask);
break;
}
mutex_unlock(&st->cmd_lock);
return ret;
}
static int cros_ec_accel_legacy_write(struct iio_dev *indio_dev,
@ -231,86 +125,14 @@ static const struct iio_info cros_ec_accel_legacy_info = {
.write_raw = &cros_ec_accel_legacy_write,
};
/**
* cros_ec_accel_legacy_capture() - The trigger handler function
* @irq: The interrupt number.
* @p: Private data - always a pointer to the poll func.
*
* On a trigger event occurring, if the pollfunc is attached then this
* handler is called as a threaded interrupt (and hence may sleep). It
* is responsible for grabbing data from the device and pushing it into
* the associated buffer.
*
* Return: IRQ_HANDLED
/*
* Present the channel using HTML5 standard:
* need to invert X and Y and invert some lid axis.
*/
static irqreturn_t cros_ec_accel_legacy_capture(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
/* Clear capture data. */
memset(st->capture_data, 0, sizeof(st->capture_data));
/*
* Read data based on which channels are enabled in scan mask. Note
* that on a capture we are always reading the calibrated data.
*/
read_ec_accel_data(st, *indio_dev->active_scan_mask, st->capture_data);
iio_push_to_buffers_with_timestamp(indio_dev, (void *)st->capture_data,
iio_get_time_ns(indio_dev));
/*
* Tell the core we are done with this trigger and ready for the
* next one.
*/
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static char *cros_ec_accel_legacy_loc_strings[] = {
[MOTIONSENSE_LOC_BASE] = "base",
[MOTIONSENSE_LOC_LID] = "lid",
[MOTIONSENSE_LOC_MAX] = "unknown",
};
static ssize_t cros_ec_accel_legacy_loc(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
return sprintf(buf, "%s\n",
cros_ec_accel_legacy_loc_strings[st->sensor_num +
MOTIONSENSE_LOC_BASE]);
}
static ssize_t cros_ec_accel_legacy_id(struct iio_dev *indio_dev,
uintptr_t private,
const struct iio_chan_spec *chan,
char *buf)
{
struct cros_ec_accel_legacy_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->sensor_num);
}
static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = {
{
.name = "id",
.shared = IIO_SHARED_BY_ALL,
.read = cros_ec_accel_legacy_id,
},
{
.name = "location",
.shared = IIO_SHARED_BY_ALL,
.read = cros_ec_accel_legacy_loc,
},
{ }
};
#define CROS_EC_ACCEL_ROTATE_AXIS(_axis) \
((_axis) == CROS_EC_SENSOR_Z ? CROS_EC_SENSOR_Z : \
((_axis) == CROS_EC_SENSOR_X ? CROS_EC_SENSOR_Y : \
CROS_EC_SENSOR_X))
#define CROS_EC_ACCEL_LEGACY_CHAN(_axis) \
{ \
@ -321,28 +143,28 @@ static const struct iio_chan_spec_ext_info cros_ec_accel_legacy_ext_info[] = {
BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_CALIBBIAS), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \
.ext_info = cros_ec_accel_legacy_ext_info, \
.ext_info = cros_ec_sensors_ext_info, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.realbits = CROS_EC_SENSOR_BITS, \
.storagebits = CROS_EC_SENSOR_BITS, \
}, \
.scan_index = CROS_EC_ACCEL_ROTATE_AXIS(_axis), \
} \
static struct iio_chan_spec ec_accel_channels[] = {
CROS_EC_ACCEL_LEGACY_CHAN(X),
CROS_EC_ACCEL_LEGACY_CHAN(Y),
CROS_EC_ACCEL_LEGACY_CHAN(Z),
IIO_CHAN_SOFT_TIMESTAMP(MAX_AXIS)
static const struct iio_chan_spec cros_ec_accel_legacy_channels[] = {
CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_X),
CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Y),
CROS_EC_ACCEL_LEGACY_CHAN(CROS_EC_SENSOR_Z),
IIO_CHAN_SOFT_TIMESTAMP(CROS_EC_SENSOR_MAX_AXIS)
};
static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec = dev_get_drvdata(dev->parent);
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
struct iio_dev *indio_dev;
struct cros_ec_accel_legacy_state *state;
struct cros_ec_sensors_core_state *state;
int ret;
if (!ec || !ec->ec_dev) {
@ -350,46 +172,32 @@ static int cros_ec_accel_legacy_probe(struct platform_device *pdev)
return -EINVAL;
}
if (!ec->ec_dev->cmd_readmem) {
dev_warn(&pdev->dev, "EC does not support direct reads.\n");
return -EINVAL;
}
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
if (!indio_dev)
return -ENOMEM;
platform_set_drvdata(pdev, indio_dev);
state = iio_priv(indio_dev);
state->ec = ec->ec_dev;
state->sensor_num = sensor_platform->sensor_num;
ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
if (ret)
return ret;
indio_dev->dev.parent = dev;
indio_dev->name = pdev->name;
indio_dev->channels = ec_accel_channels;
/*
* Present the channel using HTML5 standard:
* need to invert X and Y and invert some lid axis.
*/
ec_accel_channels[X].scan_index = Y;
ec_accel_channels[Y].scan_index = X;
ec_accel_channels[Z].scan_index = Z;
state->sign[Y] = 1;
if (state->sensor_num == MOTIONSENSE_LOC_LID)
state->sign[X] = state->sign[Z] = -1;
else
state->sign[X] = state->sign[Z] = 1;
indio_dev->num_channels = ARRAY_SIZE(ec_accel_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &cros_ec_accel_legacy_info;
indio_dev->modes = INDIO_DIRECT_MODE;
state = iio_priv(indio_dev);
if (state->ec->cmd_readmem != NULL)
state->read_ec_sensors_data = cros_ec_sensors_read_lpc;
else
state->read_ec_sensors_data = cros_ec_accel_legacy_read_cmd;
indio_dev->channels = cros_ec_accel_legacy_channels;
indio_dev->num_channels = ARRAY_SIZE(cros_ec_accel_legacy_channels);
/* The lid sensor needs to be presented inverted. */
if (state->loc == MOTIONSENSE_LOC_LID) {
state->sign[CROS_EC_SENSOR_X] = -1;
state->sign[CROS_EC_SENSOR_Z] = -1;
}
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
cros_ec_accel_legacy_capture,
NULL);
cros_ec_sensors_capture, NULL);
if (ret)
return ret;

View File

@ -424,7 +424,7 @@ static int mxc4005_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mxc4005_info;
ret = iio_triggered_buffer_setup(indio_dev,
ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev,
iio_pollfunc_store_time,
mxc4005_trigger_handler,
NULL);
@ -452,7 +452,7 @@ static int mxc4005_probe(struct i2c_client *client,
if (ret) {
dev_err(&client->dev,
"failed to init threaded irq\n");
goto err_buffer_cleanup;
return ret;
}
data->dready_trig->dev.parent = &client->dev;
@ -460,43 +460,16 @@ static int mxc4005_probe(struct i2c_client *client,
iio_trigger_set_drvdata(data->dready_trig, indio_dev);
indio_dev->trig = data->dready_trig;
iio_trigger_get(indio_dev->trig);
ret = iio_trigger_register(data->dready_trig);
ret = devm_iio_trigger_register(&client->dev,
data->dready_trig);
if (ret) {
dev_err(&client->dev,
"failed to register trigger\n");
goto err_trigger_unregister;
return ret;
}
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev,
"unable to register iio device %d\n", ret);
goto err_buffer_cleanup;
}
return 0;
err_trigger_unregister:
iio_trigger_unregister(data->dready_trig);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int mxc4005_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mxc4005_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (data->dready_trig)
iio_trigger_unregister(data->dready_trig);
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct acpi_device_id mxc4005_acpi_match[] = {
@ -517,7 +490,6 @@ static struct i2c_driver mxc4005_driver = {
.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
},
.probe = mxc4005_probe,
.remove = mxc4005_remove,
.id_table = mxc4005_id,
};

View File

@ -111,7 +111,7 @@
/* Currently unsupported */
#define SCA3000_MD_CTRL_AND_Y BIT(3)
#define SCA3000_MD_CTRL_AND_X BIT(4)
#define SAC3000_MD_CTRL_AND_Z BIT(5)
#define SCA3000_MD_CTRL_AND_Z BIT(5)
/*
* Some control registers of complex access methods requiring this register to

View File

@ -68,6 +68,7 @@ static const struct st_sensors_platform_data default_accel_pdata = {
.drdy_int_pin = 1,
};
const struct st_sensor_settings *st_accel_get_settings(const char *name);
int st_accel_common_probe(struct iio_dev *indio_dev);
void st_accel_common_remove(struct iio_dev *indio_dev);

View File

@ -29,65 +29,51 @@ int st_accel_trig_set_state(struct iio_trigger *trig, bool state)
return st_sensors_set_dataready_irq(indio_dev, state);
}
static int st_accel_buffer_preenable(struct iio_dev *indio_dev)
{
return st_sensors_set_enable(indio_dev, true);
}
static int st_accel_buffer_postenable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *adata = iio_priv(indio_dev);
adata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (adata->buffer_data == NULL) {
err = -ENOMEM;
goto allocate_memory_error;
}
err = iio_triggered_buffer_postenable(indio_dev);
if (err < 0)
goto st_accel_buffer_postenable_error;
return err;
err = st_sensors_set_axis_enable(indio_dev,
(u8)indio_dev->active_scan_mask[0]);
(u8)indio_dev->active_scan_mask[0]);
if (err < 0)
goto st_sensors_set_axis_enable_error;
goto st_accel_buffer_predisable;
return err;
err = st_sensors_set_enable(indio_dev, true);
if (err < 0)
goto st_accel_buffer_enable_all_axis;
st_sensors_set_axis_enable_error:
return 0;
st_accel_buffer_enable_all_axis:
st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
st_accel_buffer_predisable:
iio_triggered_buffer_predisable(indio_dev);
st_accel_buffer_postenable_error:
kfree(adata->buffer_data);
allocate_memory_error:
return err;
}
static int st_accel_buffer_predisable(struct iio_dev *indio_dev)
{
int err, err2;
struct st_sensor_data *adata = iio_priv(indio_dev);
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
if (err < 0)
goto st_accel_buffer_predisable_error;
err = st_sensors_set_enable(indio_dev, false);
if (err < 0)
goto st_accel_buffer_predisable_error;
goto st_accel_buffer_predisable;
st_accel_buffer_predisable_error:
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
st_accel_buffer_predisable:
err2 = iio_triggered_buffer_predisable(indio_dev);
if (!err)
err = err2;
kfree(adata->buffer_data);
return err;
}
static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {
.preenable = &st_accel_buffer_preenable,
.postenable = &st_accel_buffer_postenable,
.predisable = &st_accel_buffer_predisable,
};

View File

@ -13,7 +13,6 @@
#include <linux/acpi.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
@ -1147,32 +1146,45 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev,
#endif
}
/*
* st_accel_get_settings() - get sensor settings from device name
* @name: device name buffer reference.
*
* Return: valid reference on success, NULL otherwise.
*/
const struct st_sensor_settings *st_accel_get_settings(const char *name)
{
int index = st_sensors_get_settings_index(name,
st_accel_sensors_settings,
ARRAY_SIZE(st_accel_sensors_settings));
if (index < 0)
return NULL;
return &st_accel_sensors_settings[index];
}
EXPORT_SYMBOL(st_accel_get_settings);
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)adata->dev->platform_data;
int irq = adata->get_irq_data_ready(indio_dev);
struct iio_chan_spec *channels;
size_t channels_size;
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &accel_info;
mutex_init(&adata->tb.buf_lock);
err = st_sensors_power_enable(indio_dev);
if (err)
return err;
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_accel_sensors_settings),
st_accel_sensors_settings);
err = st_sensors_verify_id(indio_dev);
if (err < 0)
goto st_accel_power_off;
adata->num_data_channels = ST_ACCEL_NUMBER_DATA_CHANNELS;
adata->multiread_bit = adata->sensor_settings->multi_read_bit;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
channels_size = indio_dev->num_channels * sizeof(struct iio_chan_spec);
@ -1204,7 +1216,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
if (err < 0)
goto st_accel_power_off;
if (irq > 0) {
if (adata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
ST_ACCEL_TRIGGER_OPS);
if (err < 0)
@ -1221,7 +1233,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
return 0;
st_accel_device_register_error:
if (irq > 0)
if (adata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_accel_probe_trigger_error:
st_accel_deallocate_ring(indio_dev);
@ -1239,7 +1251,7 @@ void st_accel_common_remove(struct iio_dev *indio_dev)
st_sensors_power_disable(indio_dev);
iio_device_unregister(indio_dev);
if (adata->get_irq_data_ready(indio_dev) > 0)
if (adata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_accel_deallocate_ring(indio_dev);

View File

@ -150,22 +150,33 @@ MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
static int st_accel_i2c_probe(struct i2c_client *client)
{
struct iio_dev *indio_dev;
const struct st_sensor_settings *settings;
struct st_sensor_data *adata;
struct iio_dev *indio_dev;
const char *match;
int ret;
match = device_get_match_data(&client->dev);
if (match)
strlcpy(client->name, match, sizeof(client->name));
settings = st_accel_get_settings(client->name);
if (!settings) {
dev_err(&client->dev, "device name %s not recognized.\n",
client->name);
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
if (!indio_dev)
return -ENOMEM;
adata = iio_priv(indio_dev);
adata->sensor_settings = (struct st_sensor_settings *)settings;
match = device_get_match_data(&client->dev);
if (match)
strlcpy(client->name, match, sizeof(client->name));
st_sensors_i2c_configure(indio_dev, client, adata);
ret = st_sensors_i2c_configure(indio_dev, client);
if (ret < 0)
return ret;
ret = st_accel_common_probe(indio_dev);
if (ret < 0)

View File

@ -102,19 +102,31 @@ MODULE_DEVICE_TABLE(of, st_accel_of_match);
static int st_accel_spi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
const struct st_sensor_settings *settings;
struct st_sensor_data *adata;
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&spi->dev, st_accel_of_match,
spi->modalias, sizeof(spi->modalias));
settings = st_accel_get_settings(spi->modalias);
if (!settings) {
dev_err(&spi->dev, "device name %s not recognized.\n",
spi->modalias);
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adata));
if (!indio_dev)
return -ENOMEM;
adata = iio_priv(indio_dev);
adata->sensor_settings = (struct st_sensor_settings *)settings;
st_sensors_of_name_probe(&spi->dev, st_accel_of_match,
spi->modalias, sizeof(spi->modalias));
st_sensors_spi_configure(indio_dev, spi, adata);
err = st_sensors_spi_configure(indio_dev, spi);
if (err < 0)
return err;
err = st_accel_common_probe(indio_dev);
if (err < 0)

View File

@ -35,6 +35,11 @@ static const unsigned int ad7606_scale_avail[2] = {
152588, 305176
};
static const unsigned int ad7616_sw_scale_avail[3] = {
76293, 152588, 305176
};
static const unsigned int ad7606_oversampling_avail[7] = {
1, 2, 4, 8, 16, 32, 64,
};
@ -55,6 +60,29 @@ static int ad7606_reset(struct ad7606_state *st)
return -ENODEV;
}
static int ad7606_reg_access(struct iio_dev *indio_dev,
unsigned int reg,
unsigned int writeval,
unsigned int *readval)
{
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&st->lock);
if (readval) {
ret = st->bops->reg_read(st, reg);
if (ret < 0)
goto err_unlock;
*readval = ret;
ret = 0;
} else {
ret = st->bops->reg_write(st, reg, writeval);
}
err_unlock:
mutex_unlock(&st->lock);
return ret;
}
static int ad7606_read_samples(struct ad7606_state *st)
{
unsigned int num = st->chip_info->num_channels;
@ -308,29 +336,6 @@ static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
#define AD760X_CHANNEL(num, mask) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = num, \
.address = num, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
.info_mask_shared_by_all = mask, \
.scan_index = num, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
}
#define AD7605_CHANNEL(num) \
AD760X_CHANNEL(num, 0)
#define AD7606_CHANNEL(num) \
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO))
static const struct iio_chan_spec ad7605_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(4),
AD7605_CHANNEL(0),
@ -519,6 +524,14 @@ static const struct iio_info ad7606_info_os_and_range = {
.validate_trigger = &ad7606_validate_trigger,
};
static const struct iio_info ad7606_info_os_range_and_debug = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.debugfs_reg_access = &ad7606_reg_access,
.attrs = &ad7606_attribute_group_os_and_range,
.validate_trigger = &ad7606_validate_trigger,
};
static const struct iio_info ad7606_info_os = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
@ -617,35 +630,27 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
if (ret)
dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");
/* AD7616 requires al least 15ms to reconfigure after a reset */
if (msleep_interruptible(15))
return -ERESTARTSYS;
st->write_scale = ad7606_write_scale_hw;
st->write_os = ad7606_write_os_hw;
if (st->chip_info->sw_mode_config)
if (st->bops->sw_mode_config)
st->sw_mode_en = device_property_present(st->dev,
"adi,sw-mode");
if (st->sw_mode_en) {
/* Scale of 0.076293 is only available in sw mode */
st->scale_avail = ad7616_sw_scale_avail;
st->num_scales = ARRAY_SIZE(ad7616_sw_scale_avail);
/* After reset, in software mode, ±10 V is set by default */
memset32(st->range, 2, ARRAY_SIZE(st->range));
indio_dev->info = &ad7606_info_os_and_range;
indio_dev->info = &ad7606_info_os_range_and_debug;
/*
* In software mode, the range gpio has no longer its function.
* Instead, the scale can be configured individually for each
* channel from the range registers.
*/
if (st->chip_info->write_scale_sw)
st->write_scale = st->chip_info->write_scale_sw;
/*
* In software mode, the oversampling is no longer configured
* with GPIO pins. Instead, the oversampling can be configured
* in configuratiion register.
*/
if (st->chip_info->write_os_sw)
st->write_os = st->chip_info->write_os_sw;
ret = st->chip_info->sw_mode_config(indio_dev);
ret = st->bops->sw_mode_config(indio_dev);
if (ret < 0)
return ret;
}

View File

@ -8,6 +8,36 @@
#ifndef IIO_ADC_AD7606_H_
#define IIO_ADC_AD7606_H_
#define AD760X_CHANNEL(num, mask_sep, mask_type, mask_all) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = num, \
.address = num, \
.info_mask_separate = mask_sep, \
.info_mask_shared_by_type = mask_type, \
.info_mask_shared_by_all = mask_all, \
.scan_index = num, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_CPU, \
}, \
}
#define AD7605_CHANNEL(num) \
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \
BIT(IIO_CHAN_INFO_SCALE), 0)
#define AD7606_CHANNEL(num) \
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW), \
BIT(IIO_CHAN_INFO_SCALE), \
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO))
#define AD7616_CHANNEL(num) \
AD760X_CHANNEL(num, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),\
0, BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO))
/**
* struct ad7606_chip_info - chip specific information
* @channels: channel specification
@ -16,12 +46,6 @@
* oversampling ratios.
* @oversampling_num number of elements stored in oversampling_avail array
* @os_req_reset some devices require a reset to update oversampling
* @write_scale_sw pointer to the function which writes the scale via spi
in software mode
* @write_os_sw pointer to the function which writes the os via spi
in software mode
* @sw_mode_config: pointer to a function which configured the device
* for software mode
*/
struct ad7606_chip_info {
const struct iio_chan_spec *channels;
@ -29,9 +53,6 @@ struct ad7606_chip_info {
const unsigned int *oversampling_avail;
unsigned int oversampling_num;
bool os_req_reset;
int (*write_scale_sw)(struct iio_dev *indio_dev, int ch, int val);
int (*write_os_sw)(struct iio_dev *indio_dev, int val);
int (*sw_mode_config)(struct iio_dev *indio_dev);
};
/**
@ -63,6 +84,7 @@ struct ad7606_chip_info {
* @complete completion to indicate end of conversion
* @trig The IIO trigger associated with the device.
* @data buffer for reading data from the device
* @d16 be16 buffer for reading data from the device
*/
struct ad7606_state {
struct device *dev;
@ -96,15 +118,32 @@ struct ad7606_state {
* 16 * 16-bit samples + 64-bit timestamp
*/
unsigned short data[20] ____cacheline_aligned;
__be16 d16[2];
};
/**
* struct ad7606_bus_ops - driver bus operations
* @read_block function pointer for reading blocks of data
* @sw_mode_config: pointer to a function which configured the device
* for software mode
* @reg_read function pointer for reading spi register
* @reg_write function pointer for writing spi register
* @write_mask function pointer for write spi register with mask
* @rd_wr_cmd pointer to the function which calculates the spi address
*/
struct ad7606_bus_ops {
/* more methods added in future? */
int (*read_block)(struct device *dev, int num, void *data);
int (*sw_mode_config)(struct iio_dev *indio_dev);
int (*reg_read)(struct ad7606_state *st, unsigned int addr);
int (*reg_write)(struct ad7606_state *st,
unsigned int addr,
unsigned int val);
int (*write_mask)(struct ad7606_state *st,
unsigned int addr,
unsigned long mask,
unsigned int val);
u16 (*rd_wr_cmd)(int addr, char isWriteOp);
};
int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,

View File

@ -53,10 +53,8 @@ static int ad7606_par_probe(struct platform_device *pdev)
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq: %d\n", irq);
if (irq < 0)
return irq;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
addr = devm_ioremap_resource(&pdev->dev, res);

View File

@ -15,6 +15,51 @@
#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
#define AD7616_CONFIGURATION_REGISTER 0x02
#define AD7616_OS_MASK GENMASK(4, 2)
#define AD7616_BURST_MODE BIT(6)
#define AD7616_SEQEN_MODE BIT(5)
#define AD7616_RANGE_CH_A_ADDR_OFF 0x04
#define AD7616_RANGE_CH_B_ADDR_OFF 0x06
/*
* Range of channels from a group are stored in 2 registers.
* 0, 1, 2, 3 in a register followed by 4, 5, 6, 7 in second register.
* For channels from second group(8-15) the order is the same, only with
* an offset of 2 for register address.
*/
#define AD7616_RANGE_CH_ADDR(ch) ((ch) >> 2)
/* The range of the channel is stored on 2 bits*/
#define AD7616_RANGE_CH_MSK(ch) (0b11 << (((ch) & 0b11) * 2))
#define AD7616_RANGE_CH_MODE(ch, mode) ((mode) << ((((ch) & 0b11)) * 2))
static const struct iio_chan_spec ad7616_sw_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(16),
AD7616_CHANNEL(0),
AD7616_CHANNEL(1),
AD7616_CHANNEL(2),
AD7616_CHANNEL(3),
AD7616_CHANNEL(4),
AD7616_CHANNEL(5),
AD7616_CHANNEL(6),
AD7616_CHANNEL(7),
AD7616_CHANNEL(8),
AD7616_CHANNEL(9),
AD7616_CHANNEL(10),
AD7616_CHANNEL(11),
AD7616_CHANNEL(12),
AD7616_CHANNEL(13),
AD7616_CHANNEL(14),
AD7616_CHANNEL(15),
};
static u16 ad7616_spi_rd_wr_cmd(int addr, char isWriteOp)
{
/*
* The address of register consist of one w/r bit
* 6 bits of address followed by one reserved bit.
*/
return ((addr & 0x7F) << 1) | ((isWriteOp & 0x1) << 7);
}
static int ad7606_spi_read_block(struct device *dev,
int count, void *buf)
{
@ -35,17 +80,145 @@ static int ad7606_spi_read_block(struct device *dev,
return 0;
}
static int ad7606_spi_reg_read(struct ad7606_state *st, unsigned int addr)
{
struct spi_device *spi = to_spi_device(st->dev);
struct spi_transfer t[] = {
{
.tx_buf = &st->d16[0],
.len = 2,
.cs_change = 0,
}, {
.rx_buf = &st->d16[1],
.len = 2,
},
};
int ret;
st->d16[0] = cpu_to_be16(st->bops->rd_wr_cmd(addr, 0) << 8);
ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
if (ret < 0)
return ret;
return be16_to_cpu(st->d16[1]);
}
static int ad7606_spi_reg_write(struct ad7606_state *st,
unsigned int addr,
unsigned int val)
{
struct spi_device *spi = to_spi_device(st->dev);
st->d16[0] = cpu_to_be16((st->bops->rd_wr_cmd(addr, 1) << 8) |
(val & 0x1FF));
return spi_write(spi, &st->d16[0], sizeof(st->d16[0]));
}
static int ad7606_spi_write_mask(struct ad7606_state *st,
unsigned int addr,
unsigned long mask,
unsigned int val)
{
int readval;
readval = st->bops->reg_read(st, addr);
if (readval < 0)
return readval;
readval &= ~mask;
readval |= val;
return st->bops->reg_write(st, addr, readval);
}
static int ad7616_write_scale_sw(struct iio_dev *indio_dev, int ch, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int ch_addr, mode, ch_index;
/*
* Ad7616 has 16 channels divided in group A and group B.
* The range of channels from A are stored in registers with address 4
* while channels from B are stored in register with address 6.
* The last bit from channels determines if it is from group A or B
* because the order of channels in iio is 0A, 0B, 1A, 1B...
*/
ch_index = ch >> 1;
ch_addr = AD7616_RANGE_CH_ADDR(ch_index);
if ((ch & 0x1) == 0) /* channel A */
ch_addr += AD7616_RANGE_CH_A_ADDR_OFF;
else /* channel B */
ch_addr += AD7616_RANGE_CH_B_ADDR_OFF;
/* 0b01 for 2.5v, 0b10 for 5v and 0b11 for 10v */
mode = AD7616_RANGE_CH_MODE(ch_index, ((val + 1) & 0b11));
return st->bops->write_mask(st, ch_addr, AD7616_RANGE_CH_MSK(ch_index),
mode);
}
static int ad7616_write_os_sw(struct iio_dev *indio_dev, int val)
{
struct ad7606_state *st = iio_priv(indio_dev);
return st->bops->write_mask(st, AD7616_CONFIGURATION_REGISTER,
AD7616_OS_MASK, val << 2);
}
static int ad7616_sw_mode_config(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
/*
* Scale can be configured individually for each channel
* in software mode.
*/
indio_dev->channels = ad7616_sw_channels;
st->write_scale = ad7616_write_scale_sw;
st->write_os = &ad7616_write_os_sw;
/* Activate Burst mode and SEQEN MODE */
return st->bops->write_mask(st,
AD7616_CONFIGURATION_REGISTER,
AD7616_BURST_MODE | AD7616_SEQEN_MODE,
AD7616_BURST_MODE | AD7616_SEQEN_MODE);
}
static const struct ad7606_bus_ops ad7606_spi_bops = {
.read_block = ad7606_spi_read_block,
};
static const struct ad7606_bus_ops ad7616_spi_bops = {
.read_block = ad7606_spi_read_block,
.reg_read = ad7606_spi_reg_read,
.reg_write = ad7606_spi_reg_write,
.write_mask = ad7606_spi_write_mask,
.rd_wr_cmd = ad7616_spi_rd_wr_cmd,
.sw_mode_config = ad7616_sw_mode_config,
};
static int ad7606_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
const struct ad7606_bus_ops *bops;
switch (id->driver_data) {
case ID_AD7616:
bops = &ad7616_spi_bops;
break;
default:
bops = &ad7606_spi_bops;
break;
}
return ad7606_probe(&spi->dev, spi->irq, NULL,
id->name, id->driver_data,
&ad7606_spi_bops);
bops);
}
static const struct spi_device_id ad7606_id_table[] = {

View File

@ -1179,10 +1179,8 @@ static int at91_adc_probe(struct platform_device *pdev)
idev->info = &at91_adc_info;
st->irq = platform_get_irq(pdev, 0);
if (st->irq < 0) {
dev_err(&pdev->dev, "No IRQ ID is designated\n");
if (st->irq < 0)
return -ENODEV;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View File

@ -225,10 +225,8 @@ static int axp288_adc_probe(struct platform_device *pdev)
info = iio_priv(indio_dev);
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
if (info->irq < 0)
return info->irq;
}
platform_set_drvdata(pdev, indio_dev);
info->regmap = axp20x->regmap;
/*

View File

@ -540,11 +540,8 @@ static int iproc_adc_probe(struct platform_device *pdev)
}
adc_priv->irqno = platform_get_irq(pdev, 0);
if (adc_priv->irqno <= 0) {
dev_err(&pdev->dev, "platform_get_irq failed\n");
ret = -ENODEV;
return ret;
}
if (adc_priv->irqno <= 0)
return -ENODEV;
ret = regmap_update_bits(adc_priv->regmap, IPROC_REGCTL2,
IPROC_ADC_AUXIN_SCAN_ENA, 0);

View File

@ -337,10 +337,8 @@ static int da9150_gpadc_probe(struct platform_device *pdev)
init_completion(&gpadc->complete);
irq = platform_get_irq_byname(pdev, "GPADC");
if (irq < 0) {
dev_err(dev, "Failed to get IRQ: %d\n", irq);
if (irq < 0)
return irq;
}
ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq,
IRQF_ONESHOT, "GPADC", gpadc);

View File

@ -357,11 +357,8 @@ static int envelope_detector_probe(struct platform_device *pdev)
}
env->comp_irq = platform_get_irq_byname(pdev, "comp");
if (env->comp_irq < 0) {
if (env->comp_irq != -EPROBE_DEFER)
dev_err(dev, "failed to get compare interrupt\n");
if (env->comp_irq < 0)
return env->comp_irq;
}
ret = devm_request_irq(dev, env->comp_irq, envelope_detector_comp_isr,
0, "envelope-detector", env);

View File

@ -805,10 +805,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
if (irq < 0)
return irq;
}
info->irq = irq;
irq = platform_get_irq(pdev, 1);

View File

@ -340,7 +340,6 @@ static int mx25_gcq_probe(struct platform_device *pdev)
priv->irq = platform_get_irq(pdev, 0);
if (priv->irq <= 0) {
dev_err(dev, "Failed to get IRQ\n");
ret = priv->irq;
if (!ret)
ret = -ENXIO;

View File

@ -456,6 +456,11 @@ static irqreturn_t hi8435_trigger_handler(int irq, void *private)
return IRQ_HANDLED;
}
static void hi8435_triggered_event_cleanup(void *data)
{
iio_triggered_event_cleanup(data);
}
static int hi8435_probe(struct spi_device *spi)
{
struct iio_dev *idev;
@ -477,7 +482,7 @@ static int hi8435_probe(struct spi_device *spi)
hi8435_writeb(priv, HI8435_CTRL_REG, 0);
} else {
udelay(5);
gpiod_set_value(reset_gpio, 1);
gpiod_set_value_cansleep(reset_gpio, 1);
}
spi_set_drvdata(spi, idev);
@ -513,27 +518,13 @@ static int hi8435_probe(struct spi_device *spi)
if (ret)
return ret;
ret = iio_device_register(idev);
if (ret < 0) {
dev_err(&spi->dev, "unable to register device\n");
goto unregister_triggered_event;
}
ret = devm_add_action_or_reset(&spi->dev,
hi8435_triggered_event_cleanup,
idev);
if (ret)
return ret;
return 0;
unregister_triggered_event:
iio_triggered_event_cleanup(idev);
return ret;
}
static int hi8435_remove(struct spi_device *spi)
{
struct iio_dev *idev = spi_get_drvdata(spi);
iio_device_unregister(idev);
iio_triggered_event_cleanup(idev);
return 0;
return devm_iio_device_register(&spi->dev, idev);
}
static const struct of_device_id hi8435_dt_ids[] = {
@ -554,7 +545,6 @@ static struct spi_driver hi8435_driver = {
.of_match_table = of_match_ptr(hi8435_dt_ids),
},
.probe = hi8435_probe,
.remove = hi8435_remove,
.id_table = hi8435_id,
};
module_spi_driver(hi8435_driver);

View File

@ -492,10 +492,8 @@ static int imx7d_adc_probe(struct platform_device *pdev)
return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(dev, "No irq resource?\n");
if (irq < 0)
return irq;
}
info->clk = devm_clk_get(dev, "adc");
if (IS_ERR(info->clk)) {

View File

@ -172,10 +172,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev, "failed getting interrupt resource\n");
if (irq <= 0)
return -ENXIO;
}
retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
LPC32XXAD_NAME, st);

View File

@ -225,7 +225,6 @@ static int npcm_adc_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "failed getting interrupt resource\n");
ret = -EINVAL;
goto err_disable_clk;
}

View File

@ -244,10 +244,8 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
init_completion(&info->completion);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
if (irq < 0)
return irq;
}
ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
0, dev_name(&pdev->dev), info);

View File

@ -504,88 +504,85 @@ static void sc27xx_adc_free_hwlock(void *_data)
static int sc27xx_adc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct sc27xx_adc_data *sc27xx_data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*sc27xx_data));
indio_dev = devm_iio_device_alloc(dev, sizeof(*sc27xx_data));
if (!indio_dev)
return -ENOMEM;
sc27xx_data = iio_priv(indio_dev);
sc27xx_data->regmap = dev_get_regmap(pdev->dev.parent, NULL);
sc27xx_data->regmap = dev_get_regmap(dev->parent, NULL);
if (!sc27xx_data->regmap) {
dev_err(&pdev->dev, "failed to get ADC regmap\n");
dev_err(dev, "failed to get ADC regmap\n");
return -ENODEV;
}
ret = of_property_read_u32(np, "reg", &sc27xx_data->base);
if (ret) {
dev_err(&pdev->dev, "failed to get ADC base address\n");
dev_err(dev, "failed to get ADC base address\n");
return ret;
}
sc27xx_data->irq = platform_get_irq(pdev, 0);
if (sc27xx_data->irq < 0) {
dev_err(&pdev->dev, "failed to get ADC irq number\n");
if (sc27xx_data->irq < 0)
return sc27xx_data->irq;
}
ret = of_hwspin_lock_get_id(np, 0);
if (ret < 0) {
dev_err(&pdev->dev, "failed to get hwspinlock id\n");
dev_err(dev, "failed to get hwspinlock id\n");
return ret;
}
sc27xx_data->hwlock = hwspin_lock_request_specific(ret);
if (!sc27xx_data->hwlock) {
dev_err(&pdev->dev, "failed to request hwspinlock\n");
dev_err(dev, "failed to request hwspinlock\n");
return -ENXIO;
}
ret = devm_add_action(&pdev->dev, sc27xx_adc_free_hwlock,
ret = devm_add_action_or_reset(dev, sc27xx_adc_free_hwlock,
sc27xx_data->hwlock);
if (ret) {
sc27xx_adc_free_hwlock(sc27xx_data->hwlock);
dev_err(&pdev->dev, "failed to add hwspinlock action\n");
dev_err(dev, "failed to add hwspinlock action\n");
return ret;
}
init_completion(&sc27xx_data->completion);
sc27xx_data->dev = &pdev->dev;
sc27xx_data->dev = dev;
ret = sc27xx_adc_enable(sc27xx_data);
if (ret) {
dev_err(&pdev->dev, "failed to enable ADC module\n");
dev_err(dev, "failed to enable ADC module\n");
return ret;
}
ret = devm_add_action(&pdev->dev, sc27xx_adc_disable, sc27xx_data);
ret = devm_add_action_or_reset(dev, sc27xx_adc_disable, sc27xx_data);
if (ret) {
sc27xx_adc_disable(sc27xx_data);
dev_err(&pdev->dev, "failed to add ADC disable action\n");
dev_err(dev, "failed to add ADC disable action\n");
return ret;
}
ret = devm_request_threaded_irq(&pdev->dev, sc27xx_data->irq, NULL,
ret = devm_request_threaded_irq(dev, sc27xx_data->irq, NULL,
sc27xx_adc_isr, IRQF_ONESHOT,
pdev->name, sc27xx_data);
if (ret) {
dev_err(&pdev->dev, "failed to request ADC irq\n");
dev_err(dev, "failed to request ADC irq\n");
return ret;
}
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->dev.parent = dev;
indio_dev->name = dev_name(dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &sc27xx_info;
indio_dev->channels = sc27xx_channels;
indio_dev->num_channels = ARRAY_SIZE(sc27xx_channels);
ret = devm_iio_device_register(&pdev->dev, indio_dev);
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
dev_err(&pdev->dev, "could not register iio (ADC)");
dev_err(dev, "could not register iio (ADC)");
return ret;
}

View File

@ -301,7 +301,6 @@ static int spear_adc_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "failed getting interrupt resource\n");
ret = -EINVAL;
goto errout2;
}

View File

@ -14,9 +14,11 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdesc.h>
#include <linux/irqdomain.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@ -51,6 +53,17 @@
#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000
/* SYSCFG registers */
#define STM32MP1_SYSCFG_PMCSETR 0x04
#define STM32MP1_SYSCFG_PMCCLRR 0x44
/* SYSCFG bit fields */
#define STM32MP1_SYSCFG_ANASWVDD_MASK BIT(9)
/* SYSCFG capability flags */
#define HAS_VBOOSTER BIT(0)
#define HAS_ANASWVDD BIT(1)
/**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status register offset
@ -74,11 +87,13 @@ struct stm32_adc_priv;
* @regs: common registers for all instances
* @clk_sel: clock selection routine
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
* @has_syscfg: SYSCFG capability flags
*/
struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs *regs;
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
u32 max_clk_rate_hz;
unsigned int has_syscfg;
};
/**
@ -87,22 +102,32 @@ struct stm32_adc_priv_cfg {
* @domain: irq domain reference
* @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used
* @booster: booster supply reference
* @vdd: vdd supply reference
* @vdda: vdda analog supply reference
* @vref: regulator reference
* @vdd_uv: vdd supply voltage (microvolts)
* @vdda_uv: vdda supply voltage (microvolts)
* @cfg: compatible configuration data
* @common: common data for all ADC instances
* @ccr_bak: backup CCR in low power mode
* @syscfg: reference to syscon, system control registers
*/
struct stm32_adc_priv {
int irq[STM32_ADC_MAX_ADCS];
struct irq_domain *domain;
struct clk *aclk;
struct clk *bclk;
struct regulator *booster;
struct regulator *vdd;
struct regulator *vdda;
struct regulator *vref;
int vdd_uv;
int vdda_uv;
const struct stm32_adc_priv_cfg *cfg;
struct stm32_adc_common common;
u32 ccr_bak;
struct regmap *syscfg;
};
static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com)
@ -349,7 +374,6 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
*/
if (i && priv->irq[i] == -ENXIO)
continue;
dev_err(&pdev->dev, "failed to get irq\n");
return priv->irq[i];
}
@ -390,6 +414,82 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
}
}
static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv,
struct device *dev)
{
int ret;
/*
* On STM32H7 and STM32MP1, the ADC inputs are multiplexed with analog
* switches (via PCSEL) which have reduced performances when their
* supply is below 2.7V (vdda by default):
* - Voltage booster can be used, to get full ADC performances
* (increases power consumption).
* - Vdd can be used to supply them, if above 2.7V (STM32MP1 only).
*
* Recommended settings for ANASWVDD and EN_BOOSTER:
* - vdda < 2.7V but vdd > 2.7V: ANASWVDD = 1, EN_BOOSTER = 0 (stm32mp1)
* - vdda < 2.7V and vdd < 2.7V: ANASWVDD = 0, EN_BOOSTER = 1
* - vdda >= 2.7V: ANASWVDD = 0, EN_BOOSTER = 0 (default)
*/
if (priv->vdda_uv < 2700000) {
if (priv->syscfg && priv->vdd_uv > 2700000) {
ret = regulator_enable(priv->vdd);
if (ret < 0) {
dev_err(dev, "vdd enable failed %d\n", ret);
return ret;
}
ret = regmap_write(priv->syscfg,
STM32MP1_SYSCFG_PMCSETR,
STM32MP1_SYSCFG_ANASWVDD_MASK);
if (ret < 0) {
regulator_disable(priv->vdd);
dev_err(dev, "vdd select failed, %d\n", ret);
return ret;
}
dev_dbg(dev, "analog switches supplied by vdd\n");
return 0;
}
if (priv->booster) {
/*
* This is optional, as this is a trade-off between
* analog performance and power consumption.
*/
ret = regulator_enable(priv->booster);
if (ret < 0) {
dev_err(dev, "booster enable failed %d\n", ret);
return ret;
}
dev_dbg(dev, "analog switches supplied by booster\n");
return 0;
}
}
/* Fallback using vdda (default), nothing to do */
dev_dbg(dev, "analog switches supplied by vdda (%d uV)\n",
priv->vdda_uv);
return 0;
}
static void stm32_adc_core_switches_supply_dis(struct stm32_adc_priv *priv)
{
if (priv->vdda_uv < 2700000) {
if (priv->syscfg && priv->vdd_uv > 2700000) {
regmap_write(priv->syscfg, STM32MP1_SYSCFG_PMCCLRR,
STM32MP1_SYSCFG_ANASWVDD_MASK);
regulator_disable(priv->vdd);
return;
}
if (priv->booster)
regulator_disable(priv->booster);
}
}
static int stm32_adc_core_hw_start(struct device *dev)
{
struct stm32_adc_common *common = dev_get_drvdata(dev);
@ -402,10 +502,21 @@ static int stm32_adc_core_hw_start(struct device *dev)
return ret;
}
ret = regulator_get_voltage(priv->vdda);
if (ret < 0) {
dev_err(dev, "vdda get voltage failed, %d\n", ret);
goto err_vdda_disable;
}
priv->vdda_uv = ret;
ret = stm32_adc_core_switches_supply_en(priv, dev);
if (ret < 0)
goto err_vdda_disable;
ret = regulator_enable(priv->vref);
if (ret < 0) {
dev_err(dev, "vref enable failed\n");
goto err_vdda_disable;
goto err_switches_dis;
}
if (priv->bclk) {
@ -433,6 +544,8 @@ static int stm32_adc_core_hw_start(struct device *dev)
clk_disable_unprepare(priv->bclk);
err_regulator_disable:
regulator_disable(priv->vref);
err_switches_dis:
stm32_adc_core_switches_supply_dis(priv);
err_vdda_disable:
regulator_disable(priv->vdda);
@ -451,9 +564,80 @@ static void stm32_adc_core_hw_stop(struct device *dev)
if (priv->bclk)
clk_disable_unprepare(priv->bclk);
regulator_disable(priv->vref);
stm32_adc_core_switches_supply_dis(priv);
regulator_disable(priv->vdda);
}
static int stm32_adc_core_switches_probe(struct device *dev,
struct stm32_adc_priv *priv)
{
struct device_node *np = dev->of_node;
int ret;
/* Analog switches supply can be controlled by syscfg (optional) */
priv->syscfg = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
if (IS_ERR(priv->syscfg)) {
ret = PTR_ERR(priv->syscfg);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Can't probe syscfg: %d\n", ret);
return ret;
}
priv->syscfg = NULL;
}
/* Booster can be used to supply analog switches (optional) */
if (priv->cfg->has_syscfg & HAS_VBOOSTER &&
of_property_read_bool(np, "booster-supply")) {
priv->booster = devm_regulator_get_optional(dev, "booster");
if (IS_ERR(priv->booster)) {
ret = PTR_ERR(priv->booster);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "can't get booster %d\n",
ret);
return ret;
}
priv->booster = NULL;
}
}
/* Vdd can be used to supply analog switches (optional) */
if (priv->cfg->has_syscfg & HAS_ANASWVDD &&
of_property_read_bool(np, "vdd-supply")) {
priv->vdd = devm_regulator_get_optional(dev, "vdd");
if (IS_ERR(priv->vdd)) {
ret = PTR_ERR(priv->vdd);
if (ret != -ENODEV) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "can't get vdd %d\n", ret);
return ret;
}
priv->vdd = NULL;
}
}
if (priv->vdd) {
ret = regulator_enable(priv->vdd);
if (ret < 0) {
dev_err(dev, "vdd enable failed %d\n", ret);
return ret;
}
ret = regulator_get_voltage(priv->vdd);
if (ret < 0) {
dev_err(dev, "vdd get voltage failed %d\n", ret);
regulator_disable(priv->vdd);
return ret;
}
priv->vdd_uv = ret;
regulator_disable(priv->vdd);
}
return 0;
}
static int stm32_adc_probe(struct platform_device *pdev)
{
struct stm32_adc_priv *priv;
@ -514,6 +698,10 @@ static int stm32_adc_probe(struct platform_device *pdev)
priv->bclk = NULL;
}
ret = stm32_adc_core_switches_probe(dev, priv);
if (ret)
return ret;
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS);
@ -611,12 +799,14 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel,
.max_clk_rate_hz = 36000000,
.has_syscfg = HAS_VBOOSTER,
};
static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel,
.max_clk_rate_hz = 40000000,
.has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD,
};
static const struct of_device_id stm32_adc_of_match[] = {

View File

@ -1919,10 +1919,8 @@ static int stm32_adc_probe(struct platform_device *pdev)
}
adc->irq = platform_get_irq(pdev, 0);
if (adc->irq < 0) {
dev_err(&pdev->dev, "failed to get irq\n");
if (adc->irq < 0)
return adc->irq;
}
ret = devm_request_irq(&pdev->dev, adc->irq, stm32_adc_isr,
0, pdev->name, adc);

View File

@ -1601,11 +1601,8 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
* So IRQ associated to filter instance 0 is dedicated to the Filter 0.
*/
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
if (irq != -EPROBE_DEFER)
dev_err(dev, "Failed to get IRQ: %d\n", irq);
if (irq < 0)
return irq;
}
ret = devm_request_irq(dev, irq, stm32_dfsdm_irq,
0, pdev->name, adc);

View File

@ -460,10 +460,8 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name,
atomic_set(atomic, 1);
ret = platform_get_irq_byname(pdev, name);
if (ret < 0) {
dev_err(&pdev->dev, "no %s interrupt registered\n", name);
if (ret < 0)
return ret;
}
ret = regmap_irq_get_virq(mfd_dev->regmap_irqc, ret);
if (ret < 0) {

View File

@ -905,10 +905,8 @@ static int twl6030_gpadc_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq\n");
if (irq < 0)
return irq;
}
ret = devm_request_threaded_irq(dev, irq, NULL,
twl6030_gpadc_irq_handler,

View File

@ -821,10 +821,8 @@ static int vf610_adc_probe(struct platform_device *pdev)
return PTR_ERR(info->regs);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
if (irq < 0)
return irq;
}
ret = devm_request_irq(info->dev, irq,
vf610_adc_isr, 0,

View File

@ -63,10 +63,35 @@ static int cros_ec_sensors_read(struct iio_dev *indio_dev,
/* Save values */
for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.calib[i] =
st->core.calib[i].offset =
st->core.resp->sensor_offset.offset[i];
ret = IIO_VAL_INT;
*val = st->core.calib[idx];
*val = st->core.calib[idx].offset;
break;
case IIO_CHAN_INFO_CALIBSCALE:
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
st->core.param.sensor_offset.flags = 0;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
if (ret == -EPROTO) {
/* Reading calibscale is not supported on older EC. */
*val = 1;
*val2 = 0;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
} else if (ret) {
break;
}
/* Save values */
for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.calib[i].scale =
st->core.resp->sensor_scale.scale[i];
*val = st->core.calib[idx].scale >> 15;
*val2 = ((st->core.calib[idx].scale & 0x7FFF) * 1000000LL) /
MOTION_SENSE_DEFAULT_SCALE;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
case IIO_CHAN_INFO_SCALE:
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
@ -134,7 +159,7 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
st->core.calib[idx] = val;
st->core.calib[idx].offset = val;
/* Send to EC for each axis, even if not complete */
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
@ -142,10 +167,25 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev,
MOTION_SENSE_SET_OFFSET;
for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.param.sensor_offset.offset[i] =
st->core.calib[i];
st->core.calib[i].offset;
st->core.param.sensor_offset.temp =
EC_MOTION_SENSE_INVALID_CALIB_TEMP;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
break;
case IIO_CHAN_INFO_CALIBSCALE:
st->core.calib[idx].scale = val;
/* Send to EC for each axis, even if not complete */
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
st->core.param.sensor_offset.flags =
MOTION_SENSE_SET_OFFSET;
for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.param.sensor_scale.scale[i] =
st->core.calib[i].scale;
st->core.param.sensor_scale.temp =
EC_MOTION_SENSE_INVALID_CALIB_TEMP;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
break;
case IIO_CHAN_INFO_SCALE:
@ -175,6 +215,7 @@ static int cros_ec_sensors_write(struct iio_dev *indio_dev,
static const struct iio_info ec_sensors_info = {
.read_raw = &cros_ec_sensors_read,
.write_raw = &cros_ec_sensors_write,
.read_avail = &cros_ec_sensors_core_read_avail,
};
static int cros_ec_sensors_probe(struct platform_device *pdev)
@ -206,11 +247,14 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
/* Common part */
channel->info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_CALIBBIAS);
BIT(IIO_CHAN_INFO_CALIBBIAS) |
BIT(IIO_CHAN_INFO_CALIBSCALE);
channel->info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_FREQUENCY) |
BIT(IIO_CHAN_INFO_SAMP_FREQ);
channel->info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_SAMP_FREQ);
channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
channel->scan_index = i;

View File

@ -25,6 +25,62 @@ static char *cros_ec_loc[] = {
[MOTIONSENSE_LOC_MAX] = "unknown",
};
static int cros_ec_get_host_cmd_version_mask(struct cros_ec_device *ec_dev,
u16 cmd_offset, u16 cmd, u32 *mask)
{
int ret;
struct {
struct cros_ec_command msg;
union {
struct ec_params_get_cmd_versions params;
struct ec_response_get_cmd_versions resp;
};
} __packed buf = {
.msg = {
.command = EC_CMD_GET_CMD_VERSIONS + cmd_offset,
.insize = sizeof(struct ec_response_get_cmd_versions),
.outsize = sizeof(struct ec_params_get_cmd_versions)
},
.params = {.cmd = cmd}
};
ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg);
if (ret >= 0)
*mask = buf.resp.version_mask;
return ret;
}
static void get_default_min_max_freq(enum motionsensor_type type,
u32 *min_freq,
u32 *max_freq)
{
switch (type) {
case MOTIONSENSE_TYPE_ACCEL:
case MOTIONSENSE_TYPE_GYRO:
*min_freq = 12500;
*max_freq = 100000;
break;
case MOTIONSENSE_TYPE_MAG:
*min_freq = 5000;
*max_freq = 25000;
break;
case MOTIONSENSE_TYPE_PROX:
case MOTIONSENSE_TYPE_LIGHT:
*min_freq = 100;
*max_freq = 50000;
break;
case MOTIONSENSE_TYPE_BARO:
*min_freq = 250;
*max_freq = 20000;
break;
case MOTIONSENSE_TYPE_ACTIVITY:
default:
*min_freq = 0;
*max_freq = 0;
break;
}
}
int cros_ec_sensors_core_init(struct platform_device *pdev,
struct iio_dev *indio_dev,
bool physical_device)
@ -33,6 +89,8 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev);
u32 ver_mask;
int ret;
platform_set_drvdata(pdev, indio_dev);
@ -47,8 +105,15 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
mutex_init(&state->cmd_lock);
ret = cros_ec_get_host_cmd_version_mask(state->ec,
ec->cmd_offset,
EC_CMD_MOTION_SENSE_CMD,
&ver_mask);
if (ret < 0)
return ret;
/* Set up the host command structure. */
state->msg->version = 2;
state->msg->version = fls(ver_mask) - 1;
state->msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset;
state->msg->outsize = sizeof(struct ec_params_motion_sense);
@ -60,12 +125,29 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
state->param.cmd = MOTIONSENSE_CMD_INFO;
state->param.info.sensor_num = sensor_platform->sensor_num;
if (cros_ec_motion_send_host_cmd(state, 0)) {
ret = cros_ec_motion_send_host_cmd(state, 0);
if (ret) {
dev_warn(dev, "Can not access sensor info\n");
return -EIO;
return ret;
}
state->type = state->resp->info.type;
state->loc = state->resp->info.location;
/* Set sign vector, only used for backward compatibility. */
memset(state->sign, 1, CROS_EC_SENSOR_MAX_AXIS);
/* 0 is a correct value used to stop the device */
state->frequencies[0] = 0;
if (state->msg->version < 3) {
get_default_min_max_freq(state->resp->info.type,
&state->frequencies[1],
&state->frequencies[2]);
} else {
state->frequencies[1] =
state->resp->info_3.min_frequency;
state->frequencies[2] =
state->resp->info_3.max_frequency;
}
}
return 0;
@ -86,7 +168,7 @@ int cros_ec_motion_send_host_cmd(struct cros_ec_sensors_core_state *state,
ret = cros_ec_cmd_xfer_status(state->ec, state->msg);
if (ret < 0)
return -EIO;
return ret;
if (ret &&
state->resp != (struct ec_response_motion_sense *)state->msg->data)
@ -118,7 +200,7 @@ static ssize_t cros_ec_sensors_calibrate(struct iio_dev *indio_dev,
} else {
/* Save values */
for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->calib[i] = st->resp->perform_calib.offset[i];
st->calib[i].offset = st->resp->perform_calib.offset[i];
}
mutex_unlock(&st->cmd_lock);
@ -268,6 +350,7 @@ static int cros_ec_sensors_read_data_unsafe(struct iio_dev *indio_dev,
if (ret < 0)
return ret;
*data *= st->sign[i];
data++;
}
@ -396,7 +479,7 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret = IIO_VAL_INT;
int ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
@ -404,22 +487,27 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
st->param.ec_rate.data =
EC_MOTION_SENSE_NO_VALUE;
if (cros_ec_motion_send_host_cmd(st, 0))
ret = -EIO;
else
*val = st->resp->ec_rate.ret;
ret = cros_ec_motion_send_host_cmd(st, 0);
if (ret)
break;
*val = st->resp->ec_rate.ret;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_FREQUENCY:
st->param.cmd = MOTIONSENSE_CMD_SENSOR_ODR;
st->param.sensor_odr.data =
EC_MOTION_SENSE_NO_VALUE;
if (cros_ec_motion_send_host_cmd(st, 0))
ret = -EIO;
else
*val = st->resp->sensor_odr.ret;
ret = cros_ec_motion_send_host_cmd(st, 0);
if (ret)
break;
*val = st->resp->sensor_odr.ret;
ret = IIO_VAL_INT;
break;
default:
ret = -EINVAL;
break;
}
@ -427,11 +515,32 @@ int cros_ec_sensors_core_read(struct cros_ec_sensors_core_state *st,
}
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read);
int cros_ec_sensors_core_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals,
int *type,
int *length,
long mask)
{
struct cros_ec_sensors_core_state *state = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
*length = ARRAY_SIZE(state->frequencies);
*vals = (const int *)&state->frequencies;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(cros_ec_sensors_core_read_avail);
int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int ret = 0;
int ret;
switch (mask) {
case IIO_CHAN_INFO_FREQUENCY:
@ -441,17 +550,16 @@ int cros_ec_sensors_core_write(struct cros_ec_sensors_core_state *st,
/* Always roundup, so caller gets at least what it asks for. */
st->param.sensor_odr.roundup = 1;
if (cros_ec_motion_send_host_cmd(st, 0))
ret = -EIO;
ret = cros_ec_motion_send_host_cmd(st, 0);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
st->param.cmd = MOTIONSENSE_CMD_EC_RATE;
st->param.ec_rate.data = val;
if (cros_ec_motion_send_host_cmd(st, 0))
ret = -EIO;
else
st->curr_sampl_freq = val;
ret = cros_ec_motion_send_host_cmd(st, 0);
if (ret)
break;
st->curr_sampl_freq = val;
break;
default:
ret = -EINVAL;

View File

@ -17,15 +17,16 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/irqreturn.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors.h>
static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
{
int i;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int num_data_channels = sdata->num_data_channels;
int i;
for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) {
const struct iio_chan_spec *channel = &indio_dev->channels[i];
@ -36,11 +37,8 @@ static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
channel->scan_type.storagebits >> 3;
buf = PTR_ALIGN(buf, storage_bytes);
if (sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
channel->address,
bytes_to_read, buf,
sdata->multiread_bit) <
bytes_to_read)
if (regmap_bulk_read(sdata->regmap, channel->address,
buf, bytes_to_read) < 0)
return -EIO;
/* Advance the buffer pointer */

View File

@ -15,6 +15,7 @@
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <asm/unaligned.h>
#include <linux/iio/common/st_sensors.h>
@ -28,19 +29,10 @@ static inline u32 st_sensors_get_unaligned_le24(const u8 *p)
int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
u8 reg_addr, u8 mask, u8 data)
{
int err;
u8 new_data;
struct st_sensor_data *sdata = iio_priv(indio_dev);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
if (err < 0)
goto st_sensors_write_data_with_mask_error;
new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
st_sensors_write_data_with_mask_error:
return err;
return regmap_update_bits(sdata->regmap,
reg_addr, mask, data << __ffs(mask));
}
int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
@ -48,19 +40,15 @@ int st_sensors_debugfs_reg_access(struct iio_dev *indio_dev,
unsigned *readval)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
u8 readdata;
int err;
if (!readval)
return sdata->tf->write_byte(&sdata->tb, sdata->dev,
(u8)reg, (u8)writeval);
return regmap_write(sdata->regmap, reg, writeval);
err = sdata->tf->read_byte(&sdata->tb, sdata->dev, (u8)reg, &readdata);
err = regmap_read(sdata->regmap, reg, readval);
if (err < 0)
return err;
*readval = (unsigned)readdata;
return 0;
}
EXPORT_SYMBOL(st_sensors_debugfs_reg_access);
@ -545,7 +533,7 @@ int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
struct iio_chan_spec const *ch, int *data)
struct iio_chan_spec const *ch, int *data)
{
int err;
u8 *outdata;
@ -554,13 +542,12 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
ch->scan_type.shift, 8);
outdata = kmalloc(byte_for_channel, GFP_KERNEL);
outdata = kmalloc(byte_for_channel, GFP_DMA | GFP_KERNEL);
if (!outdata)
return -ENOMEM;
err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
ch->address, byte_for_channel,
outdata, sdata->multiread_bit);
err = regmap_bulk_read(sdata->regmap, ch->address,
outdata, byte_for_channel);
if (err < 0)
goto st_sensors_free_memory;
@ -608,69 +595,55 @@ int st_sensors_read_info_raw(struct iio_dev *indio_dev,
}
EXPORT_SYMBOL(st_sensors_read_info_raw);
static int st_sensors_init_interface_mode(struct iio_dev *indio_dev,
const struct st_sensor_settings *sensor_settings)
/*
* st_sensors_get_settings_index() - get index of the sensor settings for a
* specific device from list of settings
* @name: device name buffer reference.
* @list: sensor settings list.
* @list_length: length of sensor settings list.
*
* Return: non negative number on success (valid index),
* negative error code otherwise.
*/
int st_sensors_get_settings_index(const char *name,
const struct st_sensor_settings *list,
const int list_length)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
struct device_node *np = sdata->dev->of_node;
struct st_sensors_platform_data *pdata;
int i, n;
pdata = (struct st_sensors_platform_data *)sdata->dev->platform_data;
if (((np && of_property_read_bool(np, "spi-3wire")) ||
(pdata && pdata->spi_3wire)) && sensor_settings->sim.addr) {
int err;
err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
sensor_settings->sim.addr,
sensor_settings->sim.value);
if (err < 0) {
dev_err(&indio_dev->dev,
"failed to init interface mode\n");
return err;
}
}
return 0;
}
int st_sensors_check_device_support(struct iio_dev *indio_dev,
int num_sensors_list,
const struct st_sensor_settings *sensor_settings)
{
int i, n, err = 0;
u8 wai;
struct st_sensor_data *sdata = iio_priv(indio_dev);
for (i = 0; i < num_sensors_list; i++) {
for (i = 0; i < list_length; i++) {
for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) {
if (strcmp(indio_dev->name,
sensor_settings[i].sensors_supported[n]) == 0) {
break;
}
if (strcmp(name, list[i].sensors_supported[n]) == 0)
return i;
}
if (n < ST_SENSORS_MAX_4WAI)
break;
}
if (i == num_sensors_list) {
dev_err(&indio_dev->dev, "device name %s not recognized.\n",
indio_dev->name);
return -ENODEV;
}
err = st_sensors_init_interface_mode(indio_dev, &sensor_settings[i]);
if (err < 0)
return err;
return -ENODEV;
}
EXPORT_SYMBOL(st_sensors_get_settings_index);
if (sensor_settings[i].wai_addr) {
err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sensor_settings[i].wai_addr, &wai);
/*
* st_sensors_verify_id() - verify sensor ID (WhoAmI) is matching with the
* expected value
* @indio_dev: IIO device reference.
*
* Return: 0 on success (valid sensor ID), else a negative error code.
*/
int st_sensors_verify_id(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
int wai, err;
if (sdata->sensor_settings->wai_addr) {
err = regmap_read(sdata->regmap,
sdata->sensor_settings->wai_addr, &wai);
if (err < 0) {
dev_err(&indio_dev->dev,
"failed to read Who-Am-I register.\n");
return err;
}
if (sensor_settings[i].wai != wai) {
if (sdata->sensor_settings->wai != wai) {
dev_err(&indio_dev->dev,
"%s: WhoAmI mismatch (0x%x).\n",
indio_dev->name, wai);
@ -678,12 +651,9 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev,
}
}
sdata->sensor_settings =
(struct st_sensor_settings *)&sensor_settings[i];
return i;
return 0;
}
EXPORT_SYMBOL(st_sensors_check_device_support);
EXPORT_SYMBOL(st_sensors_verify_id);
ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
struct device_attribute *attr, char *buf)

View File

@ -13,68 +13,58 @@
#include <linux/iio/iio.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_i2c.h>
#define ST_SENSORS_I2C_MULTIREAD 0x80
static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return to_i2c_client(sdata->dev)->irq;
}
static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 *res_byte)
{
int err;
err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
if (err < 0)
goto st_accel_i2c_read_byte_error;
*res_byte = err & 0xff;
st_accel_i2c_read_byte_error:
return err < 0 ? err : 0;
}
static int st_sensors_i2c_read_multiple_byte(
struct st_sensor_transfer_buffer *tb, struct device *dev,
u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
if (multiread_bit)
reg_addr |= ST_SENSORS_I2C_MULTIREAD;
return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev),
reg_addr, len, data);
}
static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
}
static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
.read_byte = st_sensors_i2c_read_byte,
.write_byte = st_sensors_i2c_write_byte,
.read_multiple_byte = st_sensors_i2c_read_multiple_byte,
static const struct regmap_config st_sensors_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
void st_sensors_i2c_configure(struct iio_dev *indio_dev,
struct i2c_client *client, struct st_sensor_data *sdata)
static const struct regmap_config st_sensors_i2c_regmap_multiread_bit_config = {
.reg_bits = 8,
.val_bits = 8,
.read_flag_mask = ST_SENSORS_I2C_MULTIREAD,
};
/*
* st_sensors_i2c_configure() - configure I2C interface
* @indio_dev: IIO device reference.
* @client: i2c client reference.
*
* Return: 0 on success, else a negative error code.
*/
int st_sensors_i2c_configure(struct iio_dev *indio_dev,
struct i2c_client *client)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
const struct regmap_config *config;
if (sdata->sensor_settings->multi_read_bit)
config = &st_sensors_i2c_regmap_multiread_bit_config;
else
config = &st_sensors_i2c_regmap_config;
sdata->regmap = devm_regmap_init_i2c(client, config);
if (IS_ERR(sdata->regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap (%d)\n",
(int)PTR_ERR(sdata->regmap));
return PTR_ERR(sdata->regmap);
}
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = client->name;
sdata->dev = &client->dev;
sdata->tf = &st_sensors_tf_i2c;
sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
sdata->irq = client->irq;
return 0;
}
EXPORT_SYMBOL(st_sensors_i2c_configure);

View File

@ -11,108 +11,108 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors_spi.h>
#include "st_sensors_core.h"
#define ST_SENSORS_SPI_MULTIREAD 0xc0
#define ST_SENSORS_SPI_READ 0x80
static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
return to_spi_device(sdata->dev)->irq;
}
static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
int err;
struct spi_transfer xfers[] = {
{
.tx_buf = tb->tx_buf,
.bits_per_word = 8,
.len = 1,
},
{
.rx_buf = tb->rx_buf,
.bits_per_word = 8,
.len = len,
}
};
mutex_lock(&tb->buf_lock);
if ((multiread_bit) && (len > 1))
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
else
tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
err = spi_sync_transfer(to_spi_device(dev), xfers, ARRAY_SIZE(xfers));
if (err)
goto acc_spi_read_error;
memcpy(data, tb->rx_buf, len);
mutex_unlock(&tb->buf_lock);
return len;
acc_spi_read_error:
mutex_unlock(&tb->buf_lock);
return err;
}
static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 *res_byte)
{
return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
}
static int st_sensors_spi_read_multiple_byte(
struct st_sensor_transfer_buffer *tb, struct device *dev,
u8 reg_addr, int len, u8 *data, bool multiread_bit)
{
return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
}
static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
struct device *dev, u8 reg_addr, u8 data)
{
int err;
struct spi_transfer xfers = {
.tx_buf = tb->tx_buf,
.bits_per_word = 8,
.len = 2,
};
mutex_lock(&tb->buf_lock);
tb->tx_buf[0] = reg_addr;
tb->tx_buf[1] = data;
err = spi_sync_transfer(to_spi_device(dev), &xfers, 1);
mutex_unlock(&tb->buf_lock);
return err;
}
static const struct st_sensor_transfer_function st_sensors_tf_spi = {
.read_byte = st_sensors_spi_read_byte,
.write_byte = st_sensors_spi_write_byte,
.read_multiple_byte = st_sensors_spi_read_multiple_byte,
static const struct regmap_config st_sensors_spi_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
void st_sensors_spi_configure(struct iio_dev *indio_dev,
struct spi_device *spi, struct st_sensor_data *sdata)
static const struct regmap_config st_sensors_spi_regmap_multiread_bit_config = {
.reg_bits = 8,
.val_bits = 8,
.read_flag_mask = ST_SENSORS_SPI_MULTIREAD,
};
/*
* st_sensors_is_spi_3_wire() - check if SPI 3-wire mode has been selected
* @spi: spi device reference.
*
* Return: true if SPI 3-wire mode is selected, false otherwise.
*/
static bool st_sensors_is_spi_3_wire(struct spi_device *spi)
{
struct device_node *np = spi->dev.of_node;
struct st_sensors_platform_data *pdata;
pdata = (struct st_sensors_platform_data *)spi->dev.platform_data;
if ((np && of_property_read_bool(np, "spi-3wire")) ||
(pdata && pdata->spi_3wire)) {
return true;
}
return false;
}
/*
* st_sensors_configure_spi_3_wire() - configure SPI 3-wire if needed
* @spi: spi device reference.
* @settings: sensor specific settings reference.
*
* Return: 0 on success, else a negative error code.
*/
static int st_sensors_configure_spi_3_wire(struct spi_device *spi,
struct st_sensor_settings *settings)
{
if (settings->sim.addr) {
u8 buffer[] = {
settings->sim.addr,
settings->sim.value
};
return spi_write(spi, buffer, 2);
}
return 0;
}
/*
* st_sensors_spi_configure() - configure SPI interface
* @indio_dev: IIO device reference.
* @spi: spi device reference.
*
* Return: 0 on success, else a negative error code.
*/
int st_sensors_spi_configure(struct iio_dev *indio_dev,
struct spi_device *spi)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
const struct regmap_config *config;
int err;
if (st_sensors_is_spi_3_wire(spi)) {
err = st_sensors_configure_spi_3_wire(spi,
sdata->sensor_settings);
if (err < 0)
return err;
}
if (sdata->sensor_settings->multi_read_bit)
config = &st_sensors_spi_regmap_multiread_bit_config;
else
config = &st_sensors_spi_regmap_config;
sdata->regmap = devm_regmap_init_spi(spi, config);
if (IS_ERR(sdata->regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap (%d)\n",
(int)PTR_ERR(sdata->regmap));
return PTR_ERR(sdata->regmap);
}
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi->modalias;
sdata->dev = &spi->dev;
sdata->tf = &st_sensors_tf_spi;
sdata->get_irq_data_ready = st_sensors_spi_get_irq;
sdata->irq = spi->irq;
return 0;
}
EXPORT_SYMBOL(st_sensors_spi_configure);

View File

@ -13,6 +13,7 @@
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/iio/common/st_sensors.h>
#include "st_sensors_core.h"
@ -26,8 +27,7 @@
static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
struct st_sensor_data *sdata)
{
u8 status;
int ret;
int ret, status;
/* How would I know if I can't check it? */
if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr)
@ -37,9 +37,9 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
if (!indio_dev->active_scan_mask)
return 0;
ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sdata->sensor_settings->drdy_irq.stat_drdy.addr,
&status);
ret = regmap_read(sdata->regmap,
sdata->sensor_settings->drdy_irq.stat_drdy.addr,
&status);
if (ret < 0) {
dev_err(sdata->dev,
"error checking samples available\n");
@ -121,9 +121,9 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p)
int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
const struct iio_trigger_ops *trigger_ops)
{
int err, irq;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned long irq_trig;
int err;
sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
if (sdata->trig == NULL) {
@ -135,8 +135,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev;
irq = sdata->get_irq_data_ready(indio_dev);
irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
irq_trig = irqd_get_trigger_type(irq_get_irq_data(sdata->irq));
/*
* If the IRQ is triggered on falling edge, we need to mark the
* interrupt as active low, if the hardware supports this.
@ -206,12 +205,12 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
sdata->sensor_settings->drdy_irq.stat_drdy.addr)
irq_trig |= IRQF_SHARED;
err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
st_sensors_irq_handler,
st_sensors_irq_thread,
irq_trig,
sdata->trig->name,
sdata->trig);
err = request_threaded_irq(sdata->irq,
st_sensors_irq_handler,
st_sensors_irq_thread,
irq_trig,
sdata->trig->name,
sdata->trig);
if (err) {
dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
goto iio_trigger_free;
@ -227,7 +226,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
return 0;
iio_trigger_register_error:
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
free_irq(sdata->irq, sdata->trig);
iio_trigger_free:
iio_trigger_free(sdata->trig);
return err;
@ -239,7 +238,7 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
struct st_sensor_data *sdata = iio_priv(indio_dev);
iio_trigger_unregister(sdata->trig);
free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
free_irq(sdata->irq, sdata->trig);
iio_trigger_free(sdata->trig);
}
EXPORT_SYMBOL(st_sensors_deallocate_trigger);

View File

@ -32,6 +32,7 @@ static const struct st_sensors_platform_data gyro_pdata = {
.drdy_int_pin = 2,
};
const struct st_sensor_settings *st_gyro_get_settings(const char *name);
int st_gyro_common_probe(struct iio_dev *indio_dev);
void st_gyro_common_remove(struct iio_dev *indio_dev);

View File

@ -29,61 +29,51 @@ int st_gyro_trig_set_state(struct iio_trigger *trig, bool state)
return st_sensors_set_dataready_irq(indio_dev, state);
}
static int st_gyro_buffer_preenable(struct iio_dev *indio_dev)
{
return st_sensors_set_enable(indio_dev, true);
}
static int st_gyro_buffer_postenable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *gdata = iio_priv(indio_dev);
gdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (gdata->buffer_data == NULL) {
err = -ENOMEM;
goto allocate_memory_error;
}
err = st_sensors_set_axis_enable(indio_dev,
(u8)indio_dev->active_scan_mask[0]);
if (err < 0)
goto st_gyro_buffer_postenable_error;
err = iio_triggered_buffer_postenable(indio_dev);
if (err < 0)
goto st_gyro_buffer_postenable_error;
return err;
return err;
err = st_sensors_set_axis_enable(indio_dev,
(u8)indio_dev->active_scan_mask[0]);
if (err < 0)
goto st_gyro_buffer_predisable;
st_gyro_buffer_postenable_error:
kfree(gdata->buffer_data);
allocate_memory_error:
err = st_sensors_set_enable(indio_dev, true);
if (err < 0)
goto st_gyro_buffer_enable_all_axis;
return 0;
st_gyro_buffer_enable_all_axis:
st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
st_gyro_buffer_predisable:
iio_triggered_buffer_predisable(indio_dev);
return err;
}
static int st_gyro_buffer_predisable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *gdata = iio_priv(indio_dev);
err = iio_triggered_buffer_predisable(indio_dev);
if (err < 0)
goto st_gyro_buffer_predisable_error;
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
if (err < 0)
goto st_gyro_buffer_predisable_error;
int err, err2;
err = st_sensors_set_enable(indio_dev, false);
if (err < 0)
goto st_gyro_buffer_predisable;
err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
st_gyro_buffer_predisable:
err2 = iio_triggered_buffer_predisable(indio_dev);
if (!err)
err = err2;
st_gyro_buffer_predisable_error:
kfree(gdata->buffer_data);
return err;
}
static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = {
.preenable = &st_gyro_buffer_preenable,
.postenable = &st_gyro_buffer_postenable,
.predisable = &st_gyro_buffer_predisable,
};

View File

@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
@ -368,28 +367,41 @@ static const struct iio_trigger_ops st_gyro_trigger_ops = {
#define ST_GYRO_TRIGGER_OPS NULL
#endif
/*
* st_gyro_get_settings() - get sensor settings from device name
* @name: device name buffer reference.
*
* Return: valid reference on success, NULL otherwise.
*/
const struct st_sensor_settings *st_gyro_get_settings(const char *name)
{
int index = st_sensors_get_settings_index(name,
st_gyro_sensors_settings,
ARRAY_SIZE(st_gyro_sensors_settings));
if (index < 0)
return NULL;
return &st_gyro_sensors_settings[index];
}
EXPORT_SYMBOL(st_gyro_get_settings);
int st_gyro_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *gdata = iio_priv(indio_dev);
int irq = gdata->get_irq_data_ready(indio_dev);
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &gyro_info;
mutex_init(&gdata->tb.buf_lock);
err = st_sensors_power_enable(indio_dev);
if (err)
return err;
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_gyro_sensors_settings),
st_gyro_sensors_settings);
err = st_sensors_verify_id(indio_dev);
if (err < 0)
goto st_gyro_power_off;
gdata->num_data_channels = ST_GYRO_NUMBER_DATA_CHANNELS;
gdata->multiread_bit = gdata->sensor_settings->multi_read_bit;
indio_dev->channels = gdata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
@ -406,7 +418,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
if (err < 0)
goto st_gyro_power_off;
if (irq > 0) {
if (gdata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
ST_GYRO_TRIGGER_OPS);
if (err < 0)
@ -423,7 +435,7 @@ int st_gyro_common_probe(struct iio_dev *indio_dev)
return 0;
st_gyro_device_register_error:
if (irq > 0)
if (gdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_gyro_probe_trigger_error:
st_gyro_deallocate_ring(indio_dev);
@ -441,7 +453,7 @@ void st_gyro_common_remove(struct iio_dev *indio_dev)
st_sensors_power_disable(indio_dev);
iio_device_unregister(indio_dev);
if (gdata->get_irq_data_ready(indio_dev) > 0)
if (gdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_gyro_deallocate_ring(indio_dev);

View File

@ -63,21 +63,33 @@ MODULE_DEVICE_TABLE(of, st_gyro_of_match);
#endif
static int st_gyro_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
const struct st_sensor_settings *settings;
struct st_sensor_data *gdata;
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&client->dev, st_gyro_of_match,
client->name, sizeof(client->name));
settings = st_gyro_get_settings(client->name);
if (!settings) {
dev_err(&client->dev, "device name %s not recognized.\n",
client->name);
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*gdata));
if (!indio_dev)
return -ENOMEM;
gdata = iio_priv(indio_dev);
st_sensors_of_name_probe(&client->dev, st_gyro_of_match,
client->name, sizeof(client->name));
gdata->sensor_settings = (struct st_sensor_settings *)settings;
st_sensors_i2c_configure(indio_dev, client, gdata);
err = st_sensors_i2c_configure(indio_dev, client);
if (err < 0)
return err;
err = st_gyro_common_probe(indio_dev);
if (err < 0)

View File

@ -69,19 +69,31 @@ MODULE_DEVICE_TABLE(of, st_gyro_of_match);
static int st_gyro_spi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
const struct st_sensor_settings *settings;
struct st_sensor_data *gdata;
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&spi->dev, st_gyro_of_match,
spi->modalias, sizeof(spi->modalias));
settings = st_gyro_get_settings(spi->modalias);
if (!settings) {
dev_err(&spi->dev, "device name %s not recognized.\n",
spi->modalias);
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*gdata));
if (!indio_dev)
return -ENOMEM;
gdata = iio_priv(indio_dev);
gdata->sensor_settings = (struct st_sensor_settings *)settings;
st_sensors_of_name_probe(&spi->dev, st_gyro_of_match,
spi->modalias, sizeof(spi->modalias));
st_sensors_spi_configure(indio_dev, spi, gdata);
err = st_sensors_spi_configure(indio_dev, spi);
if (err < 0)
return err;
err = st_gyro_common_probe(indio_dev);
if (err < 0)

View File

@ -240,32 +240,15 @@ static int am2315_probe(struct i2c_client *client,
indio_dev->channels = am2315_channels;
indio_dev->num_channels = ARRAY_SIZE(am2315_channels);
ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
ret = devm_iio_triggered_buffer_setup(&client->dev,
indio_dev, iio_pollfunc_store_time,
am2315_trigger_handler, NULL);
if (ret < 0) {
dev_err(&client->dev, "iio triggered buffer setup failed\n");
return ret;
}
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err_buffer_cleanup;
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int am2315_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id am2315_i2c_id[] = {
@ -287,7 +270,6 @@ static struct i2c_driver am2315_driver = {
.acpi_match_table = ACPI_PTR(am2315_acpi_id),
},
.probe = am2315_probe,
.remove = am2315_remove,
.id_table = am2315_i2c_id,
};

View File

@ -385,28 +385,16 @@ static int hdc100x_probe(struct i2c_client *client,
hdc100x_set_it_time(data, 1, hdc100x_int_time[1][0]);
hdc100x_update_config(data, HDC100X_REG_CONFIG_ACQ_MODE, 0);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ret = devm_iio_triggered_buffer_setup(&client->dev,
indio_dev, NULL,
hdc100x_trigger_handler,
&hdc_buffer_setup_ops);
if (ret < 0) {
dev_err(&client->dev, "iio triggered buffer setup failed\n");
return ret;
}
ret = iio_device_register(indio_dev);
if (ret < 0)
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int hdc100x_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id hdc100x_id[] = {
@ -436,7 +424,6 @@ static struct i2c_driver hdc100x_driver = {
.of_match_table = of_match_ptr(hdc100x_dt_ids),
},
.probe = hdc100x_probe,
.remove = hdc100x_remove,
.id_table = hdc100x_id,
};
module_i2c_driver(hdc100x_driver);

View File

@ -17,6 +17,18 @@ config ADIS16400
adis16365, adis16400 and adis16405 triaxial inertial sensors
(adis16400 series also have magnetometers).
config ADIS16460
tristate "Analog Devices ADIS16460 and similar IMU driver"
depends on SPI
select IIO_ADIS_LIB
select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
help
Say yes here to build support for Analog Devices ADIS16460 inertial
sensor.
To compile this driver as a module, choose M here: the module will be
called adis16460.
config ADIS16480
tristate "Analog Devices ADIS16480 and similar IMU driver"
depends on SPI

View File

@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ADIS16400) += adis16400.o
obj-$(CONFIG_ADIS16460) += adis16460.o
obj-$(CONFIG_ADIS16480) += adis16480.o
adis_lib-y += adis.o

View File

@ -39,18 +39,24 @@ int adis_write_reg(struct adis *adis, unsigned int reg,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay = adis->data->cs_change_delay,
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay = adis->data->cs_change_delay,
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay = adis->data->cs_change_delay,
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 6,
.bits_per_word = 8,
@ -133,12 +139,16 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->write_delay,
.cs_change_delay = adis->data->cs_change_delay,
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 2,
.bits_per_word = 8,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
.cs_change_delay = adis->data->cs_change_delay,
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
}, {
.tx_buf = adis->tx + 4,
.rx_buf = adis->rx,
@ -146,6 +156,8 @@ int adis_read_reg(struct adis *adis, unsigned int reg,
.len = 2,
.cs_change = 1,
.delay_usecs = adis->data->read_delay,
.cs_change_delay = adis->data->cs_change_delay,
.cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
}, {
.rx_buf = adis->rx + 2,
.bits_per_word = 8,

489
drivers/iio/imu/adis16460.c Normal file
View File

@ -0,0 +1,489 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* ADIS16460 IMU driver
*
* Copyright 2019 Analog Devices Inc.
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/imu/adis.h>
#include <linux/debugfs.h>
#define ADIS16460_REG_FLASH_CNT 0x00
#define ADIS16460_REG_DIAG_STAT 0x02
#define ADIS16460_REG_X_GYRO_LOW 0x04
#define ADIS16460_REG_X_GYRO_OUT 0x06
#define ADIS16460_REG_Y_GYRO_LOW 0x08
#define ADIS16460_REG_Y_GYRO_OUT 0x0A
#define ADIS16460_REG_Z_GYRO_LOW 0x0C
#define ADIS16460_REG_Z_GYRO_OUT 0x0E
#define ADIS16460_REG_X_ACCL_LOW 0x10
#define ADIS16460_REG_X_ACCL_OUT 0x12
#define ADIS16460_REG_Y_ACCL_LOW 0x14
#define ADIS16460_REG_Y_ACCL_OUT 0x16
#define ADIS16460_REG_Z_ACCL_LOW 0x18
#define ADIS16460_REG_Z_ACCL_OUT 0x1A
#define ADIS16460_REG_SMPL_CNTR 0x1C
#define ADIS16460_REG_TEMP_OUT 0x1E
#define ADIS16460_REG_X_DELT_ANG 0x24
#define ADIS16460_REG_Y_DELT_ANG 0x26
#define ADIS16460_REG_Z_DELT_ANG 0x28
#define ADIS16460_REG_X_DELT_VEL 0x2A
#define ADIS16460_REG_Y_DELT_VEL 0x2C
#define ADIS16460_REG_Z_DELT_VEL 0x2E
#define ADIS16460_REG_MSC_CTRL 0x32
#define ADIS16460_REG_SYNC_SCAL 0x34
#define ADIS16460_REG_DEC_RATE 0x36
#define ADIS16460_REG_FLTR_CTRL 0x38
#define ADIS16460_REG_GLOB_CMD 0x3E
#define ADIS16460_REG_X_GYRO_OFF 0x40
#define ADIS16460_REG_Y_GYRO_OFF 0x42
#define ADIS16460_REG_Z_GYRO_OFF 0x44
#define ADIS16460_REG_X_ACCL_OFF 0x46
#define ADIS16460_REG_Y_ACCL_OFF 0x48
#define ADIS16460_REG_Z_ACCL_OFF 0x4A
#define ADIS16460_REG_LOT_ID1 0x52
#define ADIS16460_REG_LOT_ID2 0x54
#define ADIS16460_REG_PROD_ID 0x56
#define ADIS16460_REG_SERIAL_NUM 0x58
#define ADIS16460_REG_CAL_SGNTR 0x60
#define ADIS16460_REG_CAL_CRC 0x62
#define ADIS16460_REG_CODE_SGNTR 0x64
#define ADIS16460_REG_CODE_CRC 0x66
struct adis16460_chip_info {
unsigned int num_channels;
const struct iio_chan_spec *channels;
unsigned int gyro_max_val;
unsigned int gyro_max_scale;
unsigned int accel_max_val;
unsigned int accel_max_scale;
};
struct adis16460 {
const struct adis16460_chip_info *chip_info;
struct adis adis;
};
#ifdef CONFIG_DEBUG_FS
static int adis16460_show_serial_number(void *arg, u64 *val)
{
struct adis16460 *adis16460 = arg;
u16 serial;
int ret;
ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_SERIAL_NUM,
&serial);
if (ret < 0)
return ret;
*val = serial;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16460_serial_number_fops,
adis16460_show_serial_number, NULL, "0x%.4llx\n");
static int adis16460_show_product_id(void *arg, u64 *val)
{
struct adis16460 *adis16460 = arg;
u16 prod_id;
int ret;
ret = adis_read_reg_16(&adis16460->adis, ADIS16460_REG_PROD_ID,
&prod_id);
if (ret < 0)
return ret;
*val = prod_id;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16460_product_id_fops,
adis16460_show_product_id, NULL, "%llu\n");
static int adis16460_show_flash_count(void *arg, u64 *val)
{
struct adis16460 *adis16460 = arg;
u32 flash_count;
int ret;
ret = adis_read_reg_32(&adis16460->adis, ADIS16460_REG_FLASH_CNT,
&flash_count);
if (ret < 0)
return ret;
*val = flash_count;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(adis16460_flash_count_fops,
adis16460_show_flash_count, NULL, "%lld\n");
static int adis16460_debugfs_init(struct iio_dev *indio_dev)
{
struct adis16460 *adis16460 = iio_priv(indio_dev);
debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
adis16460, &adis16460_serial_number_fops);
debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
adis16460, &adis16460_product_id_fops);
debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
adis16460, &adis16460_flash_count_fops);
return 0;
}
#else
static int adis16460_debugfs_init(struct iio_dev *indio_dev)
{
return 0;
}
#endif
static int adis16460_set_freq(struct iio_dev *indio_dev, int val, int val2)
{
struct adis16460 *st = iio_priv(indio_dev);
unsigned int t;
t = val * 1000 + val2 / 1000;
if (t <= 0)
return -EINVAL;
t = 2048000 / t;
if (t > 2048)
t = 2048;
if (t != 0)
t--;
return adis_write_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, t);
}
static int adis16460_get_freq(struct iio_dev *indio_dev, int *val, int *val2)
{
struct adis16460 *st = iio_priv(indio_dev);
uint16_t t;
int ret;
unsigned int freq;
ret = adis_read_reg_16(&st->adis, ADIS16460_REG_DEC_RATE, &t);
if (ret < 0)
return ret;
freq = 2048000 / (t + 1);
*val = freq / 1000;
*val2 = (freq % 1000) * 1000;
return IIO_VAL_INT_PLUS_MICRO;
}
static int adis16460_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int *val, int *val2, long info)
{
struct adis16460 *st = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_RAW:
return adis_single_conversion(indio_dev, chan, 0, val);
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ANGL_VEL:
*val = st->chip_info->gyro_max_scale;
*val2 = st->chip_info->gyro_max_val;
return IIO_VAL_FRACTIONAL;
case IIO_ACCEL:
*val = st->chip_info->accel_max_scale;
*val2 = st->chip_info->accel_max_val;
return IIO_VAL_FRACTIONAL;
case IIO_TEMP:
*val = 50; /* 50 milli degrees Celsius/LSB */
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
*val = 500; /* 25 degrees Celsius = 0x0000 */
return IIO_VAL_INT;
case IIO_CHAN_INFO_SAMP_FREQ:
return adis16460_get_freq(indio_dev, val, val2);
default:
return -EINVAL;
}
}
static int adis16460_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, int val, int val2, long info)
{
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
return adis16460_set_freq(indio_dev, val, val2);
default:
return -EINVAL;
}
}
enum {
ADIS16460_SCAN_GYRO_X,
ADIS16460_SCAN_GYRO_Y,
ADIS16460_SCAN_GYRO_Z,
ADIS16460_SCAN_ACCEL_X,
ADIS16460_SCAN_ACCEL_Y,
ADIS16460_SCAN_ACCEL_Z,
ADIS16460_SCAN_TEMP,
};
#define ADIS16460_MOD_CHANNEL(_type, _mod, _address, _si, _bits) \
{ \
.type = (_type), \
.modified = 1, \
.channel2 = (_mod), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.address = (_address), \
.scan_index = (_si), \
.scan_type = { \
.sign = 's', \
.realbits = (_bits), \
.storagebits = (_bits), \
.endianness = IIO_BE, \
}, \
}
#define ADIS16460_GYRO_CHANNEL(_mod) \
ADIS16460_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
ADIS16460_REG_ ## _mod ## _GYRO_LOW, ADIS16460_SCAN_GYRO_ ## _mod, \
32)
#define ADIS16460_ACCEL_CHANNEL(_mod) \
ADIS16460_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
ADIS16460_REG_ ## _mod ## _ACCL_LOW, ADIS16460_SCAN_ACCEL_ ## _mod, \
32)
#define ADIS16460_TEMP_CHANNEL() { \
.type = IIO_TEMP, \
.indexed = 1, \
.channel = 0, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.address = ADIS16460_REG_TEMP_OUT, \
.scan_index = ADIS16460_SCAN_TEMP, \
.scan_type = { \
.sign = 's', \
.realbits = 16, \
.storagebits = 16, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec adis16460_channels[] = {
ADIS16460_GYRO_CHANNEL(X),
ADIS16460_GYRO_CHANNEL(Y),
ADIS16460_GYRO_CHANNEL(Z),
ADIS16460_ACCEL_CHANNEL(X),
ADIS16460_ACCEL_CHANNEL(Y),
ADIS16460_ACCEL_CHANNEL(Z),
ADIS16460_TEMP_CHANNEL(),
IIO_CHAN_SOFT_TIMESTAMP(7)
};
static const struct adis16460_chip_info adis16460_chip_info = {
.channels = adis16460_channels,
.num_channels = ARRAY_SIZE(adis16460_channels),
/*
* storing the value in rad/degree and the scale in degree
* gives us the result in rad and better precession than
* storing the scale directly in rad.
*/
.gyro_max_val = IIO_RAD_TO_DEGREE(200 << 16),
.gyro_max_scale = 1,
.accel_max_val = IIO_M_S_2_TO_G(20000 << 16),
.accel_max_scale = 5,
};
static const struct iio_info adis16460_info = {
.read_raw = &adis16460_read_raw,
.write_raw = &adis16460_write_raw,
.update_scan_mode = adis_update_scan_mode,
.debugfs_reg_access = adis_debugfs_reg_access,
};
static int adis16460_enable_irq(struct adis *adis, bool enable)
{
/*
* There is no way to gate the data-ready signal internally inside the
* ADIS16460 :(
*/
if (enable)
enable_irq(adis->spi->irq);
else
disable_irq(adis->spi->irq);
return 0;
}
static int adis16460_initial_setup(struct iio_dev *indio_dev)
{
struct adis16460 *st = iio_priv(indio_dev);
uint16_t prod_id;
unsigned int device_id;
int ret;
adis_reset(&st->adis);
msleep(222);
ret = adis_write_reg_16(&st->adis, ADIS16460_REG_GLOB_CMD, BIT(1));
if (ret)
return ret;
msleep(75);
ret = adis_check_status(&st->adis);
if (ret)
return ret;
ret = adis_read_reg_16(&st->adis, ADIS16460_REG_PROD_ID, &prod_id);
if (ret)
return ret;
ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
if (ret != 1)
return -EINVAL;
if (prod_id != device_id)
dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
device_id, prod_id);
return 0;
}
#define ADIS16460_DIAG_STAT_IN_CLK_OOS 7
#define ADIS16460_DIAG_STAT_FLASH_MEM 6
#define ADIS16460_DIAG_STAT_SELF_TEST 5
#define ADIS16460_DIAG_STAT_OVERRANGE 4
#define ADIS16460_DIAG_STAT_SPI_COMM 3
#define ADIS16460_DIAG_STAT_FLASH_UPT 2
static const char * const adis16460_status_error_msgs[] = {
[ADIS16460_DIAG_STAT_IN_CLK_OOS] = "Input clock out of sync",
[ADIS16460_DIAG_STAT_FLASH_MEM] = "Flash memory failure",
[ADIS16460_DIAG_STAT_SELF_TEST] = "Self test diagnostic failure",
[ADIS16460_DIAG_STAT_OVERRANGE] = "Sensor overrange",
[ADIS16460_DIAG_STAT_SPI_COMM] = "SPI communication failure",
[ADIS16460_DIAG_STAT_FLASH_UPT] = "Flash update failure",
};
static const struct adis_data adis16460_data = {
.diag_stat_reg = ADIS16460_REG_DIAG_STAT,
.glob_cmd_reg = ADIS16460_REG_GLOB_CMD,
.has_paging = false,
.read_delay = 5,
.write_delay = 5,
.cs_change_delay = 16,
.status_error_msgs = adis16460_status_error_msgs,
.status_error_mask = BIT(ADIS16460_DIAG_STAT_IN_CLK_OOS) |
BIT(ADIS16460_DIAG_STAT_FLASH_MEM) |
BIT(ADIS16460_DIAG_STAT_SELF_TEST) |
BIT(ADIS16460_DIAG_STAT_OVERRANGE) |
BIT(ADIS16460_DIAG_STAT_SPI_COMM) |
BIT(ADIS16460_DIAG_STAT_FLASH_UPT),
.enable_irq = adis16460_enable_irq,
};
static int adis16460_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adis16460 *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
spi_set_drvdata(spi, indio_dev);
st = iio_priv(indio_dev);
st->chip_info = &adis16460_chip_info;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
indio_dev->info = &adis16460_info;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = adis_init(&st->adis, indio_dev, spi, &adis16460_data);
if (ret)
return ret;
ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
if (ret)
return ret;
adis16460_enable_irq(&st->adis, 0);
ret = adis16460_initial_setup(indio_dev);
if (ret)
goto error_cleanup_buffer;
ret = iio_device_register(indio_dev);
if (ret)
goto error_cleanup_buffer;
adis16460_debugfs_init(indio_dev);
return 0;
error_cleanup_buffer:
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
return ret;
}
static int adis16460_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adis16460 *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
return 0;
}
static const struct spi_device_id adis16460_ids[] = {
{ "adis16460", 0 },
{}
};
MODULE_DEVICE_TABLE(spi, adis16460_ids);
static const struct of_device_id adis16460_of_match[] = {
{ .compatible = "adi,adis16460" },
{}
};
MODULE_DEVICE_TABLE(of, adis16460_of_match);
static struct spi_driver adis16460_driver = {
.driver = {
.name = "adis16460",
.of_match_table = adis16460_of_match,
},
.id_table = adis16460_ids,
.probe = adis16460_probe,
.remove = adis16460_remove,
};
module_spi_driver(adis16460_driver);
MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
MODULE_DESCRIPTION("Analog Devices ADIS16460 IMU driver");
MODULE_LICENSE("GPL");

View File

@ -14,8 +14,9 @@ config INV_MPU6050_I2C
select INV_MPU6050_IIO
select REGMAP_I2C
help
This driver supports the Invensense MPU6050/6500/9150 and
ICM20608/20602 motion tracking devices over I2C.
This driver supports the Invensense MPU6000/6050/6500/6515,
MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
over I2C.
This driver can be built as a module. The module will be called
inv-mpu6050-i2c.
@ -25,7 +26,8 @@ config INV_MPU6050_SPI
select INV_MPU6050_IIO
select REGMAP_SPI
help
This driver supports the Invensense MPU6050/6500/9150 and
ICM20608/20602 motion tracking devices over SPI.
This driver supports the Invensense MPU6000/6050/6500/6515,
MPU9150/9250/9255 and ICM20608/20602 motion tracking devices
over SPI.
This driver can be built as a module. The module will be called
inv-mpu6050-spi.

View File

@ -1137,10 +1137,9 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
if (result)
return result;
result = devm_add_action(dev, inv_mpu_core_disable_regulator_action,
result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action,
st);
if (result) {
inv_mpu_core_disable_regulator_action(st);
dev_err(dev, "Failed to setup regulator cleanup action %d\n",
result);
return result;

View File

@ -2,15 +2,17 @@
config IIO_ST_LSM6DSX
tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors"
depends on (I2C || SPI)
depends on (I2C || SPI || I3C)
select IIO_BUFFER
select IIO_KFIFO_BUF
select IIO_ST_LSM6DSX_I2C if (I2C)
select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
select IIO_ST_LSM6DSX_I3C if (I3C)
help
Say yes here to build support for STMicroelectronics LSM6DSx imu
sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr
ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c,
ism330dhcx
To compile this driver as a module, choose M here: the module
will be called st_lsm6dsx.
@ -24,3 +26,8 @@ config IIO_ST_LSM6DSX_SPI
tristate
depends on IIO_ST_LSM6DSX
select REGMAP_SPI
config IIO_ST_LSM6DSX_I3C
tristate
depends on IIO_ST_LSM6DSX
select REGMAP_I3C

View File

@ -5,3 +5,4 @@ st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \
obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o
obj-$(CONFIG_IIO_ST_LSM6DSX_I3C) += st_lsm6dsx_i3c.o

View File

@ -22,6 +22,8 @@
#define ST_ASM330LHH_DEV_NAME "asm330lhh"
#define ST_LSM6DSOX_DEV_NAME "lsm6dsox"
#define ST_LSM6DSR_DEV_NAME "lsm6dsr"
#define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c"
#define ST_ISM330DHCX_DEV_NAME "ism330dhcx"
enum st_lsm6dsx_hw_id {
ST_LSM6DS3_ID,
@ -33,6 +35,8 @@ enum st_lsm6dsx_hw_id {
ST_ASM330LHH_ID,
ST_LSM6DSOX_ID,
ST_LSM6DSR_ID,
ST_LSM6DS3TRC_ID,
ST_ISM330DHCX_ID,
ST_LSM6DSX_MAX_ID,
};
@ -54,8 +58,8 @@ enum st_lsm6dsx_hw_id {
.address = addr, \
.modified = 1, \
.channel2 = mod, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = scan_idx, \
.scan_type = { \
@ -198,6 +202,9 @@ struct st_lsm6dsx_ext_dev_settings {
* @wai: Sensor WhoAmI default value.
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id/device name supported by the driver configuration.
* @channels: IIO channels supported by the device.
* @odr_table: Hw sensors odr table (Hz + val).
* @fs_table: Hw sensors gain table (gain + val).
* @decimator: List of decimator register info (addr + mask).
* @batch: List of FIFO batching register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
@ -211,6 +218,12 @@ struct st_lsm6dsx_settings {
enum st_lsm6dsx_hw_id hw_id;
const char *name;
} id[ST_LSM6DSX_MAX_ID];
struct {
const struct iio_chan_spec *chan;
int len;
} channels[2];
struct st_lsm6dsx_odr_table_entry odr_table[2];
struct st_lsm6dsx_fs_table_entry fs_table[2];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;

View File

@ -2,10 +2,10 @@
/*
* STMicroelectronics st_lsm6dsx FIFO buffer library driver
*
* LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: The FIFO buffer can be
* configured to store data from gyroscope and accelerometer. Samples are
* queued without any tag according to a specific pattern based on
* 'FIFO data sets' (6 bytes each):
* LSM6DS3/LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
* The FIFO buffer can be configured to store data from gyroscope and
* accelerometer. Samples are queued without any tag according to a
* specific pattern based on 'FIFO data sets' (6 bytes each):
* - 1st data set is reserved for gyroscope data
* - 2nd data set is reserved for accelerometer data
* The FIFO pattern changes depending on the ODRs and decimation factors
@ -14,9 +14,10 @@
* (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
* value of the decimation factor and ODR set for each FIFO data set.
*
* LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR: The FIFO buffer can be configured to
* store data from gyroscope and accelerometer. Each sample is queued with
* a tag (1B) indicating data source (gyroscope, accelerometer, hw timer).
* LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: The FIFO buffer can be
* configured to store data from gyroscope and accelerometer. Each sample
* is queued with a tag (1B) indicating data source (gyroscope, accelerometer,
* hw timer).
*
* FIFO supported modes:
* - BYPASS: FIFO disabled
@ -670,7 +671,7 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
count = hw->settings->fifo_ops.read_fifo(hw);
mutex_unlock(&hw->fifo_lock);
return !count ? IRQ_NONE : IRQ_HANDLED;
return count ? IRQ_HANDLED : IRQ_NONE;
}
static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)

View File

@ -18,13 +18,13 @@
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 8KB
*
* - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC:
* - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
* - FIFO size: 4KB
*
* - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR
* - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX:
* - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
* - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
* - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
@ -61,62 +61,18 @@
#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13
#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5)
#define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28
#define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a
#define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c
#define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22
#define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24
#define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26
static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
}
static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x28, IIO_MOD_X, 0),
ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1),
ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
}
static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x22, IIO_MOD_X, 0),
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x24, IIO_MOD_Y, 1),
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, 0x26, IIO_MOD_Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
@ -129,6 +85,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.name = ST_LSM6DS3_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6dsx_gyro_channels,
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
},
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
@ -179,6 +193,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.name = ST_LSM6DS3H_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6dsx_gyro_channels,
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
},
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
@ -233,6 +305,67 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
}, {
.hw_id = ST_ISM330DLC_ID,
.name = ST_ISM330DLC_DEV_NAME,
}, {
.hw_id = ST_LSM6DS3TRC_ID,
.name = ST_LSM6DS3TRC_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6dsx_gyro_channels,
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
},
},
.decimator = {
@ -288,6 +421,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.name = ST_LSM6DSOX_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6dsx_gyro_channels,
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
},
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x09,
@ -356,6 +547,64 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
.name = ST_ASM330LHH_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6dsx_gyro_channels,
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
},
},
.batch = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x09,
@ -396,6 +645,67 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.hw_id = ST_LSM6DSR_ID,
.name = ST_LSM6DSR_DEV_NAME,
}, {
.hw_id = ST_ISM330DHCX_ID,
.name = ST_ISM330DHCX_DEV_NAME,
},
},
.channels = {
[ST_LSM6DSX_ID_ACC] = {
.chan = st_lsm6dsx_acc_channels,
.len = ARRAY_SIZE(st_lsm6dsx_acc_channels),
},
[ST_LSM6DSX_ID_GYRO] = {
.chan = st_lsm6dsx_gyro_channels,
.len = ARRAY_SIZE(st_lsm6dsx_gyro_channels),
},
},
.odr_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(7, 4),
},
.odr_avl[0] = { 13, 0x01 },
.odr_avl[1] = { 26, 0x02 },
.odr_avl[2] = { 52, 0x03 },
.odr_avl[3] = { 104, 0x04 },
.odr_avl[4] = { 208, 0x05 },
.odr_avl[5] = { 416, 0x06 },
},
},
.fs_table = {
[ST_LSM6DSX_ID_ACC] = {
.reg = {
.addr = 0x10,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_G_TO_M_S_2(61), 0x0 },
.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
},
[ST_LSM6DSX_ID_GYRO] = {
.reg = {
.addr = 0x11,
.mask = GENMASK(3, 2),
},
.fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 },
.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
},
},
.batch = {
@ -459,26 +769,6 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
},
};
static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
IIO_MOD_X, 0),
ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
IIO_MOD_Y, 1),
ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
IIO_MOD_Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
IIO_MOD_X, 0),
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
IIO_MOD_Y, 1),
ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
IIO_MOD_Z, 2),
IIO_CHAN_SOFT_TIMESTAMP(3),
};
int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
{
const struct st_lsm6dsx_shub_settings *hub_settings;
@ -533,23 +823,22 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
u32 gain)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
const struct st_lsm6dsx_reg *reg;
const struct st_lsm6dsx_fs_table_entry *fs_table;
unsigned int data;
int i, err;
u8 val;
fs_table = &sensor->hw->settings->fs_table[sensor->id];
for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain)
if (fs_table->fs_avl[i].gain == gain)
break;
if (i == ST_LSM6DSX_FS_LIST_SIZE)
return -EINVAL;
val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val;
reg = &st_lsm6dsx_fs_table[sensor->id].reg;
data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
data = ST_LSM6DSX_SHIFT_VAL(fs_table->fs_avl[i].val,
fs_table->reg.mask);
err = st_lsm6dsx_update_bits_locked(sensor->hw, fs_table->reg.addr,
fs_table->reg.mask, data);
if (err < 0)
return err;
@ -560,20 +849,22 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
{
const struct st_lsm6dsx_odr_table_entry *odr_table;
int i;
odr_table = &sensor->hw->settings->odr_table[sensor->id];
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
/*
* ext devices can run at different odr respect to
* accel sensor
*/
if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
if (odr_table->odr_avl[i].hz >= odr)
break;
if (i == ST_LSM6DSX_ODR_LIST_SIZE)
return -EINVAL;
*val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val;
*val = odr_table->odr_avl[i].val;
return 0;
}
@ -638,7 +929,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
return err;
}
reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
reg = &hw->settings->odr_table[ref_sensor->id].reg;
data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
}
@ -783,11 +1074,12 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
{
struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
enum st_lsm6dsx_sensor_id id = sensor->id;
struct st_lsm6dsx_hw *hw = sensor->hw;
int i, len = 0;
for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
st_lsm6dsx_odr_table[id].odr_avl[i].hz);
hw->settings->odr_table[id].odr_avl[i].hz);
buf[len - 1] = '\n';
return len;
@ -799,11 +1091,12 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
{
struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
enum st_lsm6dsx_sensor_id id = sensor->id;
struct st_lsm6dsx_hw *hw = sensor->hw;
int i, len = 0;
for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
st_lsm6dsx_fs_table[id].fs_avl[i].gain);
hw->settings->fs_table[id].fs_avl[i].gain);
buf[len - 1] = '\n';
return len;
@ -1033,28 +1326,24 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->dev.parent = hw->dev;
iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
iio_dev->channels = hw->settings->channels[id].chan;
iio_dev->num_channels = hw->settings->channels[id].len;
sensor = iio_priv(iio_dev);
sensor->id = id;
sensor->hw = hw;
sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz;
sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain;
sensor->watermark = 1;
switch (id) {
case ST_LSM6DSX_ID_ACC:
iio_dev->channels = st_lsm6dsx_acc_channels;
iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
iio_dev->info = &st_lsm6dsx_acc_info;
scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
name);
break;
case ST_LSM6DSX_ID_GYRO:
iio_dev->channels = st_lsm6dsx_gyro_channels;
iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
iio_dev->info = &st_lsm6dsx_gyro_info;
scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
name);
break;

View File

@ -75,6 +75,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
.compatible = "st,lsm6dsr",
.data = (void *)ST_LSM6DSR_ID,
},
{
.compatible = "st,lsm6ds3tr-c",
.data = (void *)ST_LSM6DS3TRC_ID,
},
{
.compatible = "st,ism330dhcx",
.data = (void *)ST_ISM330DHCX_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@ -89,6 +97,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
{ ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
{ ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
{ ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
{},
};
MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
*
* Author: Vitor Soares <vitor.soares@synopsys.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i3c/device.h>
#include <linux/i3c/master.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "st_lsm6dsx.h"
static const struct i3c_device_id st_lsm6dsx_i3c_ids[] = {
I3C_DEVICE(0x0104, 0x006C, (void *)ST_LSM6DSO_ID),
I3C_DEVICE(0x0104, 0x006B, (void *)ST_LSM6DSR_ID),
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(i3c, st_lsm6dsx_i3c_ids);
static int st_lsm6dsx_i3c_probe(struct i3c_device *i3cdev)
{
struct regmap_config st_lsm6dsx_i3c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
const struct i3c_device_id *id = i3c_device_match_id(i3cdev,
st_lsm6dsx_i3c_ids);
struct regmap *regmap;
regmap = devm_regmap_init_i3c(i3cdev, &st_lsm6dsx_i3c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&i3cdev->dev, "Failed to register i3c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_lsm6dsx_probe(&i3cdev->dev, 0, (uintptr_t)id->data, regmap);
}
static struct i3c_driver st_lsm6dsx_driver = {
.driver = {
.name = "st_lsm6dsx_i3c",
.pm = &st_lsm6dsx_pm_ops,
},
.probe = st_lsm6dsx_i3c_probe,
.id_table = st_lsm6dsx_i3c_ids,
};
module_i3c_driver(st_lsm6dsx_driver);
MODULE_AUTHOR("Vitor Soares <vitor.soares@synopsys.com>");
MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i3c driver");
MODULE_LICENSE("GPL v2");

View File

@ -75,6 +75,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
.compatible = "st,lsm6dsr",
.data = (void *)ST_LSM6DSR_ID,
},
{
.compatible = "st,lsm6ds3tr-c",
.data = (void *)ST_LSM6DS3TRC_ID,
},
{
.compatible = "st,ism330dhcx",
.data = (void *)ST_ISM330DHCX_ID,
},
{},
};
MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@ -89,6 +97,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
{ ST_ASM330LHH_DEV_NAME, ST_ASM330LHH_ID },
{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
{ ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
{ ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID },
{},
};
MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);

View File

@ -303,6 +303,7 @@ config MAX44000
config MAX44009
tristate "MAX44009 Ambient Light Sensor"
depends on I2C
select REGMAP_I2C
help
Say Y here if you want to build support for Maxim Integrated's
MAX44009 ambient light sensor device.
@ -310,6 +311,16 @@ config MAX44009
To compile this driver as a module, choose M here:
the module will be called max44009.
config NOA1305
tristate "ON Semiconductor NOA1305 ambient light sensor"
depends on I2C
help
Say Y here if you want to build support for the ON Semiconductor
NOA1305 ambient light sensor.
To compile this driver as a module, choose M here:
The module will be called noa1305.
config OPT3001
tristate "Texas Instruments OPT3001 Light Sensor"
depends on I2C

View File

@ -29,6 +29,7 @@ obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_LV0104CS) += lv0104cs.o
obj-$(CONFIG_MAX44000) += max44000.o
obj-$(CONFIG_MAX44009) += max44009.o
obj-$(CONFIG_NOA1305) += noa1305.o
obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o

View File

@ -1135,5 +1135,5 @@ static struct i2c_driver apds9960_driver = {
module_i2c_driver(apds9960_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("ADPS9960 Gesture/RGB/ALS/Proximity sensor");
MODULE_DESCRIPTION("APDS9960 Gesture/RGB/ALS/Proximity sensor");
MODULE_LICENSE("GPL");

View File

@ -101,15 +101,16 @@ static int cm3323_init(struct iio_dev *indio_dev)
return 0;
}
static void cm3323_disable(struct iio_dev *indio_dev)
static void cm3323_disable(void *data)
{
int ret;
struct cm3323_data *data = iio_priv(indio_dev);
struct iio_dev *indio_dev = data;
struct cm3323_data *cm_data = iio_priv(indio_dev);
ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF,
ret = i2c_smbus_write_word_data(cm_data->client, CM3323_CMD_CONF,
CM3323_CONF_SD_BIT);
if (ret < 0)
dev_err(&data->client->dev, "Error writing reg_conf\n");
dev_err(&cm_data->client->dev, "Error writing reg_conf\n");
}
static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
@ -243,26 +244,11 @@ static int cm3323_probe(struct i2c_client *client,
return ret;
}
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "failed to register iio dev\n");
goto err_init;
}
ret = devm_add_action_or_reset(&client->dev, cm3323_disable, indio_dev);
if (ret < 0)
return ret;
return 0;
err_init:
cm3323_disable(indio_dev);
return ret;
}
static int cm3323_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
cm3323_disable(indio_dev);
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id cm3323_id[] = {
@ -276,7 +262,6 @@ static struct i2c_driver cm3323_driver = {
.name = CM3323_DRV_NAME,
},
.probe = cm3323_probe,
.remove = cm3323_remove,
.id_table = cm3323_id,
};

View File

@ -646,18 +646,18 @@ static int cm36651_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev);
cm36651->client = client;
cm36651->ps_client = i2c_new_dummy(client->adapter,
cm36651->ps_client = i2c_new_dummy_device(client->adapter,
CM36651_I2C_ADDR_PS);
if (!cm36651->ps_client) {
if (IS_ERR(cm36651->ps_client)) {
dev_err(&client->dev, "%s: new i2c device failed\n", __func__);
ret = -ENODEV;
ret = PTR_ERR(cm36651->ps_client);
goto error_disable_reg;
}
cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA);
if (!cm36651->ara_client) {
cm36651->ara_client = i2c_new_dummy_device(client->adapter, CM36651_ARA);
if (IS_ERR(cm36651->ara_client)) {
dev_err(&client->dev, "%s: new i2c device failed\n", __func__);
ret = -ENODEV;
ret = PTR_ERR(cm36651->ara_client);
goto error_i2c_unregister_ps;
}

View File

@ -42,7 +42,7 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev,
struct cros_ec_light_prox_state *st = iio_priv(indio_dev);
u16 data = 0;
s64 val64;
int ret = IIO_VAL_INT;
int ret;
int idx = chan->scan_index;
mutex_lock(&st->core.cmd_lock);
@ -50,23 +50,22 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type == IIO_PROXIMITY) {
if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
(s16 *)&data) < 0) {
ret = -EIO;
ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
(s16 *)&data);
if (ret)
break;
}
*val = data;
ret = IIO_VAL_INT;
} else {
ret = -EINVAL;
}
break;
case IIO_CHAN_INFO_PROCESSED:
if (chan->type == IIO_LIGHT) {
if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
(s16 *)&data) < 0) {
ret = -EIO;
ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
(s16 *)&data);
if (ret)
break;
}
/*
* The data coming from the light sensor is
* pre-processed and represents the ambient light
@ -82,15 +81,16 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev,
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
st->core.param.sensor_offset.flags = 0;
if (cros_ec_motion_send_host_cmd(&st->core, 0)) {
ret = -EIO;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
if (ret)
break;
}
/* Save values */
st->core.calib[0] = st->core.resp->sensor_offset.offset[0];
st->core.calib[0].offset =
st->core.resp->sensor_offset.offset[0];
*val = st->core.calib[idx];
*val = st->core.calib[idx].offset;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_CALIBSCALE:
/*
@ -101,10 +101,9 @@ static int cros_ec_light_prox_read(struct iio_dev *indio_dev,
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
if (cros_ec_motion_send_host_cmd(&st->core, 0)) {
ret = -EIO;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
if (ret)
break;
}
val64 = st->core.resp->sensor_range.ret;
*val = val64 >> 16;
@ -127,28 +126,27 @@ static int cros_ec_light_prox_write(struct iio_dev *indio_dev,
int val, int val2, long mask)
{
struct cros_ec_light_prox_state *st = iio_priv(indio_dev);
int ret = 0;
int ret;
int idx = chan->scan_index;
mutex_lock(&st->core.cmd_lock);
switch (mask) {
case IIO_CHAN_INFO_CALIBBIAS:
st->core.calib[idx] = val;
st->core.calib[idx].offset = val;
/* Send to EC for each axis, even if not complete */
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
st->core.param.sensor_offset.flags = MOTION_SENSE_SET_OFFSET;
st->core.param.sensor_offset.offset[0] = st->core.calib[0];
st->core.param.sensor_offset.offset[0] =
st->core.calib[0].offset;
st->core.param.sensor_offset.temp =
EC_MOTION_SENSE_INVALID_CALIB_TEMP;
if (cros_ec_motion_send_host_cmd(&st->core, 0))
ret = -EIO;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
break;
case IIO_CHAN_INFO_CALIBSCALE:
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
st->core.param.sensor_range.data = (val << 16) | (val2 / 100);
if (cros_ec_motion_send_host_cmd(&st->core, 0))
ret = -EIO;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
break;
default:
ret = cros_ec_sensors_core_write(&st->core, chan, val, val2,
@ -164,6 +162,7 @@ static int cros_ec_light_prox_write(struct iio_dev *indio_dev,
static const struct iio_info cros_ec_light_prox_info = {
.read_raw = &cros_ec_light_prox_read,
.write_raw = &cros_ec_light_prox_write,
.read_avail = &cros_ec_sensors_core_read_avail,
};
static int cros_ec_light_prox_probe(struct platform_device *pdev)
@ -198,6 +197,8 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
channel->info_mask_shared_by_all =
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_FREQUENCY);
channel->info_mask_shared_by_all_available =
BIT(IIO_CHAN_INFO_SAMP_FREQ);
channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
channel->scan_type.shift = 0;
@ -205,8 +206,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
channel->ext_info = cros_ec_sensors_ext_info;
channel->scan_type.sign = 'u';
state->core.calib[0] = 0;
/* Sensor specific */
switch (state->core.type) {
case MOTIONSENSE_TYPE_LIGHT:

312
drivers/iio/light/noa1305.c Normal file
View File

@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Support for ON Semiconductor NOA1305 ambient light sensor
*
* Copyright (C) 2016 Emcraft Systems
* Copyright (C) 2019 Collabora Ltd.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#define NOA1305_REG_POWER_CONTROL 0x0
#define NOA1305_POWER_CONTROL_DOWN 0x00
#define NOA1305_POWER_CONTROL_ON 0x08
#define NOA1305_REG_RESET 0x1
#define NOA1305_RESET_RESET 0x10
#define NOA1305_REG_INTEGRATION_TIME 0x2
#define NOA1305_INTEGR_TIME_800MS 0x00
#define NOA1305_INTEGR_TIME_400MS 0x01
#define NOA1305_INTEGR_TIME_200MS 0x02
#define NOA1305_INTEGR_TIME_100MS 0x03
#define NOA1305_INTEGR_TIME_50MS 0x04
#define NOA1305_INTEGR_TIME_25MS 0x05
#define NOA1305_INTEGR_TIME_12_5MS 0x06
#define NOA1305_INTEGR_TIME_6_25MS 0x07
#define NOA1305_REG_INT_SELECT 0x3
#define NOA1305_INT_SEL_ACTIVE_HIGH 0x01
#define NOA1305_INT_SEL_ACTIVE_LOW 0x02
#define NOA1305_INT_SEL_INACTIVE 0x03
#define NOA1305_REG_INT_THRESH_LSB 0x4
#define NOA1305_REG_INT_THRESH_MSB 0x5
#define NOA1305_REG_ALS_DATA_LSB 0x6
#define NOA1305_REG_ALS_DATA_MSB 0x7
#define NOA1305_REG_DEVICE_ID_LSB 0x8
#define NOA1305_REG_DEVICE_ID_MSB 0x9
#define NOA1305_DEVICE_ID 0x0519
#define NOA1305_DRIVER_NAME "noa1305"
struct noa1305_priv {
struct i2c_client *client;
struct regmap *regmap;
struct regulator *vin_reg;
};
static int noa1305_measure(struct noa1305_priv *priv)
{
__le16 data;
int ret;
ret = regmap_bulk_read(priv->regmap, NOA1305_REG_ALS_DATA_LSB, &data,
2);
if (ret < 0)
return ret;
return le16_to_cpu(data);
}
static int noa1305_scale(struct noa1305_priv *priv, int *val, int *val2)
{
int data;
int ret;
ret = regmap_read(priv->regmap, NOA1305_REG_INTEGRATION_TIME, &data);
if (ret < 0)
return ret;
/*
* Lux = count / (<Integration Constant> * <Integration Time>)
*
* Integration Constant = 7.7
* Integration Time in Seconds
*/
switch (data) {
case NOA1305_INTEGR_TIME_800MS:
*val = 100;
*val2 = 77 * 8;
break;
case NOA1305_INTEGR_TIME_400MS:
*val = 100;
*val2 = 77 * 4;
case NOA1305_INTEGR_TIME_200MS:
*val = 100;
*val2 = 77 * 2;
break;
case NOA1305_INTEGR_TIME_100MS:
*val = 100;
*val2 = 77;
break;
case NOA1305_INTEGR_TIME_50MS:
*val = 1000;
*val2 = 77 * 5;
break;
case NOA1305_INTEGR_TIME_25MS:
*val = 10000;
*val2 = 77 * 25;
break;
case NOA1305_INTEGR_TIME_12_5MS:
*val = 100000;
*val2 = 77 * 125;
break;
case NOA1305_INTEGR_TIME_6_25MS:
*val = 1000000;
*val2 = 77 * 625;
break;
default:
return -EINVAL;
}
return IIO_VAL_FRACTIONAL;
}
static const struct iio_chan_spec noa1305_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
}
};
static int noa1305_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret = -EINVAL;
struct noa1305_priv *priv = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
ret = noa1305_measure(priv);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
default:
break;
}
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_LIGHT:
return noa1305_scale(priv, val, val2);
default:
break;
}
break;
default:
break;
}
return ret;
}
static const struct iio_info noa1305_info = {
.read_raw = noa1305_read_raw,
};
static bool noa1305_writable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case NOA1305_REG_POWER_CONTROL:
case NOA1305_REG_RESET:
case NOA1305_REG_INTEGRATION_TIME:
case NOA1305_REG_INT_SELECT:
case NOA1305_REG_INT_THRESH_LSB:
case NOA1305_REG_INT_THRESH_MSB:
return true;
default:
return false;
}
}
static const struct regmap_config noa1305_regmap_config = {
.name = NOA1305_DRIVER_NAME,
.reg_bits = 8,
.val_bits = 8,
.max_register = NOA1305_REG_DEVICE_ID_MSB,
.writeable_reg = noa1305_writable_reg,
};
static void noa1305_reg_remove(void *data)
{
struct noa1305_priv *priv = data;
regulator_disable(priv->vin_reg);
}
static int noa1305_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct noa1305_priv *priv;
struct iio_dev *indio_dev;
struct regmap *regmap;
__le16 data;
unsigned int dev_id;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
regmap = devm_regmap_init_i2c(client, &noa1305_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Regmap initialization failed.\n");
return PTR_ERR(regmap);
}
priv = iio_priv(indio_dev);
priv->vin_reg = devm_regulator_get(&client->dev, "vin");
if (IS_ERR(priv->vin_reg)) {
dev_err(&client->dev, "get regulator vin failed\n");
return PTR_ERR(priv->vin_reg);
}
ret = regulator_enable(priv->vin_reg);
if (ret) {
dev_err(&client->dev, "enable regulator vin failed\n");
return ret;
}
ret = devm_add_action_or_reset(&client->dev, noa1305_reg_remove, priv);
if (ret) {
dev_err(&client->dev, "addition of devm action failed\n");
return ret;
}
i2c_set_clientdata(client, indio_dev);
priv->client = client;
priv->regmap = regmap;
ret = regmap_bulk_read(regmap, NOA1305_REG_DEVICE_ID_LSB, &data, 2);
if (ret < 0) {
dev_err(&client->dev, "ID reading failed: %d\n", ret);
return ret;
}
dev_id = le16_to_cpu(data);
if (dev_id != NOA1305_DEVICE_ID) {
dev_err(&client->dev, "Unknown device ID: 0x%x\n", dev_id);
return -ENODEV;
}
ret = regmap_write(regmap, NOA1305_REG_POWER_CONTROL,
NOA1305_POWER_CONTROL_ON);
if (ret < 0) {
dev_err(&client->dev, "Enabling power control failed\n");
return ret;
}
ret = regmap_write(regmap, NOA1305_REG_RESET, NOA1305_RESET_RESET);
if (ret < 0) {
dev_err(&client->dev, "Device reset failed\n");
return ret;
}
ret = regmap_write(regmap, NOA1305_REG_INTEGRATION_TIME,
NOA1305_INTEGR_TIME_800MS);
if (ret < 0) {
dev_err(&client->dev, "Setting integration time failed\n");
return ret;
}
indio_dev->dev.parent = &client->dev;
indio_dev->info = &noa1305_info;
indio_dev->channels = noa1305_channels;
indio_dev->num_channels = ARRAY_SIZE(noa1305_channels);
indio_dev->name = NOA1305_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = devm_iio_device_register(&client->dev, indio_dev);
if (ret)
dev_err(&client->dev, "registering device failed\n");
return ret;
}
static const struct of_device_id noa1305_of_match[] = {
{ .compatible = "onnn,noa1305" },
{ }
};
MODULE_DEVICE_TABLE(of, noa1305_of_match);
static const struct i2c_device_id noa1305_ids[] = {
{ "noa1305", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, noa1305_ids);
static struct i2c_driver noa1305_driver = {
.driver = {
.name = NOA1305_DRIVER_NAME,
.of_match_table = noa1305_of_match,
},
.probe = noa1305_probe,
.id_table = noa1305_ids,
};
module_i2c_driver(noa1305_driver);
MODULE_AUTHOR("Sergei Miroshnichenko <sergeimir@emcraft.com>");
MODULE_AUTHOR("Martyn Welch <martyn.welch@collabora.com");
MODULE_DESCRIPTION("ON Semiconductor NOA1305 ambient light sensor");
MODULE_LICENSE("GPL");

View File

@ -1261,7 +1261,7 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
return ret;
}
ret = iio_trigger_register(trig);
ret = devm_iio_trigger_register(&client->dev, trig);
if (ret)
return ret;
@ -1271,16 +1271,6 @@ static int si1145_probe_trigger(struct iio_dev *indio_dev)
return 0;
}
static void si1145_remove_trigger(struct iio_dev *indio_dev)
{
struct si1145_data *data = iio_priv(indio_dev);
if (data->trig) {
iio_trigger_unregister(data->trig);
data->trig = NULL;
}
}
static int si1145_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -1332,7 +1322,8 @@ static int si1145_probe(struct i2c_client *client,
if (ret < 0)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ret = devm_iio_triggered_buffer_setup(&client->dev,
indio_dev, NULL,
si1145_trigger_handler, &si1145_buffer_setup_ops);
if (ret < 0)
return ret;
@ -1340,23 +1331,12 @@ static int si1145_probe(struct i2c_client *client,
if (client->irq) {
ret = si1145_probe_trigger(indio_dev);
if (ret < 0)
goto error_free_buffer;
return ret;
} else {
dev_info(&client->dev, "no irq, using polling\n");
}
ret = iio_device_register(indio_dev);
if (ret < 0)
goto error_free_trigger;
return 0;
error_free_trigger:
si1145_remove_trigger(indio_dev);
error_free_buffer:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id si1145_ids[] = {
@ -1371,23 +1351,11 @@ static const struct i2c_device_id si1145_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, si1145_ids);
static int si1145_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
si1145_remove_trigger(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static struct i2c_driver si1145_driver = {
.driver = {
.name = "si1145",
},
.probe = si1145_probe,
.remove = si1145_remove,
.id_table = si1145_ids,
};

View File

@ -679,9 +679,18 @@ static const struct acpi_device_id stk3310_acpi_id[] = {
MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id);
static const struct of_device_id stk3310_of_match[] = {
{ .compatible = "sensortek,stk3310", },
{ .compatible = "sensortek,stk3311", },
{ .compatible = "sensortek,stk3335", },
{}
};
MODULE_DEVICE_TABLE(of, stk3310_of_match);
static struct i2c_driver stk3310_driver = {
.driver = {
.name = "stk3310",
.of_match_table = stk3310_of_match,
.pm = STK3310_PM_OPS,
.acpi_match_table = ACPI_PTR(stk3310_acpi_id),
},

View File

@ -134,6 +134,12 @@ enum {
TSL2772_CHIP_SUSPENDED = 2
};
enum {
TSL2772_SUPPLY_VDD = 0,
TSL2772_SUPPLY_VDDIO = 1,
TSL2772_NUM_SUPPLIES = 2
};
/* Per-device data */
struct tsl2772_als_info {
u16 als_ch0;
@ -161,8 +167,7 @@ struct tsl2772_chip {
struct mutex prox_mutex;
struct mutex als_mutex;
struct i2c_client *client;
struct regulator *vdd_supply;
struct regulator *vddio_supply;
struct regulator_bulk_data supplies[TSL2772_NUM_SUPPLIES];
u16 prox_data;
struct tsl2772_als_info als_cur_info;
struct tsl2772_settings settings;
@ -697,46 +702,7 @@ static void tsl2772_disable_regulators_action(void *_data)
{
struct tsl2772_chip *chip = _data;
regulator_disable(chip->vdd_supply);
regulator_disable(chip->vddio_supply);
}
static int tsl2772_enable_regulator(struct tsl2772_chip *chip,
struct regulator *regulator)
{
int ret;
ret = regulator_enable(regulator);
if (ret < 0) {
dev_err(&chip->client->dev, "Failed to enable regulator: %d\n",
ret);
return ret;
}
return 0;
}
static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip,
char *name)
{
struct regulator *regulator;
int ret;
regulator = devm_regulator_get(&chip->client->dev, name);
if (IS_ERR(regulator)) {
if (PTR_ERR(regulator) != -EPROBE_DEFER)
dev_err(&chip->client->dev,
"Failed to get %s regulator %d\n",
name, (int)PTR_ERR(regulator));
return regulator;
}
ret = tsl2772_enable_regulator(chip, regulator);
if (ret < 0)
return ERR_PTR(ret);
return regulator;
regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies);
}
static int tsl2772_chip_on(struct iio_dev *indio_dev)
@ -860,6 +826,13 @@ static int tsl2772_chip_off(struct iio_dev *indio_dev)
return tsl2772_write_control_reg(chip, 0x00);
}
static void tsl2772_chip_off_action(void *data)
{
struct iio_dev *indio_dev = data;
tsl2772_chip_off(indio_dev);
}
/**
* tsl2772_invoke_change - power cycle the device to implement the user
* parameters
@ -1797,20 +1770,32 @@ static int tsl2772_probe(struct i2c_client *clientp,
chip->client = clientp;
i2c_set_clientdata(clientp, indio_dev);
chip->vddio_supply = tsl2772_get_regulator(chip, "vddio");
if (IS_ERR(chip->vddio_supply))
return PTR_ERR(chip->vddio_supply);
chip->supplies[TSL2772_SUPPLY_VDD].supply = "vdd";
chip->supplies[TSL2772_SUPPLY_VDDIO].supply = "vddio";
chip->vdd_supply = tsl2772_get_regulator(chip, "vdd");
if (IS_ERR(chip->vdd_supply)) {
regulator_disable(chip->vddio_supply);
return PTR_ERR(chip->vdd_supply);
ret = devm_regulator_bulk_get(&clientp->dev,
ARRAY_SIZE(chip->supplies),
chip->supplies);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(&clientp->dev,
"Failed to get regulators: %d\n",
ret);
return ret;
}
ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action,
chip);
ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies);
if (ret < 0) {
dev_err(&clientp->dev, "Failed to enable regulators: %d\n",
ret);
return ret;
}
ret = devm_add_action_or_reset(&clientp->dev,
tsl2772_disable_regulators_action,
chip);
if (ret < 0) {
tsl2772_disable_regulators_action(chip);
dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n",
ret);
return ret;
@ -1877,15 +1862,13 @@ static int tsl2772_probe(struct i2c_client *clientp,
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret) {
tsl2772_chip_off(indio_dev);
dev_err(&clientp->dev,
"%s: iio registration failed\n", __func__);
ret = devm_add_action_or_reset(&clientp->dev,
tsl2772_chip_off_action,
indio_dev);
if (ret < 0)
return ret;
}
return 0;
return devm_iio_device_register(&clientp->dev, indio_dev);
}
static int tsl2772_suspend(struct device *dev)
@ -1895,8 +1878,7 @@ static int tsl2772_suspend(struct device *dev)
int ret;
ret = tsl2772_chip_off(indio_dev);
regulator_disable(chip->vdd_supply);
regulator_disable(chip->vddio_supply);
regulator_bulk_disable(ARRAY_SIZE(chip->supplies), chip->supplies);
return ret;
}
@ -1907,32 +1889,15 @@ static int tsl2772_resume(struct device *dev)
struct tsl2772_chip *chip = iio_priv(indio_dev);
int ret;
ret = tsl2772_enable_regulator(chip, chip->vddio_supply);
ret = regulator_bulk_enable(ARRAY_SIZE(chip->supplies), chip->supplies);
if (ret < 0)
return ret;
ret = tsl2772_enable_regulator(chip, chip->vdd_supply);
if (ret < 0) {
regulator_disable(chip->vddio_supply);
return ret;
}
usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
return tsl2772_chip_on(indio_dev);
}
static int tsl2772_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
tsl2772_chip_off(indio_dev);
iio_device_unregister(indio_dev);
return 0;
}
static const struct i2c_device_id tsl2772_idtable[] = {
{ "tsl2571", tsl2571 },
{ "tsl2671", tsl2671 },
@ -1979,7 +1944,6 @@ static struct i2c_driver tsl2772_driver = {
},
.id_table = tsl2772_idtable,
.probe = tsl2772_probe,
.remove = tsl2772_remove,
};
module_i2c_driver(tsl2772_driver);

View File

@ -158,10 +158,10 @@ static int veml6070_probe(struct i2c_client *client,
indio_dev->name = VEML6070_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
data->client2 = i2c_new_dummy(client->adapter, VEML6070_ADDR_DATA_LSB);
if (!data->client2) {
data->client2 = i2c_new_dummy_device(client->adapter, VEML6070_ADDR_DATA_LSB);
if (IS_ERR(data->client2)) {
dev_err(&client->dev, "i2c device for second chip address failed\n");
return -ENODEV;
return PTR_ERR(data->client2);
}
data->config = VEML6070_IT_10 | VEML6070_COMMAND_RSRVD |

View File

@ -53,7 +53,7 @@
#define MMC35240_CTRL1_BW_SHIFT 0
#define MMC35240_WAIT_CHARGE_PUMP 50000 /* us */
#define MMC53240_WAIT_SET_RESET 1000 /* us */
#define MMC35240_WAIT_SET_RESET 1000 /* us */
/*
* Memsic OTP process code piece is put here for reference:
@ -225,7 +225,7 @@ static int mmc35240_init(struct mmc35240_data *data)
ret = mmc35240_hw_set(data, true);
if (ret < 0)
return ret;
usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1);
usleep_range(MMC35240_WAIT_SET_RESET, MMC35240_WAIT_SET_RESET + 1);
ret = mmc35240_hw_set(data, false);
if (ret < 0)

View File

@ -22,6 +22,7 @@
#define LIS2MDL_MAGN_DEV_NAME "lis2mdl"
#define LSM9DS1_MAGN_DEV_NAME "lsm9ds1_magn"
const struct st_sensor_settings *st_magn_get_settings(const char *name);
int st_magn_common_probe(struct iio_dev *indio_dev);
void st_magn_common_remove(struct iio_dev *indio_dev);

View File

@ -32,39 +32,32 @@ int st_magn_trig_set_state(struct iio_trigger *trig, bool state)
static int st_magn_buffer_postenable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *mdata = iio_priv(indio_dev);
mdata->buffer_data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (mdata->buffer_data == NULL) {
err = -ENOMEM;
goto allocate_memory_error;
}
err = iio_triggered_buffer_postenable(indio_dev);
if (err < 0)
goto st_magn_buffer_postenable_error;
return err;
return st_sensors_set_enable(indio_dev, true);
err = st_sensors_set_enable(indio_dev, true);
if (err < 0)
goto st_magn_buffer_predisable;
st_magn_buffer_postenable_error:
kfree(mdata->buffer_data);
allocate_memory_error:
return 0;
st_magn_buffer_predisable:
iio_triggered_buffer_predisable(indio_dev);
return err;
}
static int st_magn_buffer_predisable(struct iio_dev *indio_dev)
{
int err;
struct st_sensor_data *mdata = iio_priv(indio_dev);
int err, err2;
err = st_sensors_set_enable(indio_dev, false);
if (err < 0)
goto st_magn_buffer_predisable_error;
err = iio_triggered_buffer_predisable(indio_dev);
err2 = iio_triggered_buffer_predisable(indio_dev);
if (!err)
err = err2;
st_magn_buffer_predisable_error:
kfree(mdata->buffer_data);
return err;
}

View File

@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
@ -470,28 +469,41 @@ static const struct iio_trigger_ops st_magn_trigger_ops = {
#define ST_MAGN_TRIGGER_OPS NULL
#endif
/*
* st_magn_get_settings() - get sensor settings from device name
* @name: device name buffer reference.
*
* Return: valid reference on success, NULL otherwise.
*/
const struct st_sensor_settings *st_magn_get_settings(const char *name)
{
int index = st_sensors_get_settings_index(name,
st_magn_sensors_settings,
ARRAY_SIZE(st_magn_sensors_settings));
if (index < 0)
return NULL;
return &st_magn_sensors_settings[index];
}
EXPORT_SYMBOL(st_magn_get_settings);
int st_magn_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *mdata = iio_priv(indio_dev);
int irq = mdata->get_irq_data_ready(indio_dev);
int err;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &magn_info;
mutex_init(&mdata->tb.buf_lock);
err = st_sensors_power_enable(indio_dev);
if (err)
return err;
err = st_sensors_check_device_support(indio_dev,
ARRAY_SIZE(st_magn_sensors_settings),
st_magn_sensors_settings);
err = st_sensors_verify_id(indio_dev);
if (err < 0)
goto st_magn_power_off;
mdata->num_data_channels = ST_MAGN_NUMBER_DATA_CHANNELS;
mdata->multiread_bit = mdata->sensor_settings->multi_read_bit;
indio_dev->channels = mdata->sensor_settings->ch;
indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
@ -507,7 +519,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
if (err < 0)
goto st_magn_power_off;
if (irq > 0) {
if (mdata->irq > 0) {
err = st_sensors_allocate_trigger(indio_dev,
ST_MAGN_TRIGGER_OPS);
if (err < 0)
@ -524,7 +536,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev)
return 0;
st_magn_device_register_error:
if (irq > 0)
if (mdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_magn_probe_trigger_error:
st_magn_deallocate_ring(indio_dev);
@ -542,7 +554,7 @@ void st_magn_common_remove(struct iio_dev *indio_dev)
st_sensors_power_disable(indio_dev);
iio_device_unregister(indio_dev);
if (mdata->get_irq_data_ready(indio_dev) > 0)
if (mdata->irq > 0)
st_sensors_deallocate_trigger(indio_dev);
st_magn_deallocate_ring(indio_dev);

View File

@ -55,21 +55,33 @@ MODULE_DEVICE_TABLE(of, st_magn_of_match);
#endif
static int st_magn_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
const struct st_sensor_settings *settings;
struct st_sensor_data *mdata;
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&client->dev, st_magn_of_match,
client->name, sizeof(client->name));
settings = st_magn_get_settings(client->name);
if (!settings) {
dev_err(&client->dev, "device name %s not recognized.\n",
client->name);
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*mdata));
if (!indio_dev)
return -ENOMEM;
mdata = iio_priv(indio_dev);
st_sensors_of_name_probe(&client->dev, st_magn_of_match,
client->name, sizeof(client->name));
mdata->sensor_settings = (struct st_sensor_settings *)settings;
st_sensors_i2c_configure(indio_dev, client, mdata);
err = st_sensors_i2c_configure(indio_dev, client);
if (err < 0)
return err;
err = st_magn_common_probe(indio_dev);
if (err < 0)

View File

@ -51,19 +51,31 @@ MODULE_DEVICE_TABLE(of, st_magn_of_match);
static int st_magn_spi_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
const struct st_sensor_settings *settings;
struct st_sensor_data *mdata;
struct iio_dev *indio_dev;
int err;
st_sensors_of_name_probe(&spi->dev, st_magn_of_match,
spi->modalias, sizeof(spi->modalias));
settings = st_magn_get_settings(spi->modalias);
if (!settings) {
dev_err(&spi->dev, "device name %s not recognized.\n",
spi->modalias);
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*mdata));
if (!indio_dev)
return -ENOMEM;
mdata = iio_priv(indio_dev);
mdata->sensor_settings = (struct st_sensor_settings *)settings;
st_sensors_of_name_probe(&spi->dev, st_magn_of_match,
spi->modalias, sizeof(spi->modalias));
st_sensors_spi_configure(indio_dev, spi, mdata);
err = st_sensors_spi_configure(indio_dev, spi);
if (err < 0)
return err;
err = st_magn_common_probe(indio_dev);
if (err < 0)

View File

@ -26,6 +26,17 @@ config DS1803
To compile this driver as a module, choose M here: the
module will be called ds1803.
config MAX5432
tristate "Maxim MAX5432-MAX5435 Digital Potentiometer driver"
depends on I2C
help
Say yes here to build support for the Maxim
MAX5432, MAX5433, MAX5434 and MAX5435 digital
potentiometer chips.
To compile this driver as a module, choose M here: the
module will be called max5432.
config MAX5481
tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver"
depends on SPI

View File

@ -6,6 +6,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AD5272) += ad5272.o
obj-$(CONFIG_DS1803) += ds1803.o
obj-$(CONFIG_MAX5432) += max5432.o
obj-$(CONFIG_MAX5481) += max5481.o
obj-$(CONFIG_MAX5487) += max5487.o
obj-$(CONFIG_MCP4018) += mcp4018.o

View File

@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Maxim Integrated MAX5432-MAX5435 digital potentiometer driver
* Copyright (C) 2019 Martin Kaiser <martin@kaiser.cx>
*
* Datasheet:
* https://datasheets.maximintegrated.com/en/ds/MAX5432-MAX5435.pdf
*/
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
/* All chip variants have 32 wiper positions. */
#define MAX5432_MAX_POS 31
#define MAX5432_OHM_50K (50 * 1000)
#define MAX5432_OHM_100K (100 * 1000)
/* Update the volatile (currently active) setting. */
#define MAX5432_CMD_VREG 0x11
struct max5432_data {
struct i2c_client *client;
unsigned long ohm;
};
static const struct iio_chan_spec max5432_channels[] = {
{
.type = IIO_RESISTANCE,
.indexed = 1,
.output = 1,
.channel = 0,
.address = MAX5432_CMD_VREG,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
}
};
static int max5432_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct max5432_data *data = iio_priv(indio_dev);
if (mask != IIO_CHAN_INFO_SCALE)
return -EINVAL;
if (unlikely(data->ohm > INT_MAX))
return -ERANGE;
*val = data->ohm;
*val2 = MAX5432_MAX_POS;
return IIO_VAL_FRACTIONAL;
}
static int max5432_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct max5432_data *data = iio_priv(indio_dev);
u8 data_byte;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
if (val < 0 || val > MAX5432_MAX_POS)
return -EINVAL;
if (val2 != 0)
return -EINVAL;
/* Wiper position is in bits D7-D3. (D2-D0 are don't care bits.) */
data_byte = val << 3;
return i2c_smbus_write_byte_data(data->client, chan->address,
data_byte);
}
static const struct iio_info max5432_info = {
.read_raw = max5432_read_raw,
.write_raw = max5432_write_raw,
};
static int max5432_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct iio_dev *indio_dev;
struct max5432_data *data;
indio_dev = devm_iio_device_alloc(dev, sizeof(struct max5432_data));
if (!indio_dev)
return -ENOMEM;
i2c_set_clientdata(client, indio_dev);
data = iio_priv(indio_dev);
data->client = client;
data->ohm = (unsigned long)of_device_get_match_data(dev);
indio_dev->dev.parent = dev;
indio_dev->info = &max5432_info;
indio_dev->channels = max5432_channels;
indio_dev->num_channels = ARRAY_SIZE(max5432_channels);
indio_dev->name = client->name;
return devm_iio_device_register(dev, indio_dev);
}
static const struct of_device_id max5432_dt_ids[] = {
{ .compatible = "maxim,max5432", .data = (void *)MAX5432_OHM_50K },
{ .compatible = "maxim,max5433", .data = (void *)MAX5432_OHM_100K },
{ .compatible = "maxim,max5434", .data = (void *)MAX5432_OHM_50K },
{ .compatible = "maxim,max5435", .data = (void *)MAX5432_OHM_100K },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, max5432_dt_ids);
static struct i2c_driver max5432_driver = {
.driver = {
.name = "max5432",
.of_match_table = of_match_ptr(max5432_dt_ids),
},
.probe = max5432_probe,
};
module_i2c_driver(max5432_driver);
MODULE_AUTHOR("Martin Kaiser <martin@kaiser.cx>");
MODULE_DESCRIPTION("max5432-max5435 digital potentiometers");
MODULE_LICENSE("GPL v2");

View File

@ -39,26 +39,29 @@ static int cros_ec_baro_read(struct iio_dev *indio_dev,
{
struct cros_ec_baro_state *st = iio_priv(indio_dev);
u16 data = 0;
int ret = IIO_VAL_INT;
int ret;
int idx = chan->scan_index;
mutex_lock(&st->core.cmd_lock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
(s16 *)&data) < 0)
ret = -EIO;
ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
(s16 *)&data);
if (ret)
break;
*val = data;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
if (cros_ec_motion_send_host_cmd(&st->core, 0)) {
ret = -EIO;
ret = cros_ec_motion_send_host_cmd(&st->core, 0);
if (ret)
break;
}
*val = st->core.resp->sensor_range.ret;
/* scale * in_pressure_raw --> kPa */
@ -152,8 +155,6 @@ static int cros_ec_baro_probe(struct platform_device *pdev)
channel->ext_info = cros_ec_sensors_ext_info;
channel->scan_type.sign = 'u';
state->core.calib[0] = 0;
/* Sensor specific */
switch (state->core.type) {
case MOTIONSENSE_TYPE_BARO:

View File

@ -243,10 +243,10 @@ static int hp03_probe(struct i2c_client *client,
* which has it's dedicated I2C address and contains
* the calibration constants for the sensor.
*/
priv->eeprom_client = i2c_new_dummy(client->adapter, HP03_EEPROM_ADDR);
if (!priv->eeprom_client) {
priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR);
if (IS_ERR(priv->eeprom_client)) {
dev_err(dev, "New EEPROM I2C device failed\n");
return -ENODEV;
return PTR_ERR(priv->eeprom_client);
}
priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client,

View File

@ -41,6 +41,7 @@ static const struct st_sensors_platform_data default_press_pdata = {
.drdy_int_pin = 1,
};
const struct st_sensor_settings *st_press_get_settings(const char *name);
int st_press_common_probe(struct iio_dev *indio_dev);
void st_press_common_remove(struct iio_dev *indio_dev);

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