Merge tag 'iio-for-4.21a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Nov 2018 08:39:45 +0000 (09:39 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Nov 2018 08:39:45 +0000 (09:39 +0100)
Jonathan writes:

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

Along with the headline feature of 5 new drivers, we have the
substantial addition of auxilliary sensor support on the lsm6sdx
parts for ST.  There has also been a good set of staging cleanup
in this period with more underway.

An ever increasing number of devices supported with just a new
ID which is a good sign that at least some manufacturers are
continuing to stabilise their interfaces.

New device support,
* ad7124
  - New driver supporting Analog Devices' ad7124-4 and ad7124-8 parts
    with the inevitable DT binding.
* ad7949
  - New driver supporting Analog Devices' ad7949, AD7682 and AD7689 ADCs.
* rm3100
  - New driver supporting PNIs RM3100 magnometer with bindings and
    vendor prefix.
* ti-dac7311
  - New driver supporting DAC7311DAC6311 and DAC5311 TI DACs, with
    DT bindings.
* vcnl5035
  - New driver supporting the light sensor part of the VCNL4035, with
    DT bindings

Features,
* bindings
  - Add a generic ADC channel binding as we keep reinventing this
    wheel.
* adc128s052
  - Add IDs for additional pin compatible parts.
  - Add APCI ID seen on E3940 UP squared boards.
* ad_sigma_delta
  - Allow for custom data register overiding default.
* kxcjk1013
  - Add KIOX0009 ACPI ID as seen on the Acer One 10.
* lsm6dsx
  - Rework leading to...
  - External sensor support using the built in I2C master.
  - Initial support for a slave lis2mdl magnetometer.
* meson-saradc
  - Add temperature sensor support and bindings.
* st_magn
  - New ID for lsm9dsl_magn with bindings
  - New ID for lis3de accelerometer
* tpl0102
  - Add supprot for IIO_AVAIL_RANGE to report the range available
    from this device to userspace and in kernel users.

Cleanups and minor fixes
* tools
  - Allow outside specification of CFLAGS
* ad2s90
  - Handle and spi_read error.
  - Handle spi_setup failure
  - Drop a pointless assignment.
  - Prevent a potentail race by moving device registration to after
    all other setup.
  - Add missing scale attribute.
  - Add a sanity check on channel type before trying to read it.
* ad2s1210
  - Move to modern gpio descriptors.
  - Drop a gpioin flag which made no sense as far as we can tell.
  - Add dt table (bindings doc to follow when this is ready for
    moving out of staging).
* ad5933
  - Drop camel-case naming of ext_clk_hz.
  - White space fixes.
* ad7150
  - Local variable to shorten overly long line.
  - Alignment and line break fixes.
ad7280a
  - Handle an error path that was previously ignored.
  - Use crc8.h to build the crc table replacing custom code.
  - Avoid unecessary cast.
  - Power down the device if an error happens in probe
  - Use devm routines to simplify probe and remove.
* ad7606
  - Alignment fixes.
* ad7780
  - This worked as long as by coincidence an uninitialized value
    was 0.  Lets not rely on that.
  - Ensure gain update is only used with the ad778x chips that
    actually support it.
  - Tidy up pattern mask generation.
  - Read regulator when scale is requested (which should be infrequent)
    as it might have changed from initialization.
* ad7816
  - Move to modern gpio descriptors
  - Don't use a busy_pin for ad7818 as there isn't one.
  - Ensure RD/WR and CONVST pins are outputs (previously they
    were brought up as inputs which doesn't seem to make any sense)
  - DT id table.
* adc128s052
  - SPDX
* adt7316
  - Alignment fix.
  - Fix data reading.  When using I2C the driver never actually
    used the value read.  This has been broken a very long time
    hence no rush to fix it now + the driver is undergoing a lot
    of cleanup.
  - Sanity check that the i2c read didn't fail to actually read
    anything.
* dpot-dac
  - Mark a switch full through with slightly different text so that
    gcc doesn't warn on it.
* gyro-adc
  - Fix a wrong file in the MAINTAINERS entry and add binding doc to the
    listed files.
* ina2xx
  - Add some early returns to clarify error paths in switch.
* lsm6dsx
  - MAINTAINERS entry.
* max11100
  - SPDX
* max9611
  - SPDX
* mcp4131
  - use of_device_get_match_data in preference to spi_get_device_id
    approach.
* rcar-adc
  - SPDX
* sc27xx
  - Add ADC conversion timeout support to avoid possible fault.
* ssp_sensors
  - Don't free managed resources manually.
* st-magn
  - Add a comment to avoid future confusion over when to use -magn
    postfix (on multi chip in package parts)
  - Add BDU register for LIS3MDL where it seems to have been missed.
* st-sensors
  - Minor spelling, grammar etc fixes.
* tpl0102
  - Use a pointer rather than an index of an array to improve conciseness.

* tag 'iio-for-4.21a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (80 commits)
  Staging: iio: adt7316: Add an extra check for 'ret' equals to 0
  Staging: iio: adt7316: Fix i2c data reading, set the data field
  dt-bindings: iio: adc: Add docs for ad7124
  iio: adc: Add ad7124 support
  dt-bindings: iio: adc: Add common ADCs properties to a separate file
  iio: ad_sigma_delta: Allow to provide custom data register address
  staging: iio: ad7816: Add device tree table.
  iio: imu: st_lsm6dsx: add entry in MAINTAINERS file
  iio: potentiometer: mcp4131: use of_device_get_match_data()
  staging: iio: adc: ad7280a: use devm_* APIs
  staging: iio: adc: ad7280a: power down the device on error in probe
  dt-bindings: iio: imu: st_lsm6dsx: add support to i2c pullup resistors
  iio: imu: st_lsm6dsx: add hw FIFO support to i2c controller
  iio: imu: st_lsm6dsx: add st_lsm6dsx_push_tagged_data routine
  iio: imu: st_lsm6dsx: add i2c embedded controller support
  iio: imu: st_lsm6dsx: introduce st_lsm6dsx_sensor_set_enable routine
  iio: imu: st_lsm6dsx: introduce ST_LSM6DSX_ID_EXT sensor ids
  iio: imu: st_lsm6dsx: remove static from st_lsm6dsx_set_watermark
  iio: imu: st_lsm6dsx: reload trimming parameter at bootstrap
  iio: imu: st_lsm6dsx: introduce locked read/write utility routines
  ...

74 files changed:
Documentation/devicetree/bindings/iio/adc/ad7949.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt
Documentation/devicetree/bindings/iio/dac/ti,dac7311.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
Documentation/devicetree/bindings/iio/light/vcnl4035.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/st-sensors.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
MAINTAINERS
drivers/iio/accel/Kconfig
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/st_accel.h
drivers/iio/accel/st_accel_core.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/st_accel_spi.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad7124.c [new file with mode: 0644]
drivers/iio/adc/ad7949.c [new file with mode: 0644]
drivers/iio/adc/ad_sigma_delta.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/max11100.c
drivers/iio/adc/max9611.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/rcar-gyroadc.c
drivers/iio/adc/sc27xx_adc.c
drivers/iio/adc/ti-adc128s052.c
drivers/iio/common/ssp_sensors/ssp_dev.c
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/common/st_sensors/st_sensors_trigger.c
drivers/iio/dac/Kconfig
drivers/iio/dac/Makefile
drivers/iio/dac/dpot-dac.c
drivers/iio/dac/ti-dac7311.c [new file with mode: 0644]
drivers/iio/imu/st_lsm6dsx/Makefile
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c [new file with mode: 0644]
drivers/iio/light/Kconfig
drivers/iio/light/Makefile
drivers/iio/light/vcnl4035.c [new file with mode: 0644]
drivers/iio/magnetometer/Kconfig
drivers/iio/magnetometer/Makefile
drivers/iio/magnetometer/rm3100-core.c [new file with mode: 0644]
drivers/iio/magnetometer/rm3100-i2c.c [new file with mode: 0644]
drivers/iio/magnetometer/rm3100-spi.c [new file with mode: 0644]
drivers/iio/magnetometer/rm3100.h [new file with mode: 0644]
drivers/iio/magnetometer/st_magn.h
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/magnetometer/st_magn_i2c.c
drivers/iio/magnetometer/st_magn_spi.c
drivers/iio/potentiometer/mcp4131.c
drivers/iio/potentiometer/tpl0102.c
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/adc/ad7280a.c
drivers/staging/iio/adc/ad7606.c
drivers/staging/iio/adc/ad7780.c
drivers/staging/iio/adc/ad7816.c
drivers/staging/iio/addac/adt7316-i2c.c
drivers/staging/iio/addac/adt7316.c
drivers/staging/iio/addac/adt7316.h
drivers/staging/iio/cdc/ad7150.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/iio/resolver/ad2s1210.c
drivers/staging/iio/resolver/ad2s1210.h [deleted file]
drivers/staging/iio/resolver/ad2s90.c
include/linux/iio/adc/ad_sigma_delta.h
include/linux/iio/common/st_sensors.h
include/linux/platform_data/st_sensors_pdata.h
tools/iio/Makefile

diff --git a/Documentation/devicetree/bindings/iio/adc/ad7949.txt b/Documentation/devicetree/bindings/iio/adc/ad7949.txt
new file mode 100644 (file)
index 0000000..c7f5057
--- /dev/null
@@ -0,0 +1,16 @@
+* Analog Devices AD7949/AD7682/AD7689
+
+Required properties:
+ - compatible: Should be one of
+       * "adi,ad7949"
+       * "adi,ad7682"
+       * "adi,ad7689"
+ - reg: spi chip select number for the device
+ - vref-supply: The regulator supply for ADC reference voltage
+
+Example:
+adc@0 {
+       compatible = "adi,ad7949";
+       reg = <0>;
+       vref-supply = <&vdd_supply>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/adc.txt b/Documentation/devicetree/bindings/iio/adc/adc.txt
new file mode 100644 (file)
index 0000000..5bbaa33
--- /dev/null
@@ -0,0 +1,23 @@
+Common ADCs properties
+
+Optional properties for child nodes:
+- bipolar : Boolean, if set the channel is used in bipolar mode.
+- diff-channels : Differential channels muxed for this ADC. The first value
+               specifies the positive input pin, the second value the negative
+               input pin.
+
+Example:
+       adc@0 {
+               compatible = "some,adc";
+               ...
+               channel@0 {
+                       bipolar;
+                       diff-channels = <0 1>;
+                       ...
+               };
+
+               channel@1 {
+                       diff-channels = <2 3>;
+                       ...
+               };
+       };
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt b/Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt
new file mode 100644 (file)
index 0000000..416273d
--- /dev/null
@@ -0,0 +1,75 @@
+Analog Devices AD7124 ADC device driver
+
+Required properties for the AD7124:
+       - compatible: Must be one of "adi,ad7124-4" or "adi,ad7124-8"
+       - reg: SPI chip select number for the device
+       - spi-max-frequency: Max SPI frequency to use
+               see: Documentation/devicetree/bindings/spi/spi-bus.txt
+       - clocks: phandle to the master clock (mclk)
+               see: Documentation/devicetree/bindings/clock/clock-bindings.txt
+       - clock-names: Must be "mclk".
+       - interrupts: IRQ line for the ADC
+               see: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+         Required properties:
+               * #address-cells: Must be 1.
+               * #size-cells: Must be 0.
+
+         Subnode(s) represent the external channels which are connected to the ADC.
+         Each subnode represents one channel and has the following properties:
+               Required properties:
+                       * reg: The channel number. It can have up to 4 channels on ad7124-4
+                         and 8 channels on ad7124-8, numbered from 0 to 15.
+                       * diff-channels: see: Documentation/devicetree/bindings/iio/adc/adc.txt
+
+               Optional properties:
+                       * bipolar: see: Documentation/devicetree/bindings/iio/adc/adc.txt
+                       * adi,reference-select: Select the reference source to use when
+                         converting on the the specific channel. Valid values are:
+                         0: REFIN1(+)/REFIN1(−).
+                         1: REFIN2(+)/REFIN2(−).
+                         3: AVDD
+                         If this field is left empty, internal reference is selected.
+
+Optional properties:
+       - refin1-supply: refin1 supply can be used as reference for conversion.
+       - refin2-supply: refin2 supply can be used as reference for conversion.
+       - avdd-supply: avdd supply can be used as reference for conversion.
+
+Example:
+       adc@0 {
+               compatible = "adi,ad7124-4";
+               reg = <0>;
+               spi-max-frequency = <5000000>;
+               interrupts = <25 2>;
+               interrupt-parent = <&gpio>;
+               refin1-supply = <&adc_vref>;
+               clocks = <&ad7124_mclk>;
+               clock-names = "mclk";
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               channel@0 {
+                       reg = <0>;
+                       diff-channels = <0 1>;
+                       adi,reference-select = <0>;
+               };
+
+               channel@1 {
+                       reg = <1>;
+                       bipolar;
+                       diff-channels = <2 3>;
+                       adi,reference-select = <0>;
+               };
+
+               channel@2 {
+                       reg = <2>;
+                       diff-channels = <4 5>;
+               };
+
+               channel@3 {
+                       reg = <3>;
+                       diff-channels = <6 7>;
+               };
+       };
index 54b823f3a45301d63ff594783f07b015e7f6c5d2..325090e43ce6b226972ea1b0efbd1df5157133cf 100644 (file)
@@ -22,6 +22,12 @@ Required properties:
 - vref-supply: the regulator supply for the ADC reference voltage
 - #io-channel-cells: must be 1, see ../iio-bindings.txt
 
+Optional properties:
+- nvmem-cells:         phandle to the temperature_calib eFuse cells
+- nvmem-cell-names:    if present (to enable the temperature sensor
+                       calibration) this must contain "temperature_calib"
+
+
 Example:
        saradc: adc@8680 {
                compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc";
index daa2b2c294285f4e717d25d473690582a3bc0329..c07ce1a3f5c4f6ddad158591c19edc22e3f050c7 100644 (file)
@@ -1,7 +1,14 @@
 * Texas Instruments' ADC128S052, ADC122S021 and ADC124S021 ADC chip
 
 Required properties:
- - compatible: Should be "ti,adc128s052", "ti,adc122s021" or "ti,adc124s021"
+ - compatible: Should be one of:
+   - "ti,adc128s052"
+   - "ti,adc122s021"
+   - "ti,adc122s051"
+   - "ti,adc122s101"
+   - "ti,adc124s021"
+   - "ti,adc124s051"
+   - "ti,adc124s101"
  - reg: spi chip select number for the device
  - vref-supply: The regulator supply for ADC reference voltage
 
diff --git a/Documentation/devicetree/bindings/iio/dac/ti,dac7311.txt b/Documentation/devicetree/bindings/iio/dac/ti,dac7311.txt
new file mode 100644 (file)
index 0000000..e5a507d
--- /dev/null
@@ -0,0 +1,23 @@
+TI DAC7311 device tree bindings
+
+Required properties:
+- compatible: must be set to:
+       * "ti,dac7311"
+       * "ti,dac6311"
+       * "ti,dac5311"
+- reg: spi chip select number for the device
+- vref-supply: The regulator supply for ADC reference voltage
+
+Optional properties:
+- spi-max-frequency: Max SPI frequency to use
+
+Example:
+
+       spi_master {
+               dac@0 {
+                       compatible = "ti,dac7311";
+                       reg = <0>; /* CS0 */
+                       spi-max-frequency = <1000000>;
+                       vref-supply = <&vdd_supply>;
+               };
+       };
index 879322ad50fdd2dcee6a30808e687f8994e3e2b7..69d53d98d0f0f131789c0b5c7318613ba530e0c1 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
 Optional properties:
 - st,drdy-int-pin: the pin on the package that will be used to signal
   "data ready" (valid values: 1 or 2).
+- st,pullups : enable/disable internal i2c controller pullup resistors.
 - drive-open-drain: the interrupt/data ready line will be configured
   as open drain, which is useful if several sensors share the same
   interrupt line. This is a boolean property.
diff --git a/Documentation/devicetree/bindings/iio/light/vcnl4035.txt b/Documentation/devicetree/bindings/iio/light/vcnl4035.txt
new file mode 100644 (file)
index 0000000..c07c7f0
--- /dev/null
@@ -0,0 +1,18 @@
+VISHAY VCNL4035 -  Ambient Light and proximity sensor
+
+Link to datasheet: https://www.vishay.com/docs/84251/vcnl4035x01.pdf
+
+Required properties:
+
+       -compatible: should be "vishay,vcnl4035"
+       -reg: I2C address of the sensor, should be 0x60
+       -interrupts: interrupt mapping for GPIO IRQ (level active low)
+
+Example:
+
+light-sensor@60 {
+       compatible = "vishay,vcnl4035";
+       reg = <0x60>;
+       interrupt-parent = <&gpio4>;
+       interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+};
diff --git a/Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt b/Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt
new file mode 100644 (file)
index 0000000..497c932
--- /dev/null
@@ -0,0 +1,20 @@
+* PNI RM3100 3-axis magnetometer sensor
+
+Required properties:
+
+- compatible : should be "pni,rm3100"
+- reg : the I2C address or SPI chip select number of the sensor.
+
+Optional properties:
+
+- interrupts: data ready (DRDY) from the chip.
+  The interrupts can be triggered on level high.
+
+Example:
+
+rm3100: rm3100@20 {
+       compatible = "pni,rm3100";
+       reg = <0x20>;
+       interrupt-parent = <&gpio0>;
+       interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+};
index 6f626f73417ee6aeccc78eabeb45a86994c93186..ddcb95509599edc0d1122f257c62c89f5c7b59f2 100644 (file)
@@ -48,6 +48,7 @@ Accelerometers:
 - st,lis3l02dq
 - st,lis2dw12
 - st,lis3dhh
+- st,lis3de
 
 Gyroscopes:
 - st,l3g4200d-gyro
@@ -67,6 +68,7 @@ Magnetometers:
 - st,lsm303dlm-magn
 - st,lis3mdl-magn
 - st,lis2mdl
+- st,lsm9ds1-magn
 
 Pressure sensors:
 - st,lps001wp-press
index 4b1a2a8fcc16185cd5fae518e0e2fb953becac6f..3cfe0c8b8250e806737422efe8208ef7149d045f 100644 (file)
@@ -303,6 +303,7 @@ pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 plathome       Plat'Home Co., Ltd.
 plda   PLDA
 plx    Broadcom Corporation (formerly PLX Technology)
+pni    PNI Sensor Corporation
 portwell       Portwell Inc.
 poslab Poslab Technology Co., Ltd.
 powervr        PowerVR (deprecated, use img)
@@ -415,6 +416,7 @@ vamrs       Vamrs Ltd.
 variscite      Variscite Ltd.
 via    VIA Technologies, Inc.
 virtio Virtual I/O Device Specification, developed by the OASIS consortium
+vishay Vishay Intertechnology, Inc
 vitesse        Vitesse Semiconductor Corporation
 vivante        Vivante Corporation
 vocore VoCore Studio
index 49ae03fac21c366bb1cee675152ab6860532f1a8..f4d94fb0666dbe2be7ceb0c1e210319b61d6d1db 100644 (file)
@@ -845,6 +845,14 @@ S: Supported
 F:     drivers/iio/dac/ad5758.c
 F:     Documentation/devicetree/bindings/iio/dac/ad5758.txt
 
+ANALOG DEVICES INC AD7124 DRIVER
+M:     Stefan Popa <stefan.popa@analog.com>
+L:     linux-iio@vger.kernel.org
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/iio/adc/ad7124.c
+F:     Documentation/devicetree/bindings/iio/adc/adi,ad7124.txt
+
 ANALOG DEVICES INC AD9389B DRIVER
 M:     Hans Verkuil <hans.verkuil@cisco.com>
 L:     linux-media@vger.kernel.org
@@ -11858,6 +11866,13 @@ M:     "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
 S:     Maintained
 F:     drivers/pnp/
 
+PNI RM3100 IIO DRIVER
+M:     Song Qiang <songqiang1304521@gmail.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     drivers/iio/magnetometer/rm3100*
+F:     Documentation/devicetree/bindings/iio/magnetometer/pni,rm3100.txt
+
 POSIX CLOCKS and TIMERS
 M:     Thomas Gleixner <tglx@linutronix.de>
 L:     linux-kernel@vger.kernel.org
@@ -12641,7 +12656,8 @@ RENESAS R-CAR GYROADC DRIVER
 M:     Marek Vasut <marek.vasut@gmail.com>
 L:     linux-iio@vger.kernel.org
 S:     Supported
-F:     drivers/iio/adc/rcar_gyro_adc.c
+F:     Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
+F:     drivers/iio/adc/rcar-gyroadc.c
 
 RENESAS R-CAR I2C DRIVERS
 M:     Wolfram Sang <wsa+renesas@sang-engineering.com>
@@ -14048,6 +14064,14 @@ M:     Jan-Benedict Glaw <jbglaw@lug-owl.de>
 S:     Maintained
 F:     arch/alpha/kernel/srm_env.c
 
+ST LSM6DSx IMU IIO DRIVER
+M:     Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+L:     linux-iio@vger.kernel.org
+W:     http://www.st.com/
+S:     Maintained
+F:     drivers/iio/imu/st_lsm6dsx/
+F:     Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
+
 ST STM32 I2C/SMBUS DRIVER
 M:     Pierre-Yves MORDRET <pierre-yves.mordret@st.com>
 L:     linux-i2c@vger.kernel.org
index 7993a67bd35156e3aed7586cd666d93eb9854b7b..898839ca164ad5f61c97f94218edc9eabdc8555d 100644 (file)
@@ -223,7 +223,7 @@ config IIO_ST_ACCEL_3AXIS
          Say yes here to build support for STMicroelectronics accelerometers:
          LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
          LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL,
-         LNG2DM
+         LNG2DM, LIS3DE
 
          This driver can also be built as a module. If so, these modules
          will be created:
index af53a1084ee537642906fc35e19986b0d5bc508b..8600e4be88adbf623169328ff6e4d84dece0b6e1 100644 (file)
@@ -1489,6 +1489,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
        {"KXCJ1013", KXCJK1013},
        {"KXCJ1008", KXCJ91008},
        {"KXCJ9000", KXCJ91008},
+       {"KIOX0009", KXTJ21009},
        {"KIOX000A", KXCJ91008},
        {"KXTJ1009", KXTJ21009},
        {"SMO8500",  KXCJ91008},
index 2f931e4837e5ea2e3f28a55e2937fc42731bc19d..fd53258656cae5331ca991c73fb5bbfa1dc2cffa 100644 (file)
@@ -56,6 +56,7 @@ enum st_accel_type {
 #define LNG2DM_ACCEL_DEV_NAME          "lng2dm"
 #define LIS2DW12_ACCEL_DEV_NAME                "lis2dw12"
 #define LIS3DHH_ACCEL_DEV_NAME         "lis3dhh"
+#define LIS3DE_ACCEL_DEV_NAME          "lis3de"
 
 /**
 * struct st_sensors_platform_data - default accel platform data
index 3e6fd5a8ac5be13fba3a8bf1d14f75481eafd2a9..f7b47112150883a3c0b2557db1f26e30d3b41047 100644 (file)
@@ -103,6 +103,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                        [4] = LSM330DLC_ACCEL_DEV_NAME,
                        [5] = LSM303AGR_ACCEL_DEV_NAME,
                        [6] = LIS2DH12_ACCEL_DEV_NAME,
+                       [7] = LIS3DE_ACCEL_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
                .odr = {
index 2ca5d1f6ade07ab2dd5d9394f1844f0ed3dbd02b..de8ae4327094b26454181d511c44c3199718eabf 100644 (file)
@@ -98,6 +98,10 @@ static const struct of_device_id st_accel_of_match[] = {
                .compatible = "st,lis2dw12",
                .data = LIS2DW12_ACCEL_DEV_NAME,
        },
+       {
+               .compatible = "st,lis3de",
+               .data = LIS3DE_ACCEL_DEV_NAME,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -135,6 +139,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
        { LIS331DL_ACCEL_DEV_NAME },
        { LIS3LV02DL_ACCEL_DEV_NAME },
        { LIS2DW12_ACCEL_DEV_NAME },
+       { LIS3DE_ACCEL_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
index dcc9bd243a52a1a552cfd4f1736b21a8cb992619..73bfb5d04e2b23af8e8436712ec1d861b7ee3ce1 100644 (file)
@@ -90,6 +90,10 @@ static const struct of_device_id st_accel_of_match[] = {
                .compatible = "st,lis3dhh",
                .data = LIS3DHH_ACCEL_DEV_NAME,
        },
+       {
+               .compatible = "st,lis3de",
+               .data = LIS3DE_ACCEL_DEV_NAME,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -143,6 +147,7 @@ static const struct spi_device_id st_accel_id_table[] = {
        { LIS3LV02DL_ACCEL_DEV_NAME },
        { LIS2DW12_ACCEL_DEV_NAME },
        { LIS3DHH_ACCEL_DEV_NAME },
+       { LIS3DE_ACCEL_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_accel_id_table);
index a52fea8749a9050a553842067a5c2032392ee8df..da9644b508469f5325c4c9bedc94179c3a62f63f 100644 (file)
@@ -10,6 +10,17 @@ config AD_SIGMA_DELTA
        select IIO_BUFFER
        select IIO_TRIGGERED_BUFFER
 
+config AD7124
+       tristate "Analog Devices AD7124 and similar sigma-delta ADCs driver"
+       depends on SPI_MASTER
+       select AD_SIGMA_DELTA
+       help
+         Say yes here to build support for Analog Devices AD7124-4 and AD7124-8
+         SPI analog to digital converters (ADC).
+
+         To compile this driver as a module, choose M here: the module will be
+         called ad7124.
+
 config AD7266
        tristate "Analog Devices AD7265/AD7266 ADC driver"
        depends on SPI_MASTER
@@ -116,6 +127,16 @@ config AD7923
          To compile this driver as a module, choose M here: the
          module will be called ad7923.
 
+config AD7949
+       tristate "Analog Devices AD7949 and similar ADCs driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices
+         AD7949, AD7682, AD7689 8 Channel ADCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad7949.
+
 config AD799X
        tristate "Analog Devices AD799x ADC driver"
        depends on I2C
index a6e6a0b659e2ab3eb921080c1a7f436c9b93453a..07df37f621bd2c06d6c6fe45a1a0e74f988d9f16 100644 (file)
@@ -5,6 +5,7 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
+obj-$(CONFIG_AD7124) += ad7124.o
 obj-$(CONFIG_AD7266) += ad7266.o
 obj-$(CONFIG_AD7291) += ad7291.o
 obj-$(CONFIG_AD7298) += ad7298.o
@@ -14,6 +15,7 @@ obj-$(CONFIG_AD7766) += ad7766.o
 obj-$(CONFIG_AD7791) += ad7791.o
 obj-$(CONFIG_AD7793) += ad7793.o
 obj-$(CONFIG_AD7887) += ad7887.o
+obj-$(CONFIG_AD7949) += ad7949.o
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
new file mode 100644 (file)
index 0000000..7d5e531
--- /dev/null
@@ -0,0 +1,684 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * AD7124 SPI ADC driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
+#include <linux/iio/sysfs.h>
+
+/* AD7124 registers */
+#define AD7124_COMMS                   0x00
+#define AD7124_STATUS                  0x00
+#define AD7124_ADC_CONTROL             0x01
+#define AD7124_DATA                    0x02
+#define AD7124_IO_CONTROL_1            0x03
+#define AD7124_IO_CONTROL_2            0x04
+#define AD7124_ID                      0x05
+#define AD7124_ERROR                   0x06
+#define AD7124_ERROR_EN                0x07
+#define AD7124_MCLK_COUNT              0x08
+#define AD7124_CHANNEL(x)              (0x09 + (x))
+#define AD7124_CONFIG(x)               (0x19 + (x))
+#define AD7124_FILTER(x)               (0x21 + (x))
+#define AD7124_OFFSET(x)               (0x29 + (x))
+#define AD7124_GAIN(x)                 (0x31 + (x))
+
+/* AD7124_STATUS */
+#define AD7124_STATUS_POR_FLAG_MSK     BIT(4)
+
+/* AD7124_ADC_CONTROL */
+#define AD7124_ADC_CTRL_PWR_MSK        GENMASK(7, 6)
+#define AD7124_ADC_CTRL_PWR(x)         FIELD_PREP(AD7124_ADC_CTRL_PWR_MSK, x)
+#define AD7124_ADC_CTRL_MODE_MSK       GENMASK(5, 2)
+#define AD7124_ADC_CTRL_MODE(x)        FIELD_PREP(AD7124_ADC_CTRL_MODE_MSK, x)
+
+/* AD7124_CHANNEL_X */
+#define AD7124_CHANNEL_EN_MSK          BIT(15)
+#define AD7124_CHANNEL_EN(x)           FIELD_PREP(AD7124_CHANNEL_EN_MSK, x)
+#define AD7124_CHANNEL_SETUP_MSK       GENMASK(14, 12)
+#define AD7124_CHANNEL_SETUP(x)        FIELD_PREP(AD7124_CHANNEL_SETUP_MSK, x)
+#define AD7124_CHANNEL_AINP_MSK        GENMASK(9, 5)
+#define AD7124_CHANNEL_AINP(x)         FIELD_PREP(AD7124_CHANNEL_AINP_MSK, x)
+#define AD7124_CHANNEL_AINM_MSK        GENMASK(4, 0)
+#define AD7124_CHANNEL_AINM(x)         FIELD_PREP(AD7124_CHANNEL_AINM_MSK, x)
+
+/* AD7124_CONFIG_X */
+#define AD7124_CONFIG_BIPOLAR_MSK      BIT(11)
+#define AD7124_CONFIG_BIPOLAR(x)       FIELD_PREP(AD7124_CONFIG_BIPOLAR_MSK, x)
+#define AD7124_CONFIG_REF_SEL_MSK      GENMASK(4, 3)
+#define AD7124_CONFIG_REF_SEL(x)       FIELD_PREP(AD7124_CONFIG_REF_SEL_MSK, x)
+#define AD7124_CONFIG_PGA_MSK          GENMASK(2, 0)
+#define AD7124_CONFIG_PGA(x)           FIELD_PREP(AD7124_CONFIG_PGA_MSK, x)
+
+/* AD7124_FILTER_X */
+#define AD7124_FILTER_FS_MSK           GENMASK(10, 0)
+#define AD7124_FILTER_FS(x)            FIELD_PREP(AD7124_FILTER_FS_MSK, x)
+
+enum ad7124_ids {
+       ID_AD7124_4,
+       ID_AD7124_8,
+};
+
+enum ad7124_ref_sel {
+       AD7124_REFIN1,
+       AD7124_REFIN2,
+       AD7124_INT_REF,
+       AD7124_AVDD_REF,
+};
+
+enum ad7124_power_mode {
+       AD7124_LOW_POWER,
+       AD7124_MID_POWER,
+       AD7124_FULL_POWER,
+};
+
+static const unsigned int ad7124_gain[8] = {
+       1, 2, 4, 8, 16, 32, 64, 128
+};
+
+static const int ad7124_master_clk_freq_hz[3] = {
+       [AD7124_LOW_POWER] = 76800,
+       [AD7124_MID_POWER] = 153600,
+       [AD7124_FULL_POWER] = 614400,
+};
+
+static const char * const ad7124_ref_names[] = {
+       [AD7124_REFIN1] = "refin1",
+       [AD7124_REFIN2] = "refin2",
+       [AD7124_INT_REF] = "int",
+       [AD7124_AVDD_REF] = "avdd",
+};
+
+struct ad7124_chip_info {
+       unsigned int num_inputs;
+};
+
+struct ad7124_channel_config {
+       enum ad7124_ref_sel refsel;
+       bool bipolar;
+       unsigned int ain;
+       unsigned int vref_mv;
+       unsigned int pga_bits;
+       unsigned int odr;
+};
+
+struct ad7124_state {
+       const struct ad7124_chip_info *chip_info;
+       struct ad_sigma_delta sd;
+       struct ad7124_channel_config channel_config[4];
+       struct regulator *vref[4];
+       struct clk *mclk;
+       unsigned int adc_control;
+       unsigned int num_channels;
+};
+
+static const struct iio_chan_spec ad7124_channel_template = {
+       .type = IIO_VOLTAGE,
+       .indexed = 1,
+       .differential = 1,
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+               BIT(IIO_CHAN_INFO_SCALE) |
+               BIT(IIO_CHAN_INFO_OFFSET) |
+               BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .scan_type = {
+               .sign = 'u',
+               .realbits = 24,
+               .storagebits = 32,
+               .shift = 8,
+               .endianness = IIO_BE,
+       },
+};
+
+static struct ad7124_chip_info ad7124_chip_info_tbl[] = {
+       [ID_AD7124_4] = {
+               .num_inputs = 8,
+       },
+       [ID_AD7124_8] = {
+               .num_inputs = 16,
+       },
+};
+
+static int ad7124_find_closest_match(const int *array,
+                                    unsigned int size, int val)
+{
+       int i, idx;
+       unsigned int diff_new, diff_old;
+
+       diff_old = U32_MAX;
+       idx = 0;
+
+       for (i = 0; i < size; i++) {
+               diff_new = abs(val - array[i]);
+               if (diff_new < diff_old) {
+                       diff_old = diff_new;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static int ad7124_spi_write_mask(struct ad7124_state *st,
+                                unsigned int addr,
+                                unsigned long mask,
+                                unsigned int val,
+                                unsigned int bytes)
+{
+       unsigned int readval;
+       int ret;
+
+       ret = ad_sd_read_reg(&st->sd, addr, bytes, &readval);
+       if (ret < 0)
+               return ret;
+
+       readval &= ~mask;
+       readval |= val;
+
+       return ad_sd_write_reg(&st->sd, addr, bytes, readval);
+}
+
+static int ad7124_set_mode(struct ad_sigma_delta *sd,
+                          enum ad_sigma_delta_mode mode)
+{
+       struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
+
+       st->adc_control &= ~AD7124_ADC_CTRL_MODE_MSK;
+       st->adc_control |= AD7124_ADC_CTRL_MODE(mode);
+
+       return ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
+}
+
+static int ad7124_set_channel(struct ad_sigma_delta *sd, unsigned int channel)
+{
+       struct ad7124_state *st = container_of(sd, struct ad7124_state, sd);
+       unsigned int val;
+
+       val = st->channel_config[channel].ain | AD7124_CHANNEL_EN(1) |
+             AD7124_CHANNEL_SETUP(channel);
+
+       return ad_sd_write_reg(&st->sd, AD7124_CHANNEL(channel), 2, val);
+}
+
+static const struct ad_sigma_delta_info ad7124_sigma_delta_info = {
+       .set_channel = ad7124_set_channel,
+       .set_mode = ad7124_set_mode,
+       .has_registers = true,
+       .addr_shift = 0,
+       .read_mask = BIT(6),
+       .data_reg = AD7124_DATA,
+};
+
+static int ad7124_set_channel_odr(struct ad7124_state *st,
+                                 unsigned int channel,
+                                 unsigned int odr)
+{
+       unsigned int fclk, odr_sel_bits;
+       int ret;
+
+       fclk = clk_get_rate(st->mclk);
+       /*
+        * FS[10:0] = fCLK / (fADC x 32) where:
+        * fADC is the output data rate
+        * fCLK is the master clock frequency
+        * FS[10:0] are the bits in the filter register
+        * FS[10:0] can have a value from 1 to 2047
+        */
+       odr_sel_bits = DIV_ROUND_CLOSEST(fclk, odr * 32);
+       if (odr_sel_bits < 1)
+               odr_sel_bits = 1;
+       else if (odr_sel_bits > 2047)
+               odr_sel_bits = 2047;
+
+       ret = ad7124_spi_write_mask(st, AD7124_FILTER(channel),
+                                   AD7124_FILTER_FS_MSK,
+                                   AD7124_FILTER_FS(odr_sel_bits), 3);
+       if (ret < 0)
+               return ret;
+       /* fADC = fCLK / (FS[10:0] x 32) */
+       st->channel_config[channel].odr =
+               DIV_ROUND_CLOSEST(fclk, odr_sel_bits * 32);
+
+       return 0;
+}
+
+static int ad7124_set_channel_gain(struct ad7124_state *st,
+                                  unsigned int channel,
+                                  unsigned int gain)
+{
+       unsigned int res;
+       int ret;
+
+       res = ad7124_find_closest_match(ad7124_gain,
+                                       ARRAY_SIZE(ad7124_gain), gain);
+       ret = ad7124_spi_write_mask(st, AD7124_CONFIG(channel),
+                                   AD7124_CONFIG_PGA_MSK,
+                                   AD7124_CONFIG_PGA(res), 2);
+       if (ret < 0)
+               return ret;
+
+       st->channel_config[channel].pga_bits = res;
+
+       return 0;
+}
+
+static int ad7124_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long info)
+{
+       struct ad7124_state *st = iio_priv(indio_dev);
+       int idx, ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               ret = ad_sigma_delta_single_conversion(indio_dev, chan, val);
+               if (ret < 0)
+                       return ret;
+
+               /* After the conversion is performed, disable the channel */
+               ret = ad_sd_write_reg(&st->sd,
+                                     AD7124_CHANNEL(chan->address), 2,
+                                     st->channel_config[chan->address].ain |
+                                     AD7124_CHANNEL_EN(0));
+               if (ret < 0)
+                       return ret;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               idx = st->channel_config[chan->address].pga_bits;
+               *val = st->channel_config[chan->address].vref_mv;
+               if (st->channel_config[chan->address].bipolar)
+                       *val2 = chan->scan_type.realbits - 1 + idx;
+               else
+                       *val2 = chan->scan_type.realbits + idx;
+
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_OFFSET:
+               if (st->channel_config[chan->address].bipolar)
+                       *val = -(1 << (chan->scan_type.realbits - 1));
+               else
+                       *val = 0;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *val = st->channel_config[chan->address].odr;
+
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ad7124_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long info)
+{
+       struct ad7124_state *st = iio_priv(indio_dev);
+       unsigned int res, gain, full_scale, vref;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (val2 != 0)
+                       return -EINVAL;
+
+               return ad7124_set_channel_odr(st, chan->address, val);
+       case IIO_CHAN_INFO_SCALE:
+               if (val != 0)
+                       return -EINVAL;
+
+               if (st->channel_config[chan->address].bipolar)
+                       full_scale = 1 << (chan->scan_type.realbits - 1);
+               else
+                       full_scale = 1 << chan->scan_type.realbits;
+
+               vref = st->channel_config[chan->address].vref_mv * 1000000LL;
+               res = DIV_ROUND_CLOSEST(vref, full_scale);
+               gain = DIV_ROUND_CLOSEST(res, val2);
+
+               return ad7124_set_channel_gain(st, chan->address, gain);
+       default:
+               return -EINVAL;
+       }
+}
+
+static IIO_CONST_ATTR(in_voltage_scale_available,
+       "0.000001164 0.000002328 0.000004656 0.000009313 0.000018626 0.000037252 0.000074505 0.000149011 0.000298023");
+
+static struct attribute *ad7124_attributes[] = {
+       &iio_const_attr_in_voltage_scale_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7124_attrs_group = {
+       .attrs = ad7124_attributes,
+};
+
+static const struct iio_info ad7124_info = {
+       .read_raw = ad7124_read_raw,
+       .write_raw = ad7124_write_raw,
+       .validate_trigger = ad_sd_validate_trigger,
+       .attrs = &ad7124_attrs_group,
+};
+
+static int ad7124_soft_reset(struct ad7124_state *st)
+{
+       unsigned int readval, timeout;
+       int ret;
+
+       ret = ad_sd_reset(&st->sd, 64);
+       if (ret < 0)
+               return ret;
+
+       timeout = 100;
+       do {
+               ret = ad_sd_read_reg(&st->sd, AD7124_STATUS, 1, &readval);
+               if (ret < 0)
+                       return ret;
+
+               if (!(readval & AD7124_STATUS_POR_FLAG_MSK))
+                       return 0;
+
+               /* The AD7124 requires typically 2ms to power up and settle */
+               usleep_range(100, 2000);
+       } while (--timeout);
+
+       dev_err(&st->sd.spi->dev, "Soft reset failed\n");
+
+       return -EIO;
+}
+
+static int ad7124_init_channel_vref(struct ad7124_state *st,
+                                   unsigned int channel_number)
+{
+       unsigned int refsel = st->channel_config[channel_number].refsel;
+
+       switch (refsel) {
+       case AD7124_REFIN1:
+       case AD7124_REFIN2:
+       case AD7124_AVDD_REF:
+               if (IS_ERR(st->vref[refsel])) {
+                       dev_err(&st->sd.spi->dev,
+                               "Error, trying to use external voltage reference without a %s regulator.\n",
+                               ad7124_ref_names[refsel]);
+                               return PTR_ERR(st->vref[refsel]);
+               }
+               st->channel_config[channel_number].vref_mv =
+                       regulator_get_voltage(st->vref[refsel]);
+               /* Conversion from uV to mV */
+               st->channel_config[channel_number].vref_mv /= 1000;
+               break;
+       case AD7124_INT_REF:
+               st->channel_config[channel_number].vref_mv = 2500;
+               break;
+       default:
+               dev_err(&st->sd.spi->dev, "Invalid reference %d\n", refsel);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ad7124_of_parse_channel_config(struct iio_dev *indio_dev,
+                                         struct device_node *np)
+{
+       struct ad7124_state *st = iio_priv(indio_dev);
+       struct device_node *child;
+       struct iio_chan_spec *chan;
+       unsigned int ain[2], channel = 0, tmp;
+       int ret;
+
+       st->num_channels = of_get_available_child_count(np);
+       if (!st->num_channels) {
+               dev_err(indio_dev->dev.parent, "no channel children\n");
+               return -ENODEV;
+       }
+
+       chan = devm_kcalloc(indio_dev->dev.parent, st->num_channels,
+                           sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+
+       indio_dev->channels = chan;
+       indio_dev->num_channels = st->num_channels;
+
+       for_each_available_child_of_node(np, child) {
+               ret = of_property_read_u32(child, "reg", &channel);
+               if (ret)
+                       goto err;
+
+               ret = of_property_read_u32_array(child, "diff-channels",
+                                                ain, 2);
+               if (ret)
+                       goto err;
+
+               if (ain[0] >= st->chip_info->num_inputs ||
+                   ain[1] >= st->chip_info->num_inputs) {
+                       dev_err(indio_dev->dev.parent,
+                               "Input pin number out of range.\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+               st->channel_config[channel].ain = AD7124_CHANNEL_AINP(ain[0]) |
+                                                 AD7124_CHANNEL_AINM(ain[1]);
+               st->channel_config[channel].bipolar =
+                       of_property_read_bool(child, "bipolar");
+
+               ret = of_property_read_u32(child, "adi,reference-select", &tmp);
+               if (ret)
+                       st->channel_config[channel].refsel = AD7124_INT_REF;
+               else
+                       st->channel_config[channel].refsel = tmp;
+
+               *chan = ad7124_channel_template;
+               chan->address = channel;
+               chan->scan_index = channel;
+               chan->channel = ain[0];
+               chan->channel2 = ain[1];
+
+               chan++;
+       }
+
+       return 0;
+err:
+       of_node_put(child);
+
+       return ret;
+}
+
+static int ad7124_setup(struct ad7124_state *st)
+{
+       unsigned int val, fclk, power_mode;
+       int i, ret;
+
+       fclk = clk_get_rate(st->mclk);
+       if (!fclk)
+               return -EINVAL;
+
+       /* The power mode changes the master clock frequency */
+       power_mode = ad7124_find_closest_match(ad7124_master_clk_freq_hz,
+                                       ARRAY_SIZE(ad7124_master_clk_freq_hz),
+                                       fclk);
+       if (fclk != ad7124_master_clk_freq_hz[power_mode]) {
+               ret = clk_set_rate(st->mclk, fclk);
+               if (ret)
+                       return ret;
+       }
+
+       /* Set the power mode */
+       st->adc_control &= ~AD7124_ADC_CTRL_PWR_MSK;
+       st->adc_control |= AD7124_ADC_CTRL_PWR(power_mode);
+       ret = ad_sd_write_reg(&st->sd, AD7124_ADC_CONTROL, 2, st->adc_control);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < st->num_channels; i++) {
+               val = st->channel_config[i].ain | AD7124_CHANNEL_SETUP(i);
+               ret = ad_sd_write_reg(&st->sd, AD7124_CHANNEL(i), 2, val);
+               if (ret < 0)
+                       return ret;
+
+               ret = ad7124_init_channel_vref(st, i);
+               if (ret < 0)
+                       return ret;
+
+               val = AD7124_CONFIG_BIPOLAR(st->channel_config[i].bipolar) |
+                     AD7124_CONFIG_REF_SEL(st->channel_config[i].refsel);
+               ret = ad_sd_write_reg(&st->sd, AD7124_CONFIG(i), 2, val);
+               if (ret < 0)
+                       return ret;
+               /*
+                * 9.38 SPS is the minimum output data rate supported
+                * regardless of the selected power mode. Round it up to 10 and
+                * set all the enabled channels to this default value.
+                */
+               ret = ad7124_set_channel_odr(st, i, 10);
+       }
+
+       return ret;
+}
+
+static int ad7124_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id;
+       struct ad7124_state *st;
+       struct iio_dev *indio_dev;
+       int i, ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+
+       id = spi_get_device_id(spi);
+       st->chip_info = &ad7124_chip_info_tbl[id->driver_data];
+
+       ad_sd_init(&st->sd, indio_dev, spi, &ad7124_sigma_delta_info);
+
+       spi_set_drvdata(spi, indio_dev);
+
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &ad7124_info;
+
+       ret = ad7124_of_parse_channel_config(indio_dev, spi->dev.of_node);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(st->vref); i++) {
+               if (i == AD7124_INT_REF)
+                       continue;
+
+               st->vref[i] = devm_regulator_get_optional(&spi->dev,
+                                               ad7124_ref_names[i]);
+               if (PTR_ERR(st->vref[i]) == -ENODEV)
+                       continue;
+               else if (IS_ERR(st->vref[i]))
+                       return PTR_ERR(st->vref[i]);
+
+               ret = regulator_enable(st->vref[i]);
+               if (ret)
+                       return ret;
+       }
+
+       st->mclk = devm_clk_get(&spi->dev, "mclk");
+       if (IS_ERR(st->mclk)) {
+               ret = PTR_ERR(st->mclk);
+               goto error_regulator_disable;
+       }
+
+       ret = clk_prepare_enable(st->mclk);
+       if (ret < 0)
+               goto error_regulator_disable;
+
+       ret = ad7124_soft_reset(st);
+       if (ret < 0)
+               goto error_clk_disable_unprepare;
+
+       ret = ad7124_setup(st);
+       if (ret < 0)
+               goto error_clk_disable_unprepare;
+
+       ret = ad_sd_setup_buffer_and_trigger(indio_dev);
+       if (ret < 0)
+               goto error_clk_disable_unprepare;
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&spi->dev, "Failed to register iio device\n");
+               goto error_remove_trigger;
+       }
+
+       return 0;
+
+error_remove_trigger:
+       ad_sd_cleanup_buffer_and_trigger(indio_dev);
+error_clk_disable_unprepare:
+       clk_disable_unprepare(st->mclk);
+error_regulator_disable:
+       for (i = ARRAY_SIZE(st->vref) - 1; i >= 0; i--) {
+               if (!IS_ERR_OR_NULL(st->vref[i]))
+                       regulator_disable(st->vref[i]);
+       }
+
+       return ret;
+}
+
+static int ad7124_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct ad7124_state *st = iio_priv(indio_dev);
+       int i;
+
+       iio_device_unregister(indio_dev);
+       ad_sd_cleanup_buffer_and_trigger(indio_dev);
+       clk_disable_unprepare(st->mclk);
+
+       for (i = ARRAY_SIZE(st->vref) - 1; i >= 0; i--) {
+               if (!IS_ERR_OR_NULL(st->vref[i]))
+                       regulator_disable(st->vref[i]);
+       }
+
+       return 0;
+}
+
+static const struct spi_device_id ad7124_id_table[] = {
+       { "ad7124-4", ID_AD7124_4 },
+       { "ad7124-8", ID_AD7124_8 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ad7124_id_table);
+
+static const struct of_device_id ad7124_of_match[] = {
+       { .compatible = "adi,ad7124-4" },
+       { .compatible = "adi,ad7124-8" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ad7124_of_match);
+
+static struct spi_driver ad71124_driver = {
+       .driver = {
+               .name = "ad7124",
+               .of_match_table = ad7124_of_match,
+       },
+       .probe = ad7124_probe,
+       .remove = ad7124_remove,
+       .id_table = ad7124_id_table,
+};
+module_spi_driver(ad71124_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7124 SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c
new file mode 100644 (file)
index 0000000..ac0ffff
--- /dev/null
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ad7949.c - Analog Devices ADC driver 14/16 bits 4/8 channels
+ *
+ * Copyright (C) 2018 CMC NV
+ *
+ * http://www.analog.com/media/en/technical-documentation/data-sheets/AD7949.pdf
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#define AD7949_MASK_CHANNEL_SEL                GENMASK(9, 7)
+#define AD7949_MASK_TOTAL              GENMASK(13, 0)
+#define AD7949_OFFSET_CHANNEL_SEL      7
+#define AD7949_CFG_READ_BACK           0x1
+#define AD7949_CFG_REG_SIZE_BITS       14
+
+enum {
+       ID_AD7949 = 0,
+       ID_AD7682,
+       ID_AD7689,
+};
+
+struct ad7949_adc_spec {
+       u8 num_channels;
+       u8 resolution;
+};
+
+static const struct ad7949_adc_spec ad7949_adc_spec[] = {
+       [ID_AD7949] = { .num_channels = 8, .resolution = 14 },
+       [ID_AD7682] = { .num_channels = 4, .resolution = 16 },
+       [ID_AD7689] = { .num_channels = 8, .resolution = 16 },
+};
+
+/**
+ * struct ad7949_adc_chip - AD ADC chip
+ * @lock: protects write sequences
+ * @vref: regulator generating Vref
+ * @iio_dev: reference to iio structure
+ * @spi: reference to spi structure
+ * @resolution: resolution of the chip
+ * @cfg: copy of the configuration register
+ * @current_channel: current channel in use
+ * @buffer: buffer to send / receive data to / from device
+ */
+struct ad7949_adc_chip {
+       struct mutex lock;
+       struct regulator *vref;
+       struct iio_dev *indio_dev;
+       struct spi_device *spi;
+       u8 resolution;
+       u16 cfg;
+       unsigned int current_channel;
+       u32 buffer ____cacheline_aligned;
+};
+
+static bool ad7949_spi_cfg_is_read_back(struct ad7949_adc_chip *ad7949_adc)
+{
+       if (!(ad7949_adc->cfg & AD7949_CFG_READ_BACK))
+               return true;
+
+       return false;
+}
+
+static int ad7949_spi_bits_per_word(struct ad7949_adc_chip *ad7949_adc)
+{
+       int ret = ad7949_adc->resolution;
+
+       if (ad7949_spi_cfg_is_read_back(ad7949_adc))
+               ret += AD7949_CFG_REG_SIZE_BITS;
+
+       return ret;
+}
+
+static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val,
+                               u16 mask)
+{
+       int ret;
+       int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
+       int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS;
+       struct spi_message msg;
+       struct spi_transfer tx[] = {
+               {
+                       .tx_buf = &ad7949_adc->buffer,
+                       .len = 4,
+                       .bits_per_word = bits_per_word,
+               },
+       };
+
+       ad7949_adc->cfg = (val & mask) | (ad7949_adc->cfg & ~mask);
+       ad7949_adc->buffer = ad7949_adc->cfg << shift;
+       spi_message_init_with_transfers(&msg, tx, 1);
+       ret = spi_sync(ad7949_adc->spi, &msg);
+
+       /*
+        * This delay is to avoid a new request before the required time to
+        * send a new command to the device
+        */
+       udelay(2);
+       return ret;
+}
+
+static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val,
+                                  unsigned int channel)
+{
+       int ret;
+       int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc);
+       int mask = GENMASK(ad7949_adc->resolution, 0);
+       struct spi_message msg;
+       struct spi_transfer tx[] = {
+               {
+                       .rx_buf = &ad7949_adc->buffer,
+                       .len = 4,
+                       .bits_per_word = bits_per_word,
+               },
+       };
+
+       ret = ad7949_spi_write_cfg(ad7949_adc,
+                                  channel << AD7949_OFFSET_CHANNEL_SEL,
+                                  AD7949_MASK_CHANNEL_SEL);
+       if (ret)
+               return ret;
+
+       ad7949_adc->buffer = 0;
+       spi_message_init_with_transfers(&msg, tx, 1);
+       ret = spi_sync(ad7949_adc->spi, &msg);
+       if (ret)
+               return ret;
+
+       /*
+        * This delay is to avoid a new request before the required time to
+        * send a new command to the device
+        */
+       udelay(2);
+
+       ad7949_adc->current_channel = channel;
+
+       if (ad7949_spi_cfg_is_read_back(ad7949_adc))
+               *val = (ad7949_adc->buffer >> AD7949_CFG_REG_SIZE_BITS) & mask;
+       else
+               *val = ad7949_adc->buffer & mask;
+
+       return 0;
+}
+
+#define AD7949_ADC_CHANNEL(chan) {                             \
+       .type = IIO_VOLTAGE,                                    \
+       .indexed = 1,                                           \
+       .channel = (chan),                                      \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+}
+
+static const struct iio_chan_spec ad7949_adc_channels[] = {
+       AD7949_ADC_CHANNEL(0),
+       AD7949_ADC_CHANNEL(1),
+       AD7949_ADC_CHANNEL(2),
+       AD7949_ADC_CHANNEL(3),
+       AD7949_ADC_CHANNEL(4),
+       AD7949_ADC_CHANNEL(5),
+       AD7949_ADC_CHANNEL(6),
+       AD7949_ADC_CHANNEL(7),
+};
+
+static int ad7949_spi_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
+       int ret;
+
+       if (!val)
+               return -EINVAL;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&ad7949_adc->lock);
+               ret = ad7949_spi_read_channel(ad7949_adc, val, chan->channel);
+               mutex_unlock(&ad7949_adc->lock);
+
+               if (ret < 0)
+                       return ret;
+
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               ret = regulator_get_voltage(ad7949_adc->vref);
+               if (ret < 0)
+                       return ret;
+
+               *val = ret / 5000;
+               return IIO_VAL_INT;
+       }
+
+       return -EINVAL;
+}
+
+static int ad7949_spi_reg_access(struct iio_dev *indio_dev,
+                       unsigned int reg, unsigned int writeval,
+                       unsigned int *readval)
+{
+       struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
+       int ret = 0;
+
+       if (readval)
+               *readval = ad7949_adc->cfg;
+       else
+               ret = ad7949_spi_write_cfg(ad7949_adc,
+                       writeval & AD7949_MASK_TOTAL, AD7949_MASK_TOTAL);
+
+       return ret;
+}
+
+static const struct iio_info ad7949_spi_info = {
+       .read_raw = ad7949_spi_read_raw,
+       .debugfs_reg_access = ad7949_spi_reg_access,
+};
+
+static int ad7949_spi_init(struct ad7949_adc_chip *ad7949_adc)
+{
+       int ret;
+       int val;
+
+       /* Sequencer disabled, CFG readback disabled, IN0 as default channel */
+       ad7949_adc->current_channel = 0;
+       ret = ad7949_spi_write_cfg(ad7949_adc, 0x3C79, AD7949_MASK_TOTAL);
+
+       /*
+        * Do two dummy conversions to apply the first configuration setting.
+        * Required only after the start up of the device.
+        */
+       ad7949_spi_read_channel(ad7949_adc, &val, ad7949_adc->current_channel);
+       ad7949_spi_read_channel(ad7949_adc, &val, ad7949_adc->current_channel);
+
+       return ret;
+}
+
+static int ad7949_spi_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       const struct ad7949_adc_spec *spec;
+       struct ad7949_adc_chip *ad7949_adc;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*ad7949_adc));
+       if (!indio_dev) {
+               dev_err(dev, "can not allocate iio device\n");
+               return -ENOMEM;
+       }
+
+       indio_dev->dev.parent = dev;
+       indio_dev->dev.of_node = dev->of_node;
+       indio_dev->info = &ad7949_spi_info;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = ad7949_adc_channels;
+       spi_set_drvdata(spi, indio_dev);
+
+       ad7949_adc = iio_priv(indio_dev);
+       ad7949_adc->indio_dev = indio_dev;
+       ad7949_adc->spi = spi;
+
+       spec = &ad7949_adc_spec[spi_get_device_id(spi)->driver_data];
+       indio_dev->num_channels = spec->num_channels;
+       ad7949_adc->resolution = spec->resolution;
+
+       ad7949_adc->vref = devm_regulator_get(dev, "vref");
+       if (IS_ERR(ad7949_adc->vref)) {
+               dev_err(dev, "fail to request regulator\n");
+               return PTR_ERR(ad7949_adc->vref);
+       }
+
+       ret = regulator_enable(ad7949_adc->vref);
+       if (ret < 0) {
+               dev_err(dev, "fail to enable regulator\n");
+               return ret;
+       }
+
+       mutex_init(&ad7949_adc->lock);
+
+       ret = ad7949_spi_init(ad7949_adc);
+       if (ret) {
+               dev_err(dev, "enable to init this device: %d\n", ret);
+               goto err;
+       }
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(dev, "fail to register iio device: %d\n", ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       mutex_destroy(&ad7949_adc->lock);
+       regulator_disable(ad7949_adc->vref);
+
+       return ret;
+}
+
+static int ad7949_spi_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct ad7949_adc_chip *ad7949_adc = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       mutex_destroy(&ad7949_adc->lock);
+       regulator_disable(ad7949_adc->vref);
+
+       return 0;
+}
+
+static const struct of_device_id ad7949_spi_of_id[] = {
+       { .compatible = "adi,ad7949" },
+       { .compatible = "adi,ad7682" },
+       { .compatible = "adi,ad7689" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ad7949_spi_of_id);
+
+static const struct spi_device_id ad7949_spi_id[] = {
+       { "ad7949", ID_AD7949  },
+       { "ad7682", ID_AD7682 },
+       { "ad7689", ID_AD7689 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ad7949_spi_id);
+
+static struct spi_driver ad7949_spi_driver = {
+       .driver = {
+               .name           = "ad7949",
+               .of_match_table = ad7949_spi_of_id,
+       },
+       .probe    = ad7949_spi_probe,
+       .remove   = ad7949_spi_remove,
+       .id_table = ad7949_spi_id,
+};
+module_spi_driver(ad7949_spi_driver);
+
+MODULE_AUTHOR("Charles-Antoine Couret <charles-antoine.couret@essensium.com>");
+MODULE_DESCRIPTION("Analog Devices 14/16-bit 8-channel ADC driver");
+MODULE_LICENSE("GPL v2");
index fc9510716ac771633213ad1d6c960b4c8023c7cf..ff5f2da2e1b134d369fbc6ce7180a9ebf0de4ec1 100644 (file)
@@ -278,6 +278,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
 {
        struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
        unsigned int sample, raw_sample;
+       unsigned int data_reg;
        int ret = 0;
 
        if (iio_buffer_enabled(indio_dev))
@@ -305,7 +306,12 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
        if (ret < 0)
                goto out;
 
-       ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA,
+       if (sigma_delta->info->data_reg != 0)
+               data_reg = sigma_delta->info->data_reg;
+       else
+               data_reg = AD_SD_REG_DATA;
+
+       ret = ad_sd_read_reg(sigma_delta, data_reg,
                DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
                &raw_sample);
 
@@ -392,6 +398,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
        struct iio_dev *indio_dev = pf->indio_dev;
        struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
        unsigned int reg_size;
+       unsigned int data_reg;
        uint8_t data[16];
        int ret;
 
@@ -401,18 +408,23 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
                        indio_dev->channels[0].scan_type.shift;
        reg_size = DIV_ROUND_UP(reg_size, 8);
 
+       if (sigma_delta->info->data_reg != 0)
+               data_reg = sigma_delta->info->data_reg;
+       else
+               data_reg = AD_SD_REG_DATA;
+
        switch (reg_size) {
        case 4:
        case 2:
        case 1:
-               ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
-                       reg_size, &data[0]);
+               ret = ad_sd_read_reg_raw(sigma_delta, data_reg, reg_size,
+                       &data[0]);
                break;
        case 3:
                /* We store 24 bit samples in a 32 bit word. Keep the upper
                 * byte set to zero. */
-               ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA,
-                       reg_size, &data[1]);
+               ret = ad_sd_read_reg_raw(sigma_delta, data_reg, reg_size,
+                       &data[1]);
                break;
        }
 
index d1239624187da1997c44c8ba7400f549568b39ff..bdd7cba6f6b0b63f431612e75d169fda13576249 100644 (file)
@@ -250,6 +250,7 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
                        *val2 = chip->shunt_resistor_uohm;
                        return IIO_VAL_FRACTIONAL;
                }
+               return -EINVAL;
 
        case IIO_CHAN_INFO_HARDWAREGAIN:
                switch (chan->address) {
@@ -262,6 +263,7 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
                        *val = chip->range_vbus == 32 ? 1 : 2;
                        return IIO_VAL_INT;
                }
+               return -EINVAL;
        }
 
        return -EINVAL;
index af59ab2e650c7fe147cbb0db427692765db0e8fb..3440539cfdba7323952bed1ba89dace2ff7b2d18 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * iio/adc/max11100.c
  * Maxim max11100 ADC Driver with IIO interface
  *
  * Copyright (C) 2016-17 Renesas Electronics Corporation
  * Copyright (C) 2016-17 Jacopo Mondi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 #include <linux/delay.h>
 #include <linux/kernel.h>
index 643a4e66eb80b2e1d0d11148b534536f8ac3f546..917223d5ff5bb635125bca95c38150471d7e772b 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * iio/adc/max9611.c
  *
@@ -5,10 +6,6 @@
  * 12-bit ADC interface.
  *
  * Copyright (C) 2017 Jacopo Mondi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 /*
index 028ccd218f82a3b0d32b47763d1a2830b3635fd5..26011254ffbc040cbac633f72e52d9c354badcbd 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/iio/iio.h>
 #include <linux/module.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 
 #define MESON_SAR_ADC_MAX_FIFO_SIZE                            32
 #define MESON_SAR_ADC_TIMEOUT                                  100 /* ms */
+#define MESON_SAR_ADC_VOLTAGE_AND_TEMP_CHANNEL                 6
+#define MESON_SAR_ADC_TEMP_OFFSET                              27
+
+/* temperature sensor calibration information in eFuse */
+#define MESON_SAR_ADC_EFUSE_BYTES                              4
+#define MESON_SAR_ADC_EFUSE_BYTE3_UPPER_ADC_VAL                        GENMASK(6, 0)
+#define MESON_SAR_ADC_EFUSE_BYTE3_IS_CALIBRATED                        BIT(7)
+
 /* for use with IIO_VAL_INT_PLUS_MICRO */
 #define MILLION                                                        1000000
 
        .address = _chan,                                               \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
                                BIT(IIO_CHAN_INFO_AVERAGE_RAW),         \
-       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |          \
-                               BIT(IIO_CHAN_INFO_CALIBBIAS) |          \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)          \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_CALIBBIAS) |       \
                                BIT(IIO_CHAN_INFO_CALIBSCALE),          \
        .datasheet_name = "SAR_ADC_CH"#_chan,                           \
 }
 
-/*
- * TODO: the hardware supports IIO_TEMP for channel 6 as well which is
- * currently not supported by this driver.
- */
+#define MESON_SAR_ADC_TEMP_CHAN(_chan) {                               \
+       .type = IIO_TEMP,                                               \
+       .channel = _chan,                                               \
+       .address = MESON_SAR_ADC_VOLTAGE_AND_TEMP_CHANNEL,              \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
+                               BIT(IIO_CHAN_INFO_AVERAGE_RAW),         \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |         \
+                                       BIT(IIO_CHAN_INFO_SCALE),       \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_CALIBBIAS) |       \
+                               BIT(IIO_CHAN_INFO_CALIBSCALE),          \
+       .datasheet_name = "TEMP_SENSOR",                                \
+}
+
 static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
        MESON_SAR_ADC_CHAN(0),
        MESON_SAR_ADC_CHAN(1),
@@ -197,6 +215,19 @@ static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(8),
 };
 
+static const struct iio_chan_spec meson_sar_adc_and_temp_iio_channels[] = {
+       MESON_SAR_ADC_CHAN(0),
+       MESON_SAR_ADC_CHAN(1),
+       MESON_SAR_ADC_CHAN(2),
+       MESON_SAR_ADC_CHAN(3),
+       MESON_SAR_ADC_CHAN(4),
+       MESON_SAR_ADC_CHAN(5),
+       MESON_SAR_ADC_CHAN(6),
+       MESON_SAR_ADC_CHAN(7),
+       MESON_SAR_ADC_TEMP_CHAN(8),
+       IIO_CHAN_SOFT_TIMESTAMP(9),
+};
+
 enum meson_sar_adc_avg_mode {
        NO_AVERAGING = 0x0,
        MEAN_AVERAGING = 0x1,
@@ -225,6 +256,9 @@ struct meson_sar_adc_param {
        u32                                     bandgap_reg;
        unsigned int                            resolution;
        const struct regmap_config              *regmap_config;
+       u8                                      temperature_trimming_bits;
+       unsigned int                            temperature_multiplier;
+       unsigned int                            temperature_divider;
 };
 
 struct meson_sar_adc_data {
@@ -246,6 +280,9 @@ struct meson_sar_adc_priv {
        struct completion                       done;
        int                                     calibbias;
        int                                     calibscale;
+       bool                                    temperature_sensor_calibrated;
+       u8                                      temperature_sensor_coefficient;
+       u16                                     temperature_sensor_adc_val;
 };
 
 static const struct regmap_config meson_sar_adc_regmap_config_gxbb = {
@@ -389,9 +426,16 @@ static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
                           MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
                           regval);
 
-       if (chan->address == 6)
-               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
-                                  MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0);
+       if (chan->address == MESON_SAR_ADC_VOLTAGE_AND_TEMP_CHANNEL) {
+               if (chan->type == IIO_TEMP)
+                       regval = MESON_SAR_ADC_DELTA_10_TEMP_SEL;
+               else
+                       regval = 0;
+
+               regmap_update_bits(priv->regmap,
+                                  MESON_SAR_ADC_DELTA_10,
+                                  MESON_SAR_ADC_DELTA_10_TEMP_SEL, regval);
+       }
 }
 
 static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev,
@@ -506,8 +550,12 @@ static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
                                    enum meson_sar_adc_num_samples avg_samples,
                                    int *val)
 {
+       struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
        int ret;
 
+       if (chan->type == IIO_TEMP && !priv->temperature_sensor_calibrated)
+               return -ENOTSUPP;
+
        ret = meson_sar_adc_lock(indio_dev);
        if (ret)
                return ret;
@@ -555,17 +603,31 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
                break;
 
        case IIO_CHAN_INFO_SCALE:
-               ret = regulator_get_voltage(priv->vref);
-               if (ret < 0) {
-                       dev_err(indio_dev->dev.parent,
-                               "failed to get vref voltage: %d\n", ret);
-                       return ret;
+               if (chan->type == IIO_VOLTAGE) {
+                       ret = regulator_get_voltage(priv->vref);
+                       if (ret < 0) {
+                               dev_err(indio_dev->dev.parent,
+                                       "failed to get vref voltage: %d\n",
+                                       ret);
+                               return ret;
+                       }
+
+                       *val = ret / 1000;
+                       *val2 = priv->param->resolution;
+                       return IIO_VAL_FRACTIONAL_LOG2;
+               } else if (chan->type == IIO_TEMP) {
+                       /* SoC specific multiplier and divider */
+                       *val = priv->param->temperature_multiplier;
+                       *val2 = priv->param->temperature_divider;
+
+                       /* celsius to millicelsius */
+                       *val *= 1000;
+
+                       return IIO_VAL_FRACTIONAL;
+               } else {
+                       return -EINVAL;
                }
 
-               *val = ret / 1000;
-               *val2 = priv->param->resolution;
-               return IIO_VAL_FRACTIONAL_LOG2;
-
        case IIO_CHAN_INFO_CALIBBIAS:
                *val = priv->calibbias;
                return IIO_VAL_INT;
@@ -575,6 +637,13 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
                *val2 = priv->calibscale % MILLION;
                return IIO_VAL_INT_PLUS_MICRO;
 
+       case IIO_CHAN_INFO_OFFSET:
+               *val = DIV_ROUND_CLOSEST(MESON_SAR_ADC_TEMP_OFFSET *
+                                        priv->param->temperature_divider,
+                                        priv->param->temperature_multiplier);
+               *val -= priv->temperature_sensor_adc_val;
+               return IIO_VAL_INT;
+
        default:
                return -EINVAL;
        }
@@ -625,6 +694,65 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
        return 0;
 }
 
+static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev)
+{
+       struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+       u8 *buf, trimming_bits, trimming_mask, upper_adc_val;
+       struct nvmem_cell *temperature_calib;
+       size_t read_len;
+       int ret;
+
+       temperature_calib = devm_nvmem_cell_get(&indio_dev->dev,
+                                               "temperature_calib");
+       if (IS_ERR(temperature_calib)) {
+               ret = PTR_ERR(temperature_calib);
+
+               /*
+                * leave the temperature sensor disabled if no calibration data
+                * was passed via nvmem-cells.
+                */
+               if (ret == -ENODEV)
+                       return 0;
+
+               if (ret != -EPROBE_DEFER)
+                       dev_err(indio_dev->dev.parent,
+                               "failed to get temperature_calib cell\n");
+
+               return ret;
+       }
+
+       read_len = MESON_SAR_ADC_EFUSE_BYTES;
+       buf = nvmem_cell_read(temperature_calib, &read_len);
+       if (IS_ERR(buf)) {
+               dev_err(indio_dev->dev.parent,
+                       "failed to read temperature_calib cell\n");
+               return PTR_ERR(buf);
+       } else if (read_len != MESON_SAR_ADC_EFUSE_BYTES) {
+               kfree(buf);
+               dev_err(indio_dev->dev.parent,
+                       "invalid read size of temperature_calib cell\n");
+               return -EINVAL;
+       }
+
+       trimming_bits = priv->param->temperature_trimming_bits;
+       trimming_mask = BIT(trimming_bits) - 1;
+
+       priv->temperature_sensor_calibrated =
+               buf[3] & MESON_SAR_ADC_EFUSE_BYTE3_IS_CALIBRATED;
+       priv->temperature_sensor_coefficient = buf[2] & trimming_mask;
+
+       upper_adc_val = FIELD_GET(MESON_SAR_ADC_EFUSE_BYTE3_UPPER_ADC_VAL,
+                                 buf[3]);
+
+       priv->temperature_sensor_adc_val = buf[2];
+       priv->temperature_sensor_adc_val |= upper_adc_val << BITS_PER_BYTE;
+       priv->temperature_sensor_adc_val >>= trimming_bits;
+
+       kfree(buf);
+
+       return 0;
+}
+
 static int meson_sar_adc_init(struct iio_dev *indio_dev)
 {
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
@@ -649,10 +777,12 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
 
        meson_sar_adc_stop_sample_engine(indio_dev);
 
-       /* update the channel 6 MUX to select the temperature sensor */
+       /*
+        * disable this bit as seems to be only relevant for Meson6 (based
+        * on the vendor driver), which we don't support at the moment.
+        */
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
-                       MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
-                       MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
+                       MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 0);
 
        /* disable all channels by default */
        regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
@@ -709,6 +839,29 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
        regval |= MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW;
        regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval);
 
+       if (priv->temperature_sensor_calibrated) {
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+                                  MESON_SAR_ADC_DELTA_10_TS_REVE1,
+                                  MESON_SAR_ADC_DELTA_10_TS_REVE1);
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+                                  MESON_SAR_ADC_DELTA_10_TS_REVE0,
+                                  MESON_SAR_ADC_DELTA_10_TS_REVE0);
+
+               /*
+                * set bits [3:0] of the TSC (temperature sensor coefficient)
+                * to get the correct values when reading the temperature.
+                */
+               regval = FIELD_PREP(MESON_SAR_ADC_DELTA_10_TS_C_MASK,
+                                   priv->temperature_sensor_coefficient);
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+                                  MESON_SAR_ADC_DELTA_10_TS_C_MASK, regval);
+       } else {
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+                                  MESON_SAR_ADC_DELTA_10_TS_REVE1, 0);
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+                                  MESON_SAR_ADC_DELTA_10_TS_REVE0, 0);
+       }
+
        ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
        if (ret) {
                dev_err(indio_dev->dev.parent,
@@ -894,6 +1047,17 @@ static const struct meson_sar_adc_param meson_sar_adc_meson8_param = {
        .bandgap_reg = MESON_SAR_ADC_DELTA_10,
        .regmap_config = &meson_sar_adc_regmap_config_meson8,
        .resolution = 10,
+       .temperature_trimming_bits = 4,
+       .temperature_multiplier = 18 * 10000,
+       .temperature_divider = 1024 * 10 * 85,
+};
+
+static const struct meson_sar_adc_param meson_sar_adc_meson8b_param = {
+       .has_bl30_integration = false,
+       .clock_rate = 1150000,
+       .bandgap_reg = MESON_SAR_ADC_DELTA_10,
+       .regmap_config = &meson_sar_adc_regmap_config_meson8,
+       .resolution = 10,
 };
 
 static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = {
@@ -918,12 +1082,12 @@ static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
 };
 
 static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
-       .param = &meson_sar_adc_meson8_param,
+       .param = &meson_sar_adc_meson8b_param,
        .name = "meson-meson8b-saradc",
 };
 
 static const struct meson_sar_adc_data meson_sar_adc_meson8m2_data = {
-       .param = &meson_sar_adc_meson8_param,
+       .param = &meson_sar_adc_meson8b_param,
        .name = "meson-meson8m2-saradc",
 };
 
@@ -1009,9 +1173,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &meson_sar_adc_iio_info;
 
-       indio_dev->channels = meson_sar_adc_iio_channels;
-       indio_dev->num_channels = ARRAY_SIZE(meson_sar_adc_iio_channels);
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(base))
@@ -1078,6 +1239,22 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
 
        priv->calibscale = MILLION;
 
+       if (priv->param->temperature_trimming_bits) {
+               ret = meson_sar_adc_temp_sensor_init(indio_dev);
+               if (ret)
+                       return ret;
+       }
+
+       if (priv->temperature_sensor_calibrated) {
+               indio_dev->channels = meson_sar_adc_and_temp_iio_channels;
+               indio_dev->num_channels =
+                       ARRAY_SIZE(meson_sar_adc_and_temp_iio_channels);
+       } else {
+               indio_dev->channels = meson_sar_adc_iio_channels;
+               indio_dev->num_channels =
+                       ARRAY_SIZE(meson_sar_adc_iio_channels);
+       }
+
        ret = meson_sar_adc_init(indio_dev);
        if (ret)
                goto err;
index 4e982b51bcda7bc4dc1a1cdad5e7b29507e7aac9..2c0d0316d149707f96e069b11711fa2988ae9fa8 100644 (file)
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Renesas R-Car GyroADC driver
  *
  * Copyright 2016 Marek Vasut <marek.vasut@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
  */
 
 #include <linux/module.h>
index 7940b23dcad901baa00784ee48497e0f1dd99ec7..f7f7a18904b45bb7f368843a4dcae60f0ade30a9 100644 (file)
@@ -52,6 +52,9 @@
 /* Timeout (ms) for the trylock of hardware spinlocks */
 #define SC27XX_ADC_HWLOCK_TIMEOUT      5000
 
+/* Timeout (ms) for ADC data conversion according to ADC datasheet */
+#define SC27XX_ADC_RDY_TIMEOUT         100
+
 /* Maximum ADC channel number */
 #define SC27XX_ADC_CHANNEL_MAX         32
 
@@ -223,7 +226,14 @@ static int sc27xx_adc_read(struct sc27xx_adc_data *data, int channel,
        if (ret)
                goto disable_adc;
 
-       wait_for_completion(&data->completion);
+       ret = wait_for_completion_timeout(&data->completion,
+                               msecs_to_jiffies(SC27XX_ADC_RDY_TIMEOUT));
+       if (!ret) {
+               dev_err(data->dev, "read ADC data timeout\n");
+               ret = -ETIMEDOUT;
+       } else {
+               ret = 0;
+       }
 
 disable_adc:
        regmap_update_bits(data->regmap, data->base + SC27XX_ADC_CTL,
index 7cf39b3e2416d152e2384831fd66d9c37890b9af..1e5a936b5b6ad0d6b75479549f2295cea98bdee2 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
  *
@@ -6,16 +7,14 @@
  * http://www.ti.com/lit/ds/symlink/adc128s052.pdf
  * http://www.ti.com/lit/ds/symlink/adc122s021.pdf
  * http://www.ti.com/lit/ds/symlink/adc124s021.pdf
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
+#include <linux/acpi.h>
 #include <linux/err.h>
 #include <linux/spi/spi.h>
 #include <linux/module.h>
 #include <linux/iio/iio.h>
+#include <linux/property.h>
 #include <linux/regulator/consumer.h>
 
 struct adc128_configuration {
@@ -135,10 +134,15 @@ static const struct iio_info adc128_info = {
 static int adc128_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
+       unsigned int config;
        struct adc128 *adc;
-       int config = spi_get_device_id(spi)->driver_data;
        int ret;
 
+       if (dev_fwnode(&spi->dev))
+               config = (unsigned long) device_get_match_data(&spi->dev);
+       else
+               config = spi_get_device_id(spi)->driver_data;
+
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
        if (!indio_dev)
                return -ENOMEM;
@@ -186,23 +190,40 @@ static int adc128_remove(struct spi_device *spi)
 static const struct of_device_id adc128_of_match[] = {
        { .compatible = "ti,adc128s052", },
        { .compatible = "ti,adc122s021", },
+       { .compatible = "ti,adc122s051", },
+       { .compatible = "ti,adc122s101", },
        { .compatible = "ti,adc124s021", },
+       { .compatible = "ti,adc124s051", },
+       { .compatible = "ti,adc124s101", },
        { /* sentinel */ },
 };
 MODULE_DEVICE_TABLE(of, adc128_of_match);
 
 static const struct spi_device_id adc128_id[] = {
-       { "adc128s052", 0},     /* index into adc128_config */
-       { "adc122s021", 1},
-       { "adc124s021", 2},
+       { "adc128s052", 0 },    /* index into adc128_config */
+       { "adc122s021", 1 },
+       { "adc122s051", 1 },
+       { "adc122s101", 1 },
+       { "adc124s021", 2 },
+       { "adc124s051", 2 },
+       { "adc124s101", 2 },
        { }
 };
 MODULE_DEVICE_TABLE(spi, adc128_id);
 
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id adc128_acpi_match[] = {
+       { "AANT1280", 2 }, /* ADC124S021 compatible ACPI ID */
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, adc128_acpi_match);
+#endif
+
 static struct spi_driver adc128_driver = {
        .driver = {
                .name = "adc128s052",
                .of_match_table = of_match_ptr(adc128_of_match),
+               .acpi_match_table = ACPI_PTR(adc128_acpi_match),
        },
        .probe = adc128_probe,
        .remove = adc128_remove,
index af3aa38f67cda7683b30c2cd82d0b90d28cc1f8d..9e13be2c0cb94a3afe9ffeed3fcff4bf56e14884 100644 (file)
@@ -462,43 +462,35 @@ static struct ssp_data *ssp_parse_dt(struct device *dev)
 
        data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
        if (data->mcu_ap_gpio < 0)
-               goto err_free_pd;
+               return NULL;
 
        data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
        if (data->ap_mcu_gpio < 0)
-               goto err_free_pd;
+               return NULL;
 
        data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
        if (data->mcu_reset_gpio < 0)
-               goto err_free_pd;
+               return NULL;
 
        ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
                                    "ap-mcu-gpios");
        if (ret)
-               goto err_free_pd;
+               return NULL;
 
        ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
                                    GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
        if (ret)
-               goto err_ap_mcu;
+               return NULL;
 
        match = of_match_node(ssp_of_match, node);
        if (!match)
-               goto err_mcu_reset_gpio;
+               return NULL;
 
        data->sensorhub_info = match->data;
 
        dev_set_drvdata(dev, data);
 
        return data;
-
-err_mcu_reset_gpio:
-       devm_gpio_free(dev, data->mcu_reset_gpio);
-err_ap_mcu:
-       devm_gpio_free(dev, data->ap_mcu_gpio);
-err_free_pd:
-       devm_kfree(dev, data);
-       return NULL;
 }
 #else
 static struct ssp_data *ssp_parse_dt(struct device *pdev)
index 26fbd1bd941352d31cb42e0f240f88f20c12fab5..e50c975250e9109ccdfd3fe08b074f504ead86c5 100644 (file)
@@ -133,7 +133,7 @@ static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
 
        for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
                if (sensor_settings->fs.fs_avl[i].num == 0)
-                       goto st_sensors_match_odr_error;
+                       return ret;
 
                if (sensor_settings->fs.fs_avl[i].num == fs) {
                        *index_fs_avl = i;
@@ -142,7 +142,6 @@ static int st_sensors_match_fs(struct st_sensor_settings *sensor_settings,
                }
        }
 
-st_sensors_match_odr_error:
        return ret;
 }
 
index fdcc5a8919587b90033b018c4b69f37f40ba5ca0..224596b0e1892dbfbb62bf82def233c1706c057c 100644 (file)
@@ -104,7 +104,7 @@ static irqreturn_t st_sensors_irq_thread(int irq, void *p)
                return IRQ_HANDLED;
 
        /*
-        * If we are using egde IRQs, new samples arrived while processing
+        * If we are using edge IRQs, new samples arrived while processing
         * the IRQ and those may be missed unless we pick them here, so poll
         * again. If the sensor delivery frequency is very high, this thread
         * turns into a polled loop handler.
@@ -148,7 +148,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
                if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
                        dev_err(&indio_dev->dev,
                                "falling/low specified for IRQ "
-                               "but hardware only support rising/high: "
+                               "but hardware supports only rising/high: "
                                "will request rising/high\n");
                        if (irq_trig == IRQF_TRIGGER_FALLING)
                                irq_trig = IRQF_TRIGGER_RISING;
index bb2057fd1b6f54e2fd69f679196e313d4cb2166d..851b61eaf3da1347a55996877501565058666d9e 100644 (file)
@@ -366,6 +366,15 @@ config TI_DAC5571
 
          If compiled as a module, it will be called ti-dac5571.
 
+config TI_DAC7311
+       tristate "Texas Instruments 8/10/12-bit 1-channel DAC driver"
+       depends on SPI
+       help
+         Driver for the Texas Instruments
+         DAC7311, DAC6311, DAC5311.
+
+         If compiled as a module, it will be called ti-dac7311.
+
 config VF610_DAC
        tristate "Vybrid vf610 DAC driver"
        depends on OF
index 2ac93cc4a38937d849c9580ae5fef85cc7a36d53..f0a37c93de8e56754fa9a297b2e4b3dcac045348 100644 (file)
@@ -40,4 +40,5 @@ obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
 obj-$(CONFIG_STM32_DAC) += stm32-dac.o
 obj-$(CONFIG_TI_DAC082S085) += ti-dac082s085.o
 obj-$(CONFIG_TI_DAC5571) += ti-dac5571.o
+obj-$(CONFIG_TI_DAC7311) += ti-dac7311.o
 obj-$(CONFIG_VF610_DAC) += vf610_dac.o
index a791d0a09d3b5c47b46c1589018d37b33ff655a1..4a6111b7e86ca1337adc2e0787436a24730ebbaf 100644 (file)
@@ -74,11 +74,11 @@ static int dpot_dac_read_raw(struct iio_dev *indio_dev,
                case IIO_VAL_INT:
                        /*
                         * Convert integer scale to fractional scale by
-                        * setting the denominator (val2) to one...
+                        * setting the denominator (val2) to one, and...
                         */
                        *val2 = 1;
                        ret = IIO_VAL_FRACTIONAL;
-                       /* ...and fall through. */
+                       /* fall through */
                case IIO_VAL_FRACTIONAL:
                        *val *= regulator_get_voltage(dac->vref) / 1000;
                        *val2 *= dac->max_ohms;
diff --git a/drivers/iio/dac/ti-dac7311.c b/drivers/iio/dac/ti-dac7311.c
new file mode 100644 (file)
index 0000000..6f5df1a
--- /dev/null
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0
+/* ti-dac7311.c - Texas Instruments 8/10/12-bit 1-channel DAC driver
+ *
+ * Copyright (C) 2018 CMC NV
+ *
+ * http://www.ti.com/lit/ds/symlink/dac7311.pdf
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+enum {
+       ID_DAC5311 = 0,
+       ID_DAC6311,
+       ID_DAC7311,
+};
+
+enum {
+       POWER_1KOHM_TO_GND = 0,
+       POWER_100KOHM_TO_GND,
+       POWER_TRI_STATE,
+};
+
+struct ti_dac_spec {
+       u8 resolution;
+};
+
+static const struct ti_dac_spec ti_dac_spec[] = {
+       [ID_DAC5311] = { .resolution = 8 },
+       [ID_DAC6311] = { .resolution = 10 },
+       [ID_DAC7311] = { .resolution = 12 },
+};
+
+/**
+ * struct ti_dac_chip - TI DAC chip
+ * @lock: protects write sequences
+ * @vref: regulator generating Vref
+ * @spi: SPI device to send data to the device
+ * @val: cached value
+ * @powerdown: whether the chip is powered down
+ * @powerdown_mode: selected by the user
+ * @resolution: resolution of the chip
+ * @buf: buffer for transfer data
+ */
+struct ti_dac_chip {
+       struct mutex lock;
+       struct regulator *vref;
+       struct spi_device *spi;
+       u16 val;
+       bool powerdown;
+       u8 powerdown_mode;
+       u8 resolution;
+       u8 buf[2] ____cacheline_aligned;
+};
+
+static u8 ti_dac_get_power(struct ti_dac_chip *ti_dac, bool powerdown)
+{
+       if (powerdown)
+               return ti_dac->powerdown_mode + 1;
+
+       return 0;
+}
+
+static int ti_dac_cmd(struct ti_dac_chip *ti_dac, u8 power, u16 val)
+{
+       u8 shift = 14 - ti_dac->resolution;
+
+       ti_dac->buf[0] = (val << shift) & 0xFF;
+       ti_dac->buf[1] = (power << 6) | (val >> (8 - shift));
+       return spi_write(ti_dac->spi, ti_dac->buf, 2);
+}
+
+static const char * const ti_dac_powerdown_modes[] = {
+       "1kohm_to_gnd",
+       "100kohm_to_gnd",
+       "three_state",
+};
+
+static int ti_dac_get_powerdown_mode(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan)
+{
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+
+       return ti_dac->powerdown_mode;
+}
+
+static int ti_dac_set_powerdown_mode(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    unsigned int mode)
+{
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+
+       ti_dac->powerdown_mode = mode;
+       return 0;
+}
+
+static const struct iio_enum ti_dac_powerdown_mode = {
+       .items = ti_dac_powerdown_modes,
+       .num_items = ARRAY_SIZE(ti_dac_powerdown_modes),
+       .get = ti_dac_get_powerdown_mode,
+       .set = ti_dac_set_powerdown_mode,
+};
+
+static ssize_t ti_dac_read_powerdown(struct iio_dev *indio_dev,
+                                    uintptr_t private,
+                                    const struct iio_chan_spec *chan,
+                                    char *buf)
+{
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+
+       return sprintf(buf, "%d\n", ti_dac->powerdown);
+}
+
+static ssize_t ti_dac_write_powerdown(struct iio_dev *indio_dev,
+                                     uintptr_t private,
+                                     const struct iio_chan_spec *chan,
+                                     const char *buf, size_t len)
+{
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+       bool powerdown;
+       u8 power;
+       int ret;
+
+       ret = strtobool(buf, &powerdown);
+       if (ret)
+               return ret;
+
+       power = ti_dac_get_power(ti_dac, powerdown);
+
+       mutex_lock(&ti_dac->lock);
+       ret = ti_dac_cmd(ti_dac, power, 0);
+       if (!ret)
+               ti_dac->powerdown = powerdown;
+       mutex_unlock(&ti_dac->lock);
+
+       return ret ? ret : len;
+}
+
+static const struct iio_chan_spec_ext_info ti_dac_ext_info[] = {
+       {
+               .name      = "powerdown",
+               .read      = ti_dac_read_powerdown,
+               .write     = ti_dac_write_powerdown,
+               .shared    = IIO_SHARED_BY_TYPE,
+       },
+       IIO_ENUM("powerdown_mode", IIO_SHARED_BY_TYPE, &ti_dac_powerdown_mode),
+       IIO_ENUM_AVAILABLE("powerdown_mode", &ti_dac_powerdown_mode),
+       { },
+};
+
+#define TI_DAC_CHANNEL(chan) {                                 \
+       .type = IIO_VOLTAGE,                                    \
+       .channel = (chan),                                      \
+       .output = true,                                         \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+       .ext_info = ti_dac_ext_info,                            \
+}
+
+static const struct iio_chan_spec ti_dac_channels[] = {
+       TI_DAC_CHANNEL(0),
+};
+
+static int ti_dac_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               *val = ti_dac->val;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               ret = regulator_get_voltage(ti_dac->vref);
+               if (ret < 0)
+                       return ret;
+
+               *val = ret / 1000;
+               *val2 = ti_dac->resolution;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       }
+
+       return -EINVAL;
+}
+
+static int ti_dac_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
+{
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+       u8 power = ti_dac_get_power(ti_dac, ti_dac->powerdown);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               if (ti_dac->val == val)
+                       return 0;
+
+               if (val >= (1 << ti_dac->resolution) || val < 0)
+                       return -EINVAL;
+
+               if (ti_dac->powerdown)
+                       return -EBUSY;
+
+               mutex_lock(&ti_dac->lock);
+               ret = ti_dac_cmd(ti_dac, power, val);
+               if (!ret)
+                       ti_dac->val = val;
+               mutex_unlock(&ti_dac->lock);
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int ti_dac_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                   struct iio_chan_spec const *chan, long mask)
+{
+       return IIO_VAL_INT;
+}
+
+static const struct iio_info ti_dac_info = {
+       .read_raw          = ti_dac_read_raw,
+       .write_raw         = ti_dac_write_raw,
+       .write_raw_get_fmt = ti_dac_write_raw_get_fmt,
+};
+
+static int ti_dac_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       const struct ti_dac_spec *spec;
+       struct ti_dac_chip *ti_dac;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*ti_dac));
+       if (!indio_dev) {
+               dev_err(dev, "can not allocate iio device\n");
+               return -ENOMEM;
+       }
+
+       spi->mode = SPI_MODE_1;
+       spi->bits_per_word = 16;
+       spi_setup(spi);
+
+       indio_dev->dev.parent = dev;
+       indio_dev->dev.of_node = spi->dev.of_node;
+       indio_dev->info = &ti_dac_info;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = ti_dac_channels;
+       spi_set_drvdata(spi, indio_dev);
+
+       ti_dac = iio_priv(indio_dev);
+       ti_dac->powerdown = false;
+       ti_dac->spi = spi;
+
+       spec = &ti_dac_spec[spi_get_device_id(spi)->driver_data];
+       indio_dev->num_channels = 1;
+       ti_dac->resolution = spec->resolution;
+
+       ti_dac->vref = devm_regulator_get(dev, "vref");
+       if (IS_ERR(ti_dac->vref)) {
+               dev_err(dev, "error to get regulator\n");
+               return PTR_ERR(ti_dac->vref);
+       }
+
+       ret = regulator_enable(ti_dac->vref);
+       if (ret < 0) {
+               dev_err(dev, "can not enable regulator\n");
+               return ret;
+       }
+
+       mutex_init(&ti_dac->lock);
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(dev, "fail to register iio device: %d\n", ret);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       mutex_destroy(&ti_dac->lock);
+       regulator_disable(ti_dac->vref);
+       return ret;
+}
+
+static int ti_dac_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct ti_dac_chip *ti_dac = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       mutex_destroy(&ti_dac->lock);
+       regulator_disable(ti_dac->vref);
+       return 0;
+}
+
+static const struct of_device_id ti_dac_of_id[] = {
+       { .compatible = "ti,dac5311" },
+       { .compatible = "ti,dac6311" },
+       { .compatible = "ti,dac7311" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ti_dac_of_id);
+
+static const struct spi_device_id ti_dac_spi_id[] = {
+       { "dac5311", ID_DAC5311  },
+       { "dac6311", ID_DAC6311 },
+       { "dac7311", ID_DAC7311 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, ti_dac_spi_id);
+
+static struct spi_driver ti_dac_driver = {
+       .driver = {
+               .name           = "ti-dac7311",
+               .of_match_table = ti_dac_of_id,
+       },
+       .probe    = ti_dac_probe,
+       .remove   = ti_dac_remove,
+       .id_table = ti_dac_spi_id,
+};
+module_spi_driver(ti_dac_driver);
+
+MODULE_AUTHOR("Charles-Antoine Couret <charles-antoine.couret@essensium.com>");
+MODULE_DESCRIPTION("Texas Instruments 8/10/12-bit 1-channel DAC driver");
+MODULE_LICENSE("GPL v2");
index 35919febea2abe5866480db697e152716175de63..e5f733ce6e111346b613d26c5d248f0e90451d7a 100644 (file)
@@ -1,4 +1,5 @@
-st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o
+st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o \
+               st_lsm6dsx_shub.o
 
 obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
 obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
index ef73519a0fb6fa4a309bd2d10da1822cd560baeb..d1d8d07a07143d45e5c713206cd04008b23f4819 100644 (file)
@@ -43,6 +43,24 @@ enum st_lsm6dsx_hw_id {
                                         * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
 #define ST_LSM6DSX_SHIFT_VAL(val, mask)        (((val) << __ffs(mask)) & (mask))
 
+#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx)             \
+{                                                                      \
+       .type = chan_type,                                              \
+       .address = addr,                                                \
+       .modified = 1,                                                  \
+       .channel2 = mod,                                                \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
+                             BIT(IIO_CHAN_INFO_SCALE),                 \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),        \
+       .scan_index = scan_idx,                                         \
+       .scan_type = {                                                  \
+               .sign = 's',                                            \
+               .realbits = 16,                                         \
+               .storagebits = 16,                                      \
+               .endianness = IIO_LE,                                   \
+       },                                                              \
+}
+
 struct st_lsm6dsx_reg {
        u8 addr;
        u8 mask;
@@ -50,6 +68,28 @@ struct st_lsm6dsx_reg {
 
 struct st_lsm6dsx_hw;
 
+struct st_lsm6dsx_odr {
+       u16 hz;
+       u8 val;
+};
+
+#define ST_LSM6DSX_ODR_LIST_SIZE       6
+struct st_lsm6dsx_odr_table_entry {
+       struct st_lsm6dsx_reg reg;
+       struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
+};
+
+struct st_lsm6dsx_fs {
+       u32 gain;
+       u8 val;
+};
+
+#define ST_LSM6DSX_FS_LIST_SIZE                4
+struct st_lsm6dsx_fs_table_entry {
+       struct st_lsm6dsx_reg reg;
+       struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];
+};
+
 /**
  * struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
  * @read_fifo: Read FIFO callback.
@@ -84,6 +124,70 @@ struct st_lsm6dsx_hw_ts_settings {
        struct st_lsm6dsx_reg decimator;
 };
 
+/**
+ * struct st_lsm6dsx_shub_settings - ST IMU hw i2c controller settings
+ * @page_mux: register page mux info (addr + mask).
+ * @master_en: master config register info (addr + mask).
+ * @pullup_en: i2c controller pull-up register info (addr + mask).
+ * @aux_sens: aux sensor register info (addr + mask).
+ * @wr_once: write_once register info (addr + mask).
+ * @shub_out: sensor hub first output register info.
+ * @slv0_addr: slave0 address in secondary page.
+ * @dw_slv0_addr: slave0 write register address in secondary page.
+ * @batch_en: Enable/disable FIFO batching.
+ */
+struct st_lsm6dsx_shub_settings {
+       struct st_lsm6dsx_reg page_mux;
+       struct st_lsm6dsx_reg master_en;
+       struct st_lsm6dsx_reg pullup_en;
+       struct st_lsm6dsx_reg aux_sens;
+       struct st_lsm6dsx_reg wr_once;
+       u8 shub_out;
+       u8 slv0_addr;
+       u8 dw_slv0_addr;
+       u8 batch_en;
+};
+
+enum st_lsm6dsx_ext_sensor_id {
+       ST_LSM6DSX_ID_MAGN,
+};
+
+/**
+ * struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings
+ * @i2c_addr: I2c slave address list.
+ * @wai: Wai address info.
+ * @id: external sensor id.
+ * @odr: Output data rate of the sensor [Hz].
+ * @gain: Configured sensor sensitivity.
+ * @temp_comp: Temperature compensation register info (addr + mask).
+ * @pwr_table: Power on register info (addr + mask).
+ * @off_canc: Offset cancellation register info (addr + mask).
+ * @bdu: Block data update register info (addr + mask).
+ * @out: Output register info.
+ */
+struct st_lsm6dsx_ext_dev_settings {
+       u8 i2c_addr[2];
+       struct {
+               u8 addr;
+               u8 val;
+       } wai;
+       enum st_lsm6dsx_ext_sensor_id id;
+       struct st_lsm6dsx_odr_table_entry odr_table;
+       struct st_lsm6dsx_fs_table_entry fs_table;
+       struct st_lsm6dsx_reg temp_comp;
+       struct {
+               struct st_lsm6dsx_reg reg;
+               u8 off_val;
+               u8 on_val;
+       } pwr_table;
+       struct st_lsm6dsx_reg off_canc;
+       struct st_lsm6dsx_reg bdu;
+       struct {
+               u8 addr;
+               u8 len;
+       } out;
+};
+
 /**
  * struct st_lsm6dsx_settings - ST IMU sensor settings
  * @wai: Sensor WhoAmI default value.
@@ -93,6 +197,7 @@ struct st_lsm6dsx_hw_ts_settings {
  * @batch: List of FIFO batching register info (addr + mask).
  * @fifo_ops: Sensor hw FIFO parameters.
  * @ts_settings: Hw timer related settings.
+ * @shub_settings: i2c controller related settings.
  */
 struct st_lsm6dsx_settings {
        u8 wai;
@@ -102,11 +207,15 @@ struct st_lsm6dsx_settings {
        struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_fifo_ops fifo_ops;
        struct st_lsm6dsx_hw_ts_settings ts_settings;
+       struct st_lsm6dsx_shub_settings shub_settings;
 };
 
 enum st_lsm6dsx_sensor_id {
-       ST_LSM6DSX_ID_ACC,
        ST_LSM6DSX_ID_GYRO,
+       ST_LSM6DSX_ID_ACC,
+       ST_LSM6DSX_ID_EXT0,
+       ST_LSM6DSX_ID_EXT1,
+       ST_LSM6DSX_ID_EXT2,
        ST_LSM6DSX_ID_MAX,
 };
 
@@ -126,6 +235,7 @@ enum st_lsm6dsx_fifo_mode {
  * @sip: Number of samples in a given pattern.
  * @decimator: FIFO decimation factor.
  * @ts_ref: Sensor timestamp reference for hw one.
+ * @ext_info: Sensor settings if it is connected to i2c controller
  */
 struct st_lsm6dsx_sensor {
        char name[32];
@@ -139,6 +249,11 @@ struct st_lsm6dsx_sensor {
        u8 sip;
        u8 decimator;
        s64 ts_ref;
+
+       struct {
+               const struct st_lsm6dsx_ext_dev_settings *settings;
+               u8 addr;
+       } ext_info;
 };
 
 /**
@@ -148,6 +263,7 @@ struct st_lsm6dsx_sensor {
  * @irq: Device interrupt line (I2C or SPI).
  * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
  * @conf_lock: Mutex to prevent concurrent FIFO configuration update.
+ * @page_lock: Mutex to prevent concurrent memory page configuration.
  * @fifo_mode: FIFO operating mode supported by the device.
  * @enable_mask: Enabled sensor bitmask.
  * @ts_sip: Total number of timestamp samples in a given pattern.
@@ -163,6 +279,7 @@ struct st_lsm6dsx_hw {
 
        struct mutex fifo_lock;
        struct mutex conf_lock;
+       struct mutex page_lock;
 
        enum st_lsm6dsx_fifo_mode fifo_mode;
        u8 enable_mask;
@@ -176,13 +293,15 @@ struct st_lsm6dsx_hw {
        const struct st_lsm6dsx_settings *settings;
 };
 
+static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
 extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
 
 int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
                     struct regmap *regmap);
-int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
-int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
+int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
+                                bool enable);
 int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val);
 int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
                                u16 watermark);
 int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
@@ -191,5 +310,47 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
 int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw);
 int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);
 int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val);
+int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);
+int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);
+int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);
+
+static inline int
+st_lsm6dsx_update_bits_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,
+                             unsigned int mask, unsigned int val)
+{
+       int err;
+
+       mutex_lock(&hw->page_lock);
+       err = regmap_update_bits(hw->regmap, addr, mask, val);
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
+
+static inline int
+st_lsm6dsx_read_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,
+                      void *val, unsigned int len)
+{
+       int err;
+
+       mutex_lock(&hw->page_lock);
+       err = regmap_bulk_read(hw->regmap, addr, val, len);
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
+
+static inline int
+st_lsm6dsx_write_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,
+                       unsigned int val)
+{
+       int err;
+
+       mutex_lock(&hw->page_lock);
+       err = regmap_write(hw->regmap, addr, val);
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
 
 #endif /* ST_LSM6DSX_H */
index b5263fc522ca662e431f34a8b11786bd5d598ef2..2c0d3763405ad69fdaf23ce14aca241d327d6b7a 100644 (file)
@@ -68,6 +68,9 @@ enum st_lsm6dsx_fifo_tag {
        ST_LSM6DSX_GYRO_TAG = 0x01,
        ST_LSM6DSX_ACC_TAG = 0x02,
        ST_LSM6DSX_TS_TAG = 0x04,
+       ST_LSM6DSX_EXT0_TAG = 0x0f,
+       ST_LSM6DSX_EXT1_TAG = 0x10,
+       ST_LSM6DSX_EXT2_TAG = 0x11,
 };
 
 static const
@@ -102,6 +105,9 @@ static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
 
        *max_odr = 0, *min_odr = ~0;
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                sensor = iio_priv(hw->iio_devs[i]);
 
                if (!(hw->enable_mask & BIT(sensor->id)))
@@ -125,6 +131,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
                const struct st_lsm6dsx_reg *dec_reg;
 
+               if (!hw->iio_devs[i])
+                       continue;
+
                sensor = iio_priv(hw->iio_devs[i]);
                /* update fifo decimators and sample in pattern */
                if (hw->enable_mask & BIT(sensor->id)) {
@@ -142,8 +151,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
                if (dec_reg->addr) {
                        int val = ST_LSM6DSX_SHIFT_VAL(data, dec_reg->mask);
 
-                       err = regmap_update_bits(hw->regmap, dec_reg->addr,
-                                                dec_reg->mask, val);
+                       err = st_lsm6dsx_update_bits_locked(hw, dec_reg->addr,
+                                                           dec_reg->mask,
+                                                           val);
                        if (err < 0)
                                return err;
                }
@@ -162,8 +172,8 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
                int val, ts_dec = !!hw->ts_sip;
 
                val = ST_LSM6DSX_SHIFT_VAL(ts_dec, ts_dec_reg->mask);
-               err = regmap_update_bits(hw->regmap, ts_dec_reg->addr,
-                                        ts_dec_reg->mask, val);
+               err = st_lsm6dsx_update_bits_locked(hw, ts_dec_reg->addr,
+                                                   ts_dec_reg->mask, val);
        }
        return err;
 }
@@ -171,12 +181,12 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
 int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
                             enum st_lsm6dsx_fifo_mode fifo_mode)
 {
+       unsigned int data;
        int err;
 
-       err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
-                                ST_LSM6DSX_FIFO_MODE_MASK,
-                                FIELD_PREP(ST_LSM6DSX_FIFO_MODE_MASK,
-                                           fifo_mode));
+       data = FIELD_PREP(ST_LSM6DSX_FIFO_MODE_MASK, fifo_mode);
+       err = st_lsm6dsx_update_bits_locked(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
+                                           ST_LSM6DSX_FIFO_MODE_MASK, data);
        if (err < 0)
                return err;
 
@@ -207,15 +217,15 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
                        data = 0;
                }
                val = ST_LSM6DSX_SHIFT_VAL(data, batch_reg->mask);
-               return regmap_update_bits(hw->regmap, batch_reg->addr,
-                                         batch_reg->mask, val);
+               return st_lsm6dsx_update_bits_locked(hw, batch_reg->addr,
+                                                    batch_reg->mask, val);
        } else {
                data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
-               return regmap_update_bits(hw->regmap,
-                                         ST_LSM6DSX_REG_FIFO_MODE_ADDR,
-                                         ST_LSM6DSX_FIFO_ODR_MASK,
-                                         FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
-                                                    data));
+               return st_lsm6dsx_update_bits_locked(hw,
+                                       ST_LSM6DSX_REG_FIFO_MODE_ADDR,
+                                       ST_LSM6DSX_FIFO_ODR_MASK,
+                                       FIELD_PREP(ST_LSM6DSX_FIFO_ODR_MASK,
+                                                  data));
        }
 }
 
@@ -231,6 +241,9 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
                return 0;
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                cur_sensor = iio_priv(hw->iio_devs[i]);
 
                if (!(hw->enable_mask & BIT(cur_sensor->id)))
@@ -246,19 +259,23 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
        fifo_watermark = (fifo_watermark / hw->sip) * hw->sip;
        fifo_watermark = fifo_watermark * hw->settings->fifo_ops.th_wl;
 
+       mutex_lock(&hw->page_lock);
        err = regmap_read(hw->regmap, hw->settings->fifo_ops.fifo_th.addr + 1,
                          &data);
        if (err < 0)
-               return err;
+               goto out;
 
        fifo_th_mask = hw->settings->fifo_ops.fifo_th.mask;
        fifo_watermark = ((data << 8) & ~fifo_th_mask) |
                         (fifo_watermark & fifo_th_mask);
 
        wdata = cpu_to_le16(fifo_watermark);
-       return regmap_bulk_write(hw->regmap,
-                                hw->settings->fifo_ops.fifo_th.addr,
-                                &wdata, sizeof(wdata));
+       err = regmap_bulk_write(hw->regmap,
+                               hw->settings->fifo_ops.fifo_th.addr,
+                               &wdata, sizeof(wdata));
+out:
+       mutex_unlock(&hw->page_lock);
+       return err;
 }
 
 static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
@@ -267,12 +284,15 @@ static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
        int i, err;
 
        /* reset hw ts counter */
-       err = regmap_write(hw->regmap, ST_LSM6DSX_REG_TS_RESET_ADDR,
-                          ST_LSM6DSX_TS_RESET_VAL);
+       err = st_lsm6dsx_write_locked(hw, ST_LSM6DSX_REG_TS_RESET_ADDR,
+                                     ST_LSM6DSX_TS_RESET_VAL);
        if (err < 0)
                return err;
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                sensor = iio_priv(hw->iio_devs[i]);
                /*
                 * store enable buffer timestamp as reference for
@@ -297,8 +317,8 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
        while (read_len < data_len) {
                word_len = min_t(unsigned int, data_len - read_len,
                                 max_word_len);
-               err = regmap_bulk_read(hw->regmap, addr, data + read_len,
-                                      word_len);
+               err = st_lsm6dsx_read_locked(hw, addr, data + read_len,
+                                            word_len);
                if (err < 0)
                        return err;
                read_len += word_len;
@@ -328,9 +348,9 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
        __le16 fifo_status;
        s64 ts = 0;
 
-       err = regmap_bulk_read(hw->regmap,
-                              hw->settings->fifo_ops.fifo_diff.addr,
-                              &fifo_status, sizeof(fifo_status));
+       err = st_lsm6dsx_read_locked(hw,
+                                    hw->settings->fifo_ops.fifo_diff.addr,
+                                    &fifo_status, sizeof(fifo_status));
        if (err < 0) {
                dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
                        err);
@@ -436,6 +456,55 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
        return read_len;
 }
 
+static int
+st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag,
+                           u8 *data, s64 ts)
+{
+       struct st_lsm6dsx_sensor *sensor;
+       struct iio_dev *iio_dev;
+
+       /*
+        * EXT_TAG are managed in FIFO fashion so ST_LSM6DSX_EXT0_TAG
+        * corresponds to the first enabled channel, ST_LSM6DSX_EXT1_TAG
+        * to the second one and ST_LSM6DSX_EXT2_TAG to the last enabled
+        * channel
+        */
+       switch (tag) {
+       case ST_LSM6DSX_GYRO_TAG:
+               iio_dev = hw->iio_devs[ST_LSM6DSX_ID_GYRO];
+               break;
+       case ST_LSM6DSX_ACC_TAG:
+               iio_dev = hw->iio_devs[ST_LSM6DSX_ID_ACC];
+               break;
+       case ST_LSM6DSX_EXT0_TAG:
+               if (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT0))
+                       iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT0];
+               else if (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT1))
+                       iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT1];
+               else
+                       iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
+               break;
+       case ST_LSM6DSX_EXT1_TAG:
+               if ((hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT0)) &&
+                   (hw->enable_mask & BIT(ST_LSM6DSX_ID_EXT1)))
+                       iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT1];
+               else
+                       iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
+               break;
+       case ST_LSM6DSX_EXT2_TAG:
+               iio_dev = hw->iio_devs[ST_LSM6DSX_ID_EXT2];
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       sensor = iio_priv(iio_dev);
+       iio_push_to_buffers_with_timestamp(iio_dev, data,
+                                          ts + sensor->ts_ref);
+
+       return 0;
+}
+
 /**
  * st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine
  * @hw: Pointer to instance of struct st_lsm6dsx_hw.
@@ -455,9 +524,9 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
        __le16 fifo_status;
        s64 ts = 0;
 
-       err = regmap_bulk_read(hw->regmap,
-                              hw->settings->fifo_ops.fifo_diff.addr,
-                              &fifo_status, sizeof(fifo_status));
+       err = st_lsm6dsx_read_locked(hw,
+                                    hw->settings->fifo_ops.fifo_diff.addr,
+                                    &fifo_status, sizeof(fifo_status));
        if (err < 0) {
                dev_err(hw->dev, "failed to read fifo status (err=%d)\n",
                        err);
@@ -491,8 +560,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
                               ST_LSM6DSX_SAMPLE_SIZE);
 
                        tag = hw->buff[i] >> 3;
-                       switch (tag) {
-                       case ST_LSM6DSX_TS_TAG:
+                       if (tag == ST_LSM6DSX_TS_TAG) {
                                /*
                                 * hw timestamp is 4B long and it is stored
                                 * in FIFO according to this schema:
@@ -509,19 +577,9 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
                                if (!reset_ts && ts >= 0xffff0000)
                                        reset_ts = true;
                                ts *= ST_LSM6DSX_TS_SENSITIVITY;
-                               break;
-                       case ST_LSM6DSX_GYRO_TAG:
-                               iio_push_to_buffers_with_timestamp(
-                                       hw->iio_devs[ST_LSM6DSX_ID_GYRO],
-                                       iio_buff, gyro_sensor->ts_ref + ts);
-                               break;
-                       case ST_LSM6DSX_ACC_TAG:
-                               iio_push_to_buffers_with_timestamp(
-                                       hw->iio_devs[ST_LSM6DSX_ID_ACC],
-                                       iio_buff, acc_sensor->ts_ref + ts);
-                               break;
-                       default:
-                               break;
+                       } else {
+                               st_lsm6dsx_push_tagged_data(hw, tag, iio_buff,
+                                                           ts);
                        }
                }
        }
@@ -562,19 +620,21 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
                        goto out;
        }
 
-       if (enable) {
-               err = st_lsm6dsx_sensor_enable(sensor);
+       if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
+           sensor->id == ST_LSM6DSX_ID_EXT1 ||
+           sensor->id == ST_LSM6DSX_ID_EXT2) {
+               err = st_lsm6dsx_shub_set_enable(sensor, enable);
                if (err < 0)
                        goto out;
        } else {
-               err = st_lsm6dsx_sensor_disable(sensor);
+               err = st_lsm6dsx_sensor_set_enable(sensor, enable);
                if (err < 0)
                        goto out;
-       }
 
-       err = st_lsm6dsx_set_fifo_odr(sensor, enable);
-       if (err < 0)
-               goto out;
+               err = st_lsm6dsx_set_fifo_odr(sensor, enable);
+               if (err < 0)
+                       goto out;
+       }
 
        err = st_lsm6dsx_update_decimators(hw);
        if (err < 0)
@@ -690,6 +750,9 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
        }
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                buffer = devm_iio_kfifo_allocate(hw->dev);
                if (!buffer)
                        return -ENOMEM;
index 2ad3c610e4b63777cfc7e83f278d88ca231e0e2f..12e29dda9b98f9c3e41ef8b068f0cedcc06c4911 100644 (file)
@@ -56,6 +56,7 @@
 #define ST_LSM6DSX_REG_WHOAMI_ADDR             0x0f
 #define ST_LSM6DSX_REG_RESET_ADDR              0x12
 #define ST_LSM6DSX_REG_RESET_MASK              BIT(0)
+#define ST_LSM6DSX_REG_BOOT_MASK               BIT(7)
 #define ST_LSM6DSX_REG_BDU_ADDR                        0x12
 #define ST_LSM6DSX_REG_BDU_MASK                        BIT(6)
 #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR       0x13
 #define ST_LSM6DSX_GYRO_FS_1000_GAIN           IIO_DEGREE_TO_RAD(35000)
 #define ST_LSM6DSX_GYRO_FS_2000_GAIN           IIO_DEGREE_TO_RAD(70000)
 
-struct st_lsm6dsx_odr {
-       u16 hz;
-       u8 val;
-};
-
-#define ST_LSM6DSX_ODR_LIST_SIZE       6
-struct st_lsm6dsx_odr_table_entry {
-       struct st_lsm6dsx_reg reg;
-       struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
-};
-
 static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
        [ST_LSM6DSX_ID_ACC] = {
                .reg = {
@@ -125,17 +115,6 @@ static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
        }
 };
 
-struct st_lsm6dsx_fs {
-       u32 gain;
-       u8 val;
-};
-
-#define ST_LSM6DSX_FS_LIST_SIZE                4
-struct st_lsm6dsx_fs_table_entry {
-       struct st_lsm6dsx_reg reg;
-       struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];
-};
-
 static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
        [ST_LSM6DSX_ID_ACC] = {
                .reg = {
@@ -341,27 +320,35 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                                .mask = GENMASK(7, 6),
                        },
                },
+               .shub_settings = {
+                       .page_mux = {
+                               .addr = 0x01,
+                               .mask = BIT(6),
+                       },
+                       .master_en = {
+                               .addr = 0x14,
+                               .mask = BIT(2),
+                       },
+                       .pullup_en = {
+                               .addr = 0x14,
+                               .mask = BIT(3),
+                       },
+                       .aux_sens = {
+                               .addr = 0x14,
+                               .mask = GENMASK(1, 0),
+                       },
+                       .wr_once = {
+                               .addr = 0x14,
+                               .mask = BIT(6),
+                       },
+                       .shub_out = 0x02,
+                       .slv0_addr = 0x15,
+                       .dw_slv0_addr = 0x21,
+                       .batch_en = BIT(3),
+               }
        },
 };
 
-#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx)             \
-{                                                                      \
-       .type = chan_type,                                              \
-       .address = addr,                                                \
-       .modified = 1,                                                  \
-       .channel2 = mod,                                                \
-       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
-                             BIT(IIO_CHAN_INFO_SCALE),                 \
-       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),        \
-       .scan_index = scan_idx,                                         \
-       .scan_type = {                                                  \
-               .sign = 's',                                            \
-               .realbits = 16,                                         \
-               .storagebits = 16,                                      \
-               .endianness = IIO_LE,                                   \
-       },                                                              \
-}
-
 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),
@@ -382,6 +369,21 @@ static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
        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;
+       unsigned int data;
+       int err;
+
+       hub_settings = &hw->settings->shub_settings;
+       data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->page_mux.mask);
+       err = regmap_update_bits(hw->regmap, hub_settings->page_mux.addr,
+                                hub_settings->page_mux.mask, data);
+       usleep_range(100, 150);
+
+       return err;
+}
+
 static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
 {
        int err, i, j, data;
@@ -421,6 +423,7 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
 {
        struct st_lsm6dsx_hw *hw = sensor->hw;
        const struct st_lsm6dsx_reg *reg;
+       unsigned int data;
        int i, err;
        u8 val;
 
@@ -433,8 +436,8 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
 
        val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val;
        reg = &st_lsm6dsx_fs_table[sensor->id].reg;
-       err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
-                                ST_LSM6DSX_SHIFT_VAL(val, reg->mask));
+       data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
+       err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
        if (err < 0)
                return err;
 
@@ -448,7 +451,11 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
        int i;
 
        for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
-               if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr)
+               /*
+                * ext devices can run at different odr respect to
+                * accel sensor
+                */
+               if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
                        break;
 
        if (i == ST_LSM6DSX_ODR_LIST_SIZE)
@@ -459,48 +466,86 @@ int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
        return 0;
 }
 
-static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
+static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
+                                          enum st_lsm6dsx_sensor_id id)
 {
-       struct st_lsm6dsx_hw *hw = sensor->hw;
-       const struct st_lsm6dsx_reg *reg;
-       int err;
-       u8 val;
-
-       err = st_lsm6dsx_check_odr(sensor, odr, &val);
-       if (err < 0)
-               return err;
-
-       reg = &st_lsm6dsx_odr_table[sensor->id].reg;
-       return regmap_update_bits(hw->regmap, reg->addr, reg->mask,
-                                 ST_LSM6DSX_SHIFT_VAL(val, reg->mask));
+       struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
+
+       if (odr > 0) {
+               if (hw->enable_mask & BIT(id))
+                       return max_t(u16, ref->odr, odr);
+               else
+                       return odr;
+       } else {
+               return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
+       }
 }
 
-int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor)
+static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
 {
+       struct st_lsm6dsx_sensor *ref_sensor = sensor;
+       struct st_lsm6dsx_hw *hw = sensor->hw;
+       const struct st_lsm6dsx_reg *reg;
+       unsigned int data;
+       u8 val = 0;
        int err;
 
-       err = st_lsm6dsx_set_odr(sensor, sensor->odr);
-       if (err < 0)
-               return err;
+       switch (sensor->id) {
+       case ST_LSM6DSX_ID_EXT0:
+       case ST_LSM6DSX_ID_EXT1:
+       case ST_LSM6DSX_ID_EXT2:
+       case ST_LSM6DSX_ID_ACC: {
+               u16 odr;
+               int i;
+
+               /*
+                * i2c embedded controller relies on the accelerometer sensor as
+                * bus read/write trigger so we need to enable accel device
+                * at odr = max(accel_odr, ext_odr) in order to properly
+                * communicate with i2c slave devices
+                */
+               ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+               for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) {
+                       if (!hw->iio_devs[i] || i == sensor->id)
+                               continue;
+
+                       odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i);
+                       if (odr != req_odr)
+                               /* device already configured */
+                               return 0;
+               }
+               break;
+       }
+       default:
+               break;
+       }
 
-       sensor->hw->enable_mask |= BIT(sensor->id);
+       if (req_odr > 0) {
+               err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val);
+               if (err < 0)
+                       return err;
+       }
 
-       return 0;
+       reg = &st_lsm6dsx_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);
 }
 
-int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor)
+int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
+                                bool enable)
 {
        struct st_lsm6dsx_hw *hw = sensor->hw;
-       const struct st_lsm6dsx_reg *reg;
+       u16 odr = enable ? sensor->odr : 0;
        int err;
 
-       reg = &st_lsm6dsx_odr_table[sensor->id].reg;
-       err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
-                                ST_LSM6DSX_SHIFT_VAL(0, reg->mask));
+       err = st_lsm6dsx_set_odr(sensor, odr);
        if (err < 0)
                return err;
 
-       sensor->hw->enable_mask &= ~BIT(sensor->id);
+       if (enable)
+               hw->enable_mask |= BIT(sensor->id);
+       else
+               hw->enable_mask &= ~BIT(sensor->id);
 
        return 0;
 }
@@ -512,18 +557,18 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
        int err, delay;
        __le16 data;
 
-       err = st_lsm6dsx_sensor_enable(sensor);
+       err = st_lsm6dsx_sensor_set_enable(sensor, true);
        if (err < 0)
                return err;
 
        delay = 1000000 / sensor->odr;
        usleep_range(delay, 2 * delay);
 
-       err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data));
+       err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
        if (err < 0)
                return err;
 
-       st_lsm6dsx_sensor_disable(sensor);
+       st_lsm6dsx_sensor_set_enable(sensor, false);
 
        *val = (s16)le16_to_cpu(data);
 
@@ -596,7 +641,7 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
        return err;
 }
 
-static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
+int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
 {
        struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
        struct st_lsm6dsx_hw *hw = sensor->hw;
@@ -692,8 +737,6 @@ static const struct iio_info st_lsm6dsx_gyro_info = {
        .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
 };
 
-static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
-
 static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
 {
        struct device_node *np = hw->dev->of_node;
@@ -732,6 +775,51 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
        return err;
 }
 
+static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       struct device_node *np = hw->dev->of_node;
+       struct st_sensors_platform_data *pdata;
+       unsigned int data;
+       int err = 0;
+
+       hub_settings = &hw->settings->shub_settings;
+
+       pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
+       if ((np && of_property_read_bool(np, "st,pullups")) ||
+           (pdata && pdata->pullups)) {
+               err = st_lsm6dsx_set_page(hw, true);
+               if (err < 0)
+                       return err;
+
+               data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask);
+               err = regmap_update_bits(hw->regmap,
+                                        hub_settings->pullup_en.addr,
+                                        hub_settings->pullup_en.mask, data);
+
+               st_lsm6dsx_set_page(hw, false);
+
+               if (err < 0)
+                       return err;
+       }
+
+       if (hub_settings->aux_sens.addr) {
+               /* configure aux sensors */
+               err = st_lsm6dsx_set_page(hw, true);
+               if (err < 0)
+                       return err;
+
+               data = ST_LSM6DSX_SHIFT_VAL(3, hub_settings->aux_sens.mask);
+               err = regmap_update_bits(hw->regmap,
+                                        hub_settings->aux_sens.addr,
+                                        hub_settings->aux_sens.mask, data);
+
+               st_lsm6dsx_set_page(hw, false);
+       }
+
+       return err;
+}
+
 static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
 {
        const struct st_lsm6dsx_hw_ts_settings *ts_settings;
@@ -775,12 +863,23 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
        u8 drdy_int_reg;
        int err;
 
-       err = regmap_write(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
-                          ST_LSM6DSX_REG_RESET_MASK);
+       /* device sw reset */
+       err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
+                                ST_LSM6DSX_REG_RESET_MASK,
+                                FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
+       if (err < 0)
+               return err;
+
+       msleep(50);
+
+       /* reload trimming parameter */
+       err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
+                                ST_LSM6DSX_REG_BOOT_MASK,
+                                FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
        if (err < 0)
                return err;
 
-       msleep(200);
+       msleep(50);
 
        /* enable Block Data Update */
        err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR,
@@ -801,6 +900,10 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
        if (err < 0)
                return err;
 
+       err = st_lsm6dsx_init_shub(hw);
+       if (err < 0)
+               return err;
+
        return st_lsm6dsx_init_hw_timer(hw);
 }
 
@@ -854,6 +957,7 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
 int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
                     struct regmap *regmap)
 {
+       const struct st_lsm6dsx_shub_settings *hub_settings;
        struct st_lsm6dsx_hw *hw;
        int i, err;
 
@@ -865,6 +969,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
 
        mutex_init(&hw->fifo_lock);
        mutex_init(&hw->conf_lock);
+       mutex_init(&hw->page_lock);
 
        hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
        if (!hw->buff)
@@ -878,7 +983,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
        if (err < 0)
                return err;
 
-       for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+       for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
                hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
                if (!hw->iio_devs[i])
                        return -ENOMEM;
@@ -888,6 +993,13 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
        if (err < 0)
                return err;
 
+       hub_settings = &hw->settings->shub_settings;
+       if (hub_settings->master_en.addr) {
+               err = st_lsm6dsx_shub_probe(hw, name);
+               if (err < 0)
+                       return err;
+       }
+
        if (hw->irq > 0) {
                err = st_lsm6dsx_fifo_setup(hw);
                if (err < 0)
@@ -895,6 +1007,9 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
        }
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
                if (err)
                        return err;
@@ -909,16 +1024,21 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
        struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
        struct st_lsm6dsx_sensor *sensor;
        const struct st_lsm6dsx_reg *reg;
+       unsigned int data;
        int i, err = 0;
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                sensor = iio_priv(hw->iio_devs[i]);
                if (!(hw->enable_mask & BIT(sensor->id)))
                        continue;
 
                reg = &st_lsm6dsx_odr_table[sensor->id].reg;
-               err = regmap_update_bits(hw->regmap, reg->addr, reg->mask,
-                                        ST_LSM6DSX_SHIFT_VAL(0, reg->mask));
+               data = ST_LSM6DSX_SHIFT_VAL(0, reg->mask);
+               err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask,
+                                                   data);
                if (err < 0)
                        return err;
        }
@@ -936,6 +1056,9 @@ static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
        int i, err = 0;
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
                sensor = iio_priv(hw->iio_devs[i]);
                if (!(hw->enable_mask & BIT(sensor->id)))
                        continue;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c
new file mode 100644 (file)
index 0000000..ee59b0c
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ * STMicroelectronics st_lsm6dsx i2c controller driver
+ *
+ * i2c controller embedded in lsm6dx series can connect up to four
+ * slave devices using accelerometer sensor as trigger for i2c
+ * read/write operations. Current implementation relies on SLV0 channel
+ * for slave configuration and SLV{1,2,3} to read data and push them into
+ * the hw FIFO
+ *
+ * Copyright (C) 2018 Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/bitfield.h>
+
+#include "st_lsm6dsx.h"
+
+#define ST_LSM6DSX_MAX_SLV_NUM                 3
+#define ST_LSM6DSX_SLV_ADDR(n, base)           ((base) + (n) * 3)
+#define ST_LSM6DSX_SLV_SUB_ADDR(n, base)       ((base) + 1 + (n) * 3)
+#define ST_LSM6DSX_SLV_CONFIG(n, base)         ((base) + 2 + (n) * 3)
+
+#define ST_LS6DSX_READ_OP_MASK                 GENMASK(2, 0)
+
+static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = {
+       /* LIS2MDL */
+       {
+               .i2c_addr = { 0x1e },
+               .wai = {
+                       .addr = 0x4f,
+                       .val = 0x40,
+               },
+               .id = ST_LSM6DSX_ID_MAGN,
+               .odr_table = {
+                       .reg = {
+                               .addr = 0x60,
+                               .mask = GENMASK(3, 2),
+                       },
+                       .odr_avl[0] = {  10, 0x0 },
+                       .odr_avl[1] = {  20, 0x1 },
+                       .odr_avl[2] = {  50, 0x2 },
+                       .odr_avl[3] = { 100, 0x3 },
+               },
+               .fs_table = {
+                       .fs_avl[0] = {
+                               .gain = 1500,
+                               .val = 0x0,
+                       }, /* 1500 uG/LSB */
+               },
+               .temp_comp = {
+                       .addr = 0x60,
+                       .mask = BIT(7),
+               },
+               .pwr_table = {
+                       .reg = {
+                               .addr = 0x60,
+                               .mask = GENMASK(1, 0),
+                       },
+                       .off_val = 0x2,
+                       .on_val = 0x0,
+               },
+               .off_canc = {
+                       .addr = 0x61,
+                       .mask = BIT(1),
+               },
+               .bdu = {
+                       .addr = 0x62,
+                       .mask = BIT(4),
+               },
+               .out = {
+                       .addr = 0x68,
+                       .len = 6,
+               },
+       },
+};
+
+static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw)
+{
+       struct st_lsm6dsx_sensor *sensor;
+
+       sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+       msleep((2000U / sensor->odr) + 1);
+}
+
+/**
+ * st_lsm6dsx_shub_read_reg - read i2c controller register
+ *
+ * Read st_lsm6dsx i2c controller register
+ */
+static int st_lsm6dsx_shub_read_reg(struct st_lsm6dsx_hw *hw, u8 addr,
+                                   u8 *data, int len)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       int err;
+
+       mutex_lock(&hw->page_lock);
+
+       hub_settings = &hw->settings->shub_settings;
+       err = st_lsm6dsx_set_page(hw, true);
+       if (err < 0)
+               goto out;
+
+       err = regmap_bulk_read(hw->regmap, addr, data, len);
+
+       st_lsm6dsx_set_page(hw, false);
+out:
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
+
+/**
+ * st_lsm6dsx_shub_write_reg - write i2c controller register
+ *
+ * Write st_lsm6dsx i2c controller register
+ */
+static int st_lsm6dsx_shub_write_reg(struct st_lsm6dsx_hw *hw, u8 addr,
+                                    u8 *data, int len)
+{
+       int err;
+
+       mutex_lock(&hw->page_lock);
+       err = st_lsm6dsx_set_page(hw, true);
+       if (err < 0)
+               goto out;
+
+       err = regmap_bulk_write(hw->regmap, addr, data, len);
+
+       st_lsm6dsx_set_page(hw, false);
+out:
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
+
+static int
+st_lsm6dsx_shub_write_reg_with_mask(struct st_lsm6dsx_hw *hw, u8 addr,
+                                   u8 mask, u8 val)
+{
+       int err;
+
+       mutex_lock(&hw->page_lock);
+       err = st_lsm6dsx_set_page(hw, true);
+       if (err < 0)
+               goto out;
+
+       err = regmap_update_bits(hw->regmap, addr, mask, val);
+
+       st_lsm6dsx_set_page(hw, false);
+out:
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
+
+static int st_lsm6dsx_shub_master_enable(struct st_lsm6dsx_sensor *sensor,
+                                        bool enable)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       struct st_lsm6dsx_hw *hw = sensor->hw;
+       unsigned int data;
+       int err;
+
+       /* enable acc sensor as trigger */
+       err = st_lsm6dsx_sensor_set_enable(sensor, enable);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&hw->page_lock);
+
+       hub_settings = &hw->settings->shub_settings;
+       err = st_lsm6dsx_set_page(hw, true);
+       if (err < 0)
+               goto out;
+
+       data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->master_en.mask);
+       err = regmap_update_bits(hw->regmap, hub_settings->master_en.addr,
+                                hub_settings->master_en.mask, data);
+
+       st_lsm6dsx_set_page(hw, false);
+out:
+       mutex_unlock(&hw->page_lock);
+
+       return err;
+}
+
+/**
+ * st_lsm6dsx_shub_read - read data from slave device register
+ *
+ * Read data from slave device register. SLV0 is used for
+ * one-shot read operation
+ */
+static int
+st_lsm6dsx_shub_read(struct st_lsm6dsx_sensor *sensor, u8 addr,
+                    u8 *data, int len)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       struct st_lsm6dsx_hw *hw = sensor->hw;
+       u8 config[3], slv_addr;
+       int err;
+
+       hub_settings = &hw->settings->shub_settings;
+       slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
+
+       config[0] = (sensor->ext_info.addr << 1) | 1;
+       config[1] = addr;
+       config[2] = len & ST_LS6DSX_READ_OP_MASK;
+
+       err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
+                                       sizeof(config));
+       if (err < 0)
+               return err;
+
+       err = st_lsm6dsx_shub_master_enable(sensor, true);
+       if (err < 0)
+               return err;
+
+       st_lsm6dsx_shub_wait_complete(hw);
+
+       err = st_lsm6dsx_shub_read_reg(hw, hub_settings->shub_out, data,
+                                      len & ST_LS6DSX_READ_OP_MASK);
+
+       st_lsm6dsx_shub_master_enable(sensor, false);
+
+       memset(config, 0, sizeof(config));
+       return st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
+                                        sizeof(config));
+}
+
+/**
+ * st_lsm6dsx_shub_write - write data to slave device register
+ *
+ * Write data from slave device register. SLV0 is used for
+ * one-shot write operation
+ */
+static int
+st_lsm6dsx_shub_write(struct st_lsm6dsx_sensor *sensor, u8 addr,
+                     u8 *data, int len)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       struct st_lsm6dsx_hw *hw = sensor->hw;
+       u8 config[2], slv_addr;
+       int err, i;
+
+       hub_settings = &hw->settings->shub_settings;
+       if (hub_settings->wr_once.addr) {
+               unsigned int data;
+
+               data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->wr_once.mask);
+               err = st_lsm6dsx_shub_write_reg_with_mask(hw,
+                       hub_settings->wr_once.addr,
+                       hub_settings->wr_once.mask,
+                       data);
+               if (err < 0)
+                       return err;
+       }
+
+       slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
+       config[0] = sensor->ext_info.addr << 1;
+       for (i = 0 ; i < len; i++) {
+               config[1] = addr + i;
+
+               err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
+                                               sizeof(config));
+               if (err < 0)
+                       return err;
+
+               err = st_lsm6dsx_shub_write_reg(hw, hub_settings->dw_slv0_addr,
+                                               &data[i], 1);
+               if (err < 0)
+                       return err;
+
+               err = st_lsm6dsx_shub_master_enable(sensor, true);
+               if (err < 0)
+                       return err;
+
+               st_lsm6dsx_shub_wait_complete(hw);
+
+               st_lsm6dsx_shub_master_enable(sensor, false);
+       }
+
+       memset(config, 0, sizeof(config));
+       return st_lsm6dsx_shub_write_reg(hw, slv_addr, config, sizeof(config));
+}
+
+static int
+st_lsm6dsx_shub_write_with_mask(struct st_lsm6dsx_sensor *sensor,
+                               u8 addr, u8 mask, u8 val)
+{
+       int err;
+       u8 data;
+
+       err = st_lsm6dsx_shub_read(sensor, addr, &data, sizeof(data));
+       if (err < 0)
+               return err;
+
+       data = ((data & ~mask) | (val << __ffs(mask) & mask));
+
+       return st_lsm6dsx_shub_write(sensor, addr, &data, sizeof(data));
+}
+
+static int
+st_lsm6dsx_shub_get_odr_val(struct st_lsm6dsx_sensor *sensor,
+                           u16 odr, u16 *val)
+{
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       int i;
+
+       settings = sensor->ext_info.settings;
+       for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
+               if (settings->odr_table.odr_avl[i].hz == odr)
+                       break;
+
+       if (i == ST_LSM6DSX_ODR_LIST_SIZE)
+               return -EINVAL;
+
+       *val = settings->odr_table.odr_avl[i].val;
+       return 0;
+}
+
+static int
+st_lsm6dsx_shub_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
+{
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       u16 val;
+       int err;
+
+       err = st_lsm6dsx_shub_get_odr_val(sensor, odr, &val);
+       if (err < 0)
+               return err;
+
+       settings = sensor->ext_info.settings;
+       return st_lsm6dsx_shub_write_with_mask(sensor,
+                                              settings->odr_table.reg.addr,
+                                              settings->odr_table.reg.mask,
+                                              val);
+}
+
+/* use SLV{1,2,3} for FIFO read operations */
+static int
+st_lsm6dsx_shub_config_channels(struct st_lsm6dsx_sensor *sensor,
+                               bool enable)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       u8 config[9] = {}, enable_mask, slv_addr;
+       struct st_lsm6dsx_hw *hw = sensor->hw;
+       struct st_lsm6dsx_sensor *cur_sensor;
+       int i, j = 0;
+
+       hub_settings = &hw->settings->shub_settings;
+       if (enable)
+               enable_mask = hw->enable_mask | BIT(sensor->id);
+       else
+               enable_mask = hw->enable_mask & ~BIT(sensor->id);
+
+       for (i = ST_LSM6DSX_ID_EXT0; i <= ST_LSM6DSX_ID_EXT2; i++) {
+               if (!hw->iio_devs[i])
+                       continue;
+
+               cur_sensor = iio_priv(hw->iio_devs[i]);
+               if (!(enable_mask & BIT(cur_sensor->id)))
+                       continue;
+
+               settings = cur_sensor->ext_info.settings;
+               config[j] = (sensor->ext_info.addr << 1) | 1;
+               config[j + 1] = settings->out.addr;
+               config[j + 2] = (settings->out.len & ST_LS6DSX_READ_OP_MASK) |
+                               hub_settings->batch_en;
+               j += 3;
+       }
+
+       slv_addr = ST_LSM6DSX_SLV_ADDR(1, hub_settings->slv0_addr);
+       return st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
+                                        sizeof(config));
+}
+
+int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)
+{
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       int err;
+
+       err = st_lsm6dsx_shub_config_channels(sensor, enable);
+       if (err < 0)
+               return err;
+
+       settings = sensor->ext_info.settings;
+       if (enable) {
+               err = st_lsm6dsx_shub_set_odr(sensor, sensor->odr);
+               if (err < 0)
+                       return err;
+       } else {
+               err = st_lsm6dsx_shub_write_with_mask(sensor,
+                                       settings->odr_table.reg.addr,
+                                       settings->odr_table.reg.mask, 0);
+               if (err < 0)
+                       return err;
+       }
+
+       if (settings->pwr_table.reg.addr) {
+               u8 val;
+
+               val = enable ? settings->pwr_table.on_val
+                            : settings->pwr_table.off_val;
+               err = st_lsm6dsx_shub_write_with_mask(sensor,
+                                       settings->pwr_table.reg.addr,
+                                       settings->pwr_table.reg.mask, val);
+               if (err < 0)
+                       return err;
+       }
+
+       return st_lsm6dsx_shub_master_enable(sensor, enable);
+}
+
+static int
+st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor,
+                            struct iio_chan_spec const *ch,
+                            int *val)
+{
+       int err, delay, len = ch->scan_type.realbits >> 3;
+       __le16 data;
+
+       err = st_lsm6dsx_shub_set_enable(sensor, true);
+       if (err < 0)
+               return err;
+
+       delay = 1000000 / sensor->odr;
+       usleep_range(delay, 2 * delay);
+
+       err = st_lsm6dsx_shub_read(sensor, ch->address, (u8 *)&data, len);
+       if (err < 0)
+               return err;
+
+       st_lsm6dsx_shub_set_enable(sensor, false);
+
+       switch (len) {
+       case 2:
+               *val = (s16)le16_to_cpu(data);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return IIO_VAL_INT;
+}
+
+static int
+st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev,
+                        struct iio_chan_spec const *ch,
+                        int *val, int *val2, long mask)
+{
+       struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(iio_dev);
+               if (ret)
+                       break;
+
+               ret = st_lsm6dsx_shub_read_oneshot(sensor, ch, val);
+               iio_device_release_direct_mode(iio_dev);
+               break;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *val = sensor->odr;
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = sensor->gain;
+               ret = IIO_VAL_INT_PLUS_MICRO;
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int
+st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev,
+                         struct iio_chan_spec const *chan,
+                         int val, int val2, long mask)
+{
+       struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+       int err;
+
+       err = iio_device_claim_direct_mode(iio_dev);
+       if (err)
+               return err;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ: {
+               u16 data;
+
+               err = st_lsm6dsx_shub_get_odr_val(sensor, val, &data);
+               if (!err)
+                       sensor->odr = val;
+               break;
+       }
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       iio_device_release_direct_mode(iio_dev);
+
+       return err;
+}
+
+static ssize_t
+st_lsm6dsx_shub_sampling_freq_avail(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
+{
+       struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       int i, len = 0;
+
+       settings = sensor->ext_info.settings;
+       for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) {
+               u16 val = settings->odr_table.odr_avl[i].hz;
+
+               if (val > 0)
+                       len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+                                        val);
+       }
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static ssize_t st_lsm6dsx_shub_scale_avail(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       int i, len = 0;
+
+       settings = sensor->ext_info.settings;
+       for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) {
+               u16 val = settings->fs_table.fs_avl[i].gain;
+
+               if (val > 0)
+                       len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
+                                        val);
+       }
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_shub_sampling_freq_avail);
+static IIO_DEVICE_ATTR(in_scale_available, 0444,
+                      st_lsm6dsx_shub_scale_avail, NULL, 0);
+static struct attribute *st_lsm6dsx_ext_attributes[] = {
+       &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_in_scale_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group st_lsm6dsx_ext_attribute_group = {
+       .attrs = st_lsm6dsx_ext_attributes,
+};
+
+static const struct iio_info st_lsm6dsx_ext_info = {
+       .attrs = &st_lsm6dsx_ext_attribute_group,
+       .read_raw = st_lsm6dsx_shub_read_raw,
+       .write_raw = st_lsm6dsx_shub_write_raw,
+       .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
+};
+
+static struct iio_dev *
+st_lsm6dsx_shub_alloc_iiodev(struct st_lsm6dsx_hw *hw,
+                            enum st_lsm6dsx_sensor_id id,
+                            const struct st_lsm6dsx_ext_dev_settings *info,
+                            u8 i2c_addr, const char *name)
+{
+       struct iio_chan_spec *ext_channels;
+       struct st_lsm6dsx_sensor *sensor;
+       struct iio_dev *iio_dev;
+
+       iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
+       if (!iio_dev)
+               return NULL;
+
+       iio_dev->modes = INDIO_DIRECT_MODE;
+       iio_dev->dev.parent = hw->dev;
+       iio_dev->info = &st_lsm6dsx_ext_info;
+
+       sensor = iio_priv(iio_dev);
+       sensor->id = id;
+       sensor->hw = hw;
+       sensor->odr = info->odr_table.odr_avl[0].hz;
+       sensor->gain = info->fs_table.fs_avl[0].gain;
+       sensor->ext_info.settings = info;
+       sensor->ext_info.addr = i2c_addr;
+       sensor->watermark = 1;
+
+       switch (info->id) {
+       case ST_LSM6DSX_ID_MAGN: {
+               const struct iio_chan_spec magn_channels[] = {
+                       ST_LSM6DSX_CHANNEL(IIO_MAGN, info->out.addr,
+                                          IIO_MOD_X, 0),
+                       ST_LSM6DSX_CHANNEL(IIO_MAGN, info->out.addr + 2,
+                                          IIO_MOD_Y, 1),
+                       ST_LSM6DSX_CHANNEL(IIO_MAGN, info->out.addr + 4,
+                                          IIO_MOD_Z, 2),
+                       IIO_CHAN_SOFT_TIMESTAMP(3),
+               };
+
+               ext_channels = devm_kzalloc(hw->dev, sizeof(magn_channels),
+                                           GFP_KERNEL);
+               if (!ext_channels)
+                       return NULL;
+
+               memcpy(ext_channels, magn_channels, sizeof(magn_channels));
+               iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
+               iio_dev->channels = ext_channels;
+               iio_dev->num_channels = ARRAY_SIZE(magn_channels);
+
+               scnprintf(sensor->name, sizeof(sensor->name), "%s_magn",
+                         name);
+               break;
+       }
+       default:
+               return NULL;
+       }
+       iio_dev->name = sensor->name;
+
+       return iio_dev;
+}
+
+static int st_lsm6dsx_shub_init_device(struct st_lsm6dsx_sensor *sensor)
+{
+       const struct st_lsm6dsx_ext_dev_settings *settings;
+       int err;
+
+       settings = sensor->ext_info.settings;
+       if (settings->bdu.addr) {
+               err = st_lsm6dsx_shub_write_with_mask(sensor,
+                                                     settings->bdu.addr,
+                                                     settings->bdu.mask, 1);
+               if (err < 0)
+                       return err;
+       }
+
+       if (settings->temp_comp.addr) {
+               err = st_lsm6dsx_shub_write_with_mask(sensor,
+                                       settings->temp_comp.addr,
+                                       settings->temp_comp.mask, 1);
+               if (err < 0)
+                       return err;
+       }
+
+       if (settings->off_canc.addr) {
+               err = st_lsm6dsx_shub_write_with_mask(sensor,
+                                       settings->off_canc.addr,
+                                       settings->off_canc.mask, 1);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int
+st_lsm6dsx_shub_check_wai(struct st_lsm6dsx_hw *hw, u8 *i2c_addr,
+                         const struct st_lsm6dsx_ext_dev_settings *settings)
+{
+       const struct st_lsm6dsx_shub_settings *hub_settings;
+       struct st_lsm6dsx_sensor *sensor;
+       u8 config[3], data, slv_addr;
+       bool found = false;
+       int i, err;
+
+       hub_settings = &hw->settings->shub_settings;
+       slv_addr = ST_LSM6DSX_SLV_ADDR(0, hub_settings->slv0_addr);
+       sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+
+       for (i = 0; i < ARRAY_SIZE(settings->i2c_addr); i++) {
+               if (!settings->i2c_addr[i])
+                       continue;
+
+               /* read wai slave register */
+               config[0] = (settings->i2c_addr[i] << 1) | 0x1;
+               config[1] = settings->wai.addr;
+               config[2] = 0x1;
+
+               err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
+                                               sizeof(config));
+               if (err < 0)
+                       return err;
+
+               err = st_lsm6dsx_shub_master_enable(sensor, true);
+               if (err < 0)
+                       return err;
+
+               st_lsm6dsx_shub_wait_complete(hw);
+
+               err = st_lsm6dsx_shub_read_reg(hw,
+                                              hub_settings->shub_out,
+                                              &data, sizeof(data));
+
+               st_lsm6dsx_shub_master_enable(sensor, false);
+
+               if (err < 0)
+                       return err;
+
+               if (data != settings->wai.val)
+                       continue;
+
+               *i2c_addr = settings->i2c_addr[i];
+               found = true;
+               break;
+       }
+
+       /* reset SLV0 channel */
+       memset(config, 0, sizeof(config));
+       err = st_lsm6dsx_shub_write_reg(hw, slv_addr, config,
+                                       sizeof(config));
+       if (err < 0)
+               return err;
+
+       return found ? 0 : -ENODEV;
+}
+
+int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name)
+{
+       enum st_lsm6dsx_sensor_id id = ST_LSM6DSX_ID_EXT0;
+       struct st_lsm6dsx_sensor *sensor;
+       int err, i, num_ext_dev = 0;
+       u8 i2c_addr = 0;
+
+       for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_ext_dev_table); i++) {
+               err = st_lsm6dsx_shub_check_wai(hw, &i2c_addr,
+                                       &st_lsm6dsx_ext_dev_table[i]);
+               if (err == -ENODEV)
+                       continue;
+               else if (err < 0)
+                       return err;
+
+               hw->iio_devs[id] = st_lsm6dsx_shub_alloc_iiodev(hw, id,
+                                               &st_lsm6dsx_ext_dev_table[i],
+                                               i2c_addr, name);
+               if (!hw->iio_devs[id])
+                       return -ENOMEM;
+
+               sensor = iio_priv(hw->iio_devs[id]);
+               err = st_lsm6dsx_shub_init_device(sensor);
+               if (err < 0)
+                       return err;
+
+               if (++num_ext_dev >= ST_LSM6DSX_MAX_SLV_NUM)
+                       break;
+               id++;
+       }
+
+       return 0;
+}
index d66ea754fffff7d341bc8fe8b959fad385a5171b..36f45843348053ae4b31bd01d4a1d527dd5991ec 100644 (file)
@@ -460,6 +460,19 @@ config VCNL4000
         To compile this driver as a module, choose M here: the
         module will be called vcnl4000.
 
+config VCNL4035
+       tristate "VCNL4035 combined ALS and proximity sensor"
+       select IIO_TRIGGERED_BUFFER
+       select REGMAP_I2C
+       depends on I2C
+       help
+        Say Y here if you want to build a driver for the Vishay VCNL4035,
+        combined ambient light (ALS) and proximity sensor. Currently only ALS
+        function is available.
+
+        To compile this driver as a module, choose M here: the
+        module will be called vcnl4035.
+
 config VEML6070
        tristate "VEML6070 UV A light sensor"
        depends on I2C
index 86337b114bc4e5a7339247e40d660b1b10d55e9c..286bf39753722b265cb19908beda0909165ce45b 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_TSL2772)         += tsl2772.o
 obj-$(CONFIG_TSL4531)          += tsl4531.o
 obj-$(CONFIG_US5182D)          += us5182d.o
 obj-$(CONFIG_VCNL4000)         += vcnl4000.o
+obj-$(CONFIG_VCNL4035)         += vcnl4035.o
 obj-$(CONFIG_VEML6070)         += veml6070.o
 obj-$(CONFIG_VL6180)           += vl6180.o
 obj-$(CONFIG_ZOPT2201)         += zopt2201.o
diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c
new file mode 100644 (file)
index 0000000..cca4db3
--- /dev/null
@@ -0,0 +1,676 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * VCNL4035 Ambient Light and Proximity Sensor - 7-bit I2C slave address 0x60
+ *
+ * Copyright (c) 2018, DENX Software Engineering GmbH
+ * Author: Parthiban Nallathambi <pn@denx.de>
+ *
+ * TODO: Proximity
+ */
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define VCNL4035_DRV_NAME      "vcnl4035"
+#define VCNL4035_IRQ_NAME      "vcnl4035_event"
+#define VCNL4035_REGMAP_NAME   "vcnl4035_regmap"
+
+/* Device registers */
+#define VCNL4035_ALS_CONF      0x00
+#define VCNL4035_ALS_THDH      0x01
+#define VCNL4035_ALS_THDL      0x02
+#define VCNL4035_ALS_DATA      0x0B
+#define VCNL4035_WHITE_DATA    0x0C
+#define VCNL4035_INT_FLAG      0x0D
+#define VCNL4035_DEV_ID                0x0E
+
+/* Register masks */
+#define VCNL4035_MODE_ALS_MASK         BIT(0)
+#define VCNL4035_MODE_ALS_WHITE_CHAN   BIT(8)
+#define VCNL4035_MODE_ALS_INT_MASK     BIT(1)
+#define VCNL4035_ALS_IT_MASK           GENMASK(7, 5)
+#define VCNL4035_ALS_PERS_MASK         GENMASK(3, 2)
+#define VCNL4035_INT_ALS_IF_H_MASK     BIT(12)
+#define VCNL4035_INT_ALS_IF_L_MASK     BIT(13)
+
+/* Default values */
+#define VCNL4035_MODE_ALS_ENABLE       BIT(0)
+#define VCNL4035_MODE_ALS_DISABLE      0x00
+#define VCNL4035_MODE_ALS_INT_ENABLE   BIT(1)
+#define VCNL4035_MODE_ALS_INT_DISABLE  0
+#define VCNL4035_DEV_ID_VAL            0x80
+#define VCNL4035_ALS_IT_DEFAULT                0x01
+#define VCNL4035_ALS_PERS_DEFAULT      0x00
+#define VCNL4035_ALS_THDH_DEFAULT      5000
+#define VCNL4035_ALS_THDL_DEFAULT      100
+#define VCNL4035_SLEEP_DELAY_MS                2000
+
+struct vcnl4035_data {
+       struct i2c_client *client;
+       struct regmap *regmap;
+       unsigned int als_it_val;
+       unsigned int als_persistence;
+       unsigned int als_thresh_low;
+       unsigned int als_thresh_high;
+       struct iio_trigger *drdy_trigger0;
+};
+
+static inline bool vcnl4035_is_triggered(struct vcnl4035_data *data)
+{
+       int ret;
+       int reg;
+
+       ret = regmap_read(data->regmap, VCNL4035_INT_FLAG, &reg);
+       if (ret < 0)
+               return false;
+
+       return !!(reg &
+               (VCNL4035_INT_ALS_IF_H_MASK | VCNL4035_INT_ALS_IF_L_MASK));
+}
+
+static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+
+       if (vcnl4035_is_triggered(data)) {
+               iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+                                                       0,
+                                                       IIO_EV_TYPE_THRESH,
+                                                       IIO_EV_DIR_EITHER),
+                               iio_get_time_ns(indio_dev));
+               iio_trigger_poll_chained(data->drdy_trigger0);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+/* Triggered buffer */
+static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+       u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)];
+       int ret;
+
+       ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
+       if (ret < 0) {
+               dev_err(&data->client->dev,
+                       "Trigger consumer can't read from sensor.\n");
+               goto fail_read;
+       }
+       iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+                                       iio_get_time_ns(indio_dev));
+
+fail_read:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int vcnl4035_als_drdy_set_state(struct iio_trigger *trigger,
+                                       bool enable_drdy)
+{
+       struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+       int val = enable_drdy ? VCNL4035_MODE_ALS_INT_ENABLE :
+                                       VCNL4035_MODE_ALS_INT_DISABLE;
+
+       return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                VCNL4035_MODE_ALS_INT_MASK,
+                                val);
+}
+
+static const struct iio_trigger_ops vcnl4035_trigger_ops = {
+       .validate_device = iio_trigger_validate_own_device,
+       .set_trigger_state = vcnl4035_als_drdy_set_state,
+};
+
+static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
+{
+       int ret;
+       struct device *dev = &data->client->dev;
+
+       if (on) {
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0)
+                       pm_runtime_put_noidle(dev);
+       } else {
+               pm_runtime_mark_last_busy(dev);
+               ret = pm_runtime_put_autosuspend(dev);
+       }
+
+       return ret;
+}
+
+/*
+ *     Device IT       INT Time (ms)   Scale (lux/step)
+ *     000             50              0.064
+ *     001             100             0.032
+ *     010             200             0.016
+ *     100             400             0.008
+ *     101 - 111       800             0.004
+ * Values are proportional, so ALS INT is selected for input due to
+ * simplicity reason. Integration time value and scaling is
+ * calculated based on device INT value
+ *
+ * Raw value needs to be scaled using ALS steps
+ */
+static int vcnl4035_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan, int *val,
+                           int *val2, long mask)
+{
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+       int ret;
+       int raw_data;
+       unsigned int reg;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = vcnl4035_set_pm_runtime_state(data, true);
+               if  (ret < 0)
+                       return ret;
+
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (!ret) {
+                       if (chan->channel)
+                               reg = VCNL4035_ALS_DATA;
+                       else
+                               reg = VCNL4035_WHITE_DATA;
+                       ret = regmap_read(data->regmap, reg, &raw_data);
+                       iio_device_release_direct_mode(indio_dev);
+                       if (!ret) {
+                               *val = raw_data;
+                               ret = IIO_VAL_INT;
+                       }
+               }
+               vcnl4035_set_pm_runtime_state(data, false);
+               return ret;
+       case IIO_CHAN_INFO_INT_TIME:
+               *val = 50;
+               if (data->als_it_val)
+                       *val = data->als_it_val * 100;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 64;
+               if (!data->als_it_val)
+                       *val2 = 1000;
+               else
+                       *val2 = data->als_it_val * 2 * 1000;
+               return IIO_VAL_FRACTIONAL;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vcnl4035_write_raw(struct iio_dev *indio_dev,
+                               struct iio_chan_spec const *chan,
+                               int val, int val2, long mask)
+{
+       int ret;
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_INT_TIME:
+               if (val <= 0 || val > 800)
+                       return -EINVAL;
+
+               ret = vcnl4035_set_pm_runtime_state(data, true);
+               if  (ret < 0)
+                       return ret;
+
+               ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                        VCNL4035_ALS_IT_MASK,
+                                        val / 100);
+               if (!ret)
+                       data->als_it_val = val / 100;
+
+               vcnl4035_set_pm_runtime_state(data, false);
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+/* No direct ABI for persistence and threshold, so eventing */
+static int vcnl4035_read_thresh(struct iio_dev *indio_dev,
+               const struct iio_chan_spec *chan, enum iio_event_type type,
+               enum iio_event_direction dir, enum iio_event_info info,
+               int *val, int *val2)
+{
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               switch (dir) {
+               case IIO_EV_DIR_RISING:
+                       *val = data->als_thresh_high;
+                       return IIO_VAL_INT;
+               case IIO_EV_DIR_FALLING:
+                       *val = data->als_thresh_low;
+                       return IIO_VAL_INT;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_EV_INFO_PERIOD:
+               *val = data->als_persistence;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+
+}
+
+static int vcnl4035_write_thresh(struct iio_dev *indio_dev,
+               const struct iio_chan_spec *chan, enum iio_event_type type,
+               enum iio_event_direction dir, enum iio_event_info info, int val,
+               int val2)
+{
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               /* 16 bit threshold range 0 - 65535 */
+               if (val < 0 || val > 65535)
+                       return -EINVAL;
+               if (dir == IIO_EV_DIR_RISING) {
+                       if (val < data->als_thresh_low)
+                               return -EINVAL;
+                       ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
+                                          val);
+                       if (ret)
+                               return ret;
+                       data->als_thresh_high = val;
+               } else {
+                       if (val > data->als_thresh_high)
+                               return -EINVAL;
+                       ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
+                                          val);
+                       if (ret)
+                               return ret;
+                       data->als_thresh_low = val;
+               }
+               return ret;
+       case IIO_EV_INFO_PERIOD:
+               /* allow only 1 2 4 8 as persistence value */
+               if (val < 0 || val > 8 || hweight8(val) != 1)
+                       return -EINVAL;
+               ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                        VCNL4035_ALS_PERS_MASK, val);
+               if (!ret)
+                       data->als_persistence = val;
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static IIO_CONST_ATTR_INT_TIME_AVAIL("50 100 200 400 800");
+
+static struct attribute *vcnl4035_attributes[] = {
+       &iio_const_attr_integration_time_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group vcnl4035_attribute_group = {
+       .attrs = vcnl4035_attributes,
+};
+
+static const struct iio_info vcnl4035_info = {
+       .read_raw               = vcnl4035_read_raw,
+       .write_raw              = vcnl4035_write_raw,
+       .read_event_value       = vcnl4035_read_thresh,
+       .write_event_value      = vcnl4035_write_thresh,
+       .attrs                  = &vcnl4035_attribute_group,
+};
+
+static const struct iio_event_spec vcnl4035_event_spec[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+       }, {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE),
+       }, {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_EITHER,
+               .mask_separate = BIT(IIO_EV_INFO_PERIOD),
+       },
+};
+
+enum vcnl4035_scan_index_order {
+       VCNL4035_CHAN_INDEX_LIGHT,
+       VCNL4035_CHAN_INDEX_WHITE_LED,
+};
+
+static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
+       .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static const struct iio_chan_spec vcnl4035_channels[] = {
+       {
+               .type = IIO_LIGHT,
+               .channel = 0,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                               BIT(IIO_CHAN_INFO_INT_TIME) |
+                               BIT(IIO_CHAN_INFO_SCALE),
+               .event_spec = vcnl4035_event_spec,
+               .num_event_specs = ARRAY_SIZE(vcnl4035_event_spec),
+               .scan_index = VCNL4035_CHAN_INDEX_LIGHT,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_LE,
+               },
+       },
+       {
+               .type = IIO_INTENSITY,
+               .channel = 1,
+               .modified = 1,
+               .channel2 = IIO_MOD_LIGHT_BOTH,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .scan_index = VCNL4035_CHAN_INDEX_WHITE_LED,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_LE,
+               },
+       },
+};
+
+static int vcnl4035_set_als_power_state(struct vcnl4035_data *data, u8 status)
+{
+       return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                       VCNL4035_MODE_ALS_MASK,
+                                       status);
+}
+
+static int vcnl4035_init(struct vcnl4035_data *data)
+{
+       int ret;
+       int id;
+
+       ret = regmap_read(data->regmap, VCNL4035_DEV_ID, &id);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "Failed to read DEV_ID register\n");
+               return ret;
+       }
+
+       if (id != VCNL4035_DEV_ID_VAL) {
+               dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
+                       id, VCNL4035_DEV_ID_VAL);
+               return -ENODEV;
+       }
+
+       ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
+       if (ret < 0)
+               return ret;
+
+       /* ALS white channel enable */
+       ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                VCNL4035_MODE_ALS_WHITE_CHAN,
+                                1);
+       if (ret) {
+               dev_err(&data->client->dev, "set white channel enable %d\n",
+                       ret);
+               return ret;
+       }
+
+       /* set default integration time - 100 ms for ALS */
+       ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                VCNL4035_ALS_IT_MASK,
+                                VCNL4035_ALS_IT_DEFAULT);
+       if (ret) {
+               dev_err(&data->client->dev, "set default ALS IT returned %d\n",
+                       ret);
+               return ret;
+       }
+       data->als_it_val = VCNL4035_ALS_IT_DEFAULT;
+
+       /* set default persistence time - 1 for ALS */
+       ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
+                                VCNL4035_ALS_PERS_MASK,
+                                VCNL4035_ALS_PERS_DEFAULT);
+       if (ret) {
+               dev_err(&data->client->dev, "set default PERS returned %d\n",
+                       ret);
+               return ret;
+       }
+       data->als_persistence = VCNL4035_ALS_PERS_DEFAULT;
+
+       /* set default HIGH threshold for ALS */
+       ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
+                               VCNL4035_ALS_THDH_DEFAULT);
+       if (ret) {
+               dev_err(&data->client->dev, "set default THDH returned %d\n",
+                       ret);
+               return ret;
+       }
+       data->als_thresh_high = VCNL4035_ALS_THDH_DEFAULT;
+
+       /* set default LOW threshold for ALS */
+       ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
+                               VCNL4035_ALS_THDL_DEFAULT);
+       if (ret) {
+               dev_err(&data->client->dev, "set default THDL returned %d\n",
+                       ret);
+               return ret;
+       }
+       data->als_thresh_low = VCNL4035_ALS_THDL_DEFAULT;
+
+       return 0;
+}
+
+static bool vcnl4035_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case VCNL4035_ALS_CONF:
+       case VCNL4035_DEV_ID:
+               return false;
+       default:
+               return true;
+       }
+}
+
+static const struct regmap_config vcnl4035_regmap_config = {
+       .name           = VCNL4035_REGMAP_NAME,
+       .reg_bits       = 8,
+       .val_bits       = 16,
+       .max_register   = VCNL4035_DEV_ID,
+       .cache_type     = REGCACHE_RBTREE,
+       .volatile_reg   = vcnl4035_is_volatile_reg,
+       .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+
+       data->drdy_trigger0 = devm_iio_trigger_alloc(
+                       indio_dev->dev.parent,
+                       "%s-dev%d", indio_dev->name, indio_dev->id);
+       if (!data->drdy_trigger0)
+               return -ENOMEM;
+
+       data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
+       data->drdy_trigger0->ops = &vcnl4035_trigger_ops;
+       iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
+       ret = devm_iio_trigger_register(indio_dev->dev.parent,
+                                       data->drdy_trigger0);
+       if (ret) {
+               dev_err(&data->client->dev, "iio trigger register failed\n");
+               return ret;
+       }
+
+       /* Trigger setup */
+       ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
+                                       NULL, vcnl4035_trigger_consumer_handler,
+                                       &iio_triggered_buffer_setup_ops);
+       if (ret < 0) {
+               dev_err(&data->client->dev, "iio triggered buffer setup failed\n");
+               return ret;
+       }
+
+       /* IRQ to trigger mapping */
+       ret = devm_request_threaded_irq(&data->client->dev, data->client->irq,
+                       NULL, vcnl4035_drdy_irq_thread,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                       VCNL4035_IRQ_NAME, indio_dev);
+       if (ret < 0)
+               dev_err(&data->client->dev, "request irq %d for trigger0 failed\n",
+                               data->client->irq);
+       return ret;
+}
+
+static int vcnl4035_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct vcnl4035_data *data;
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_i2c(client, &vcnl4035_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&client->dev, "regmap_init failed!\n");
+               return PTR_ERR(regmap);
+       }
+
+       data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
+       data->client = client;
+       data->regmap = regmap;
+
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->info = &vcnl4035_info;
+       indio_dev->name = VCNL4035_DRV_NAME;
+       indio_dev->channels = vcnl4035_channels;
+       indio_dev->num_channels = ARRAY_SIZE(vcnl4035_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = vcnl4035_init(data);
+       if (ret < 0) {
+               dev_err(&client->dev, "vcnl4035 chip init failed\n");
+               return ret;
+       }
+
+       if (client->irq > 0) {
+               ret = vcnl4035_probe_trigger(indio_dev);
+               if (ret < 0) {
+                       dev_err(&client->dev, "vcnl4035 unable init trigger\n");
+                       goto fail_poweroff;
+               }
+       }
+
+       ret = pm_runtime_set_active(&client->dev);
+       if (ret < 0)
+               goto fail_poweroff;
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0)
+               goto fail_poweroff;
+
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, VCNL4035_SLEEP_DELAY_MS);
+       pm_runtime_use_autosuspend(&client->dev);
+
+       return 0;
+
+fail_poweroff:
+       vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
+       return ret;
+}
+
+static int vcnl4035_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+       pm_runtime_dont_use_autosuspend(&client->dev);
+       pm_runtime_disable(&client->dev);
+       iio_device_unregister(indio_dev);
+       pm_runtime_set_suspended(&client->dev);
+
+       return vcnl4035_set_als_power_state(iio_priv(indio_dev),
+                                       VCNL4035_MODE_ALS_DISABLE);
+}
+
+static int __maybe_unused vcnl4035_runtime_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+       int ret;
+
+       ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
+       regcache_mark_dirty(data->regmap);
+
+       return ret;
+}
+
+static int __maybe_unused vcnl4035_runtime_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct vcnl4035_data *data = iio_priv(indio_dev);
+       int ret;
+
+       regcache_sync(data->regmap);
+       ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
+       if (ret < 0)
+               return ret;
+
+       /* wait for 1 ALS integration cycle */
+       msleep(data->als_it_val * 100);
+
+       return 0;
+}
+
+static const struct dev_pm_ops vcnl4035_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(vcnl4035_runtime_suspend,
+                          vcnl4035_runtime_resume, NULL)
+};
+
+static const struct of_device_id vcnl4035_of_match[] = {
+       { .compatible = "vishay,vcnl4035", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, vcnl4035_of_match);
+
+static struct i2c_driver vcnl4035_driver = {
+       .driver = {
+               .name   = VCNL4035_DRV_NAME,
+               .pm     = &vcnl4035_pm_ops,
+               .of_match_table = vcnl4035_of_match,
+       },
+       .probe  = vcnl4035_probe,
+       .remove = vcnl4035_remove,
+};
+
+module_i2c_driver(vcnl4035_driver);
+
+MODULE_AUTHOR("Parthiban Nallathambi <pn@denx.de>");
+MODULE_DESCRIPTION("VCNL4035 Ambient Light Sensor driver");
+MODULE_LICENSE("GPL v2");
index ed9d776d01afd9609731679e4552017d314e80a6..8a63cbbca4b7274e6ebb134ce2966e1144b25bf9 100644 (file)
@@ -175,4 +175,33 @@ config SENSORS_HMC5843_SPI
          - hmc5843_core (core functions)
          - hmc5843_spi (support for HMC5983)
 
+config SENSORS_RM3100
+       tristate
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+
+config SENSORS_RM3100_I2C
+       tristate "PNI RM3100 3-Axis Magnetometer (I2C)"
+       depends on I2C
+       select SENSORS_RM3100
+       select REGMAP_I2C
+       help
+         Say Y here to add support for the PNI RM3100 3-Axis Magnetometer.
+
+         This driver can also be compiled as a module.
+         To compile this driver as a module, choose M here: the module
+         will be called rm3100-i2c.
+
+config SENSORS_RM3100_SPI
+       tristate "PNI RM3100 3-Axis Magnetometer (SPI)"
+       depends on SPI_MASTER
+       select SENSORS_RM3100
+       select REGMAP_SPI
+       help
+         Say Y here to add support for the PNI RM3100 3-Axis Magnetometer.
+
+         This driver can also be compiled as a module.
+         To compile this driver as a module, choose M here: the module
+         will be called rm3100-spi.
+
 endmenu
index 664b2f866472d120e2d488c9f6a7939aae00f068..ba1bc34b82fafe9d35db19221ac740d33b378d52 100644 (file)
@@ -24,3 +24,7 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
 obj-$(CONFIG_SENSORS_HMC5843)          += hmc5843_core.o
 obj-$(CONFIG_SENSORS_HMC5843_I2C)      += hmc5843_i2c.o
 obj-$(CONFIG_SENSORS_HMC5843_SPI)      += hmc5843_spi.o
+
+obj-$(CONFIG_SENSORS_RM3100)           += rm3100-core.o
+obj-$(CONFIG_SENSORS_RM3100_I2C)       += rm3100-i2c.o
+obj-$(CONFIG_SENSORS_RM3100_SPI)       += rm3100-spi.o
diff --git a/drivers/iio/magnetometer/rm3100-core.c b/drivers/iio/magnetometer/rm3100-core.c
new file mode 100644 (file)
index 0000000..7c20918
--- /dev/null
@@ -0,0 +1,616 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PNI RM3100 3-axis geomagnetic sensor driver core.
+ *
+ * Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
+ *
+ * User Manual available at
+ * <https://www.pnicorp.com/download/rm3100-user-manual/>
+ *
+ * TODO: event generation, pm.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include "rm3100.h"
+
+/* Cycle Count Registers. */
+#define RM3100_REG_CC_X                        0x05
+#define RM3100_REG_CC_Y                        0x07
+#define RM3100_REG_CC_Z                        0x09
+
+/* Poll Measurement Mode register. */
+#define RM3100_REG_POLL                        0x00
+#define                RM3100_POLL_X           BIT(4)
+#define                RM3100_POLL_Y           BIT(5)
+#define                RM3100_POLL_Z           BIT(6)
+
+/* Continuous Measurement Mode register. */
+#define RM3100_REG_CMM                 0x01
+#define                RM3100_CMM_START        BIT(0)
+#define                RM3100_CMM_X            BIT(4)
+#define                RM3100_CMM_Y            BIT(5)
+#define                RM3100_CMM_Z            BIT(6)
+
+/* TiMe Rate Configuration register. */
+#define RM3100_REG_TMRC                        0x0B
+#define RM3100_TMRC_OFFSET             0x92
+
+/* Result Status register. */
+#define RM3100_REG_STATUS              0x34
+#define                RM3100_STATUS_DRDY      BIT(7)
+
+/* Measurement result registers. */
+#define RM3100_REG_MX2                 0x24
+#define RM3100_REG_MY2                 0x27
+#define RM3100_REG_MZ2                 0x2a
+
+#define RM3100_W_REG_START             RM3100_REG_POLL
+#define RM3100_W_REG_END               RM3100_REG_TMRC
+#define RM3100_R_REG_START             RM3100_REG_POLL
+#define RM3100_R_REG_END               RM3100_REG_STATUS
+#define RM3100_V_REG_START             RM3100_REG_POLL
+#define RM3100_V_REG_END               RM3100_REG_STATUS
+
+/*
+ * This is computed by hand, is the sum of channel storage bits and padding
+ * bits, which is 4+4+4+12=24 in here.
+ */
+#define RM3100_SCAN_BYTES              24
+
+#define RM3100_CMM_AXIS_SHIFT          4
+
+struct rm3100_data {
+       struct regmap *regmap;
+       struct completion measuring_done;
+       bool use_interrupt;
+       int conversion_time;
+       int scale;
+       u8 buffer[RM3100_SCAN_BYTES];
+       struct iio_trigger *drdy_trig;
+
+       /*
+        * This lock is for protecting the consistency of series of i2c
+        * operations, that is, to make sure a measurement process will
+        * not be interrupted by a set frequency operation, which should
+        * be taken where a series of i2c operation starts, released where
+        * the operation ends.
+        */
+       struct mutex lock;
+};
+
+static const struct regmap_range rm3100_readable_ranges[] = {
+       regmap_reg_range(RM3100_R_REG_START, RM3100_R_REG_END),
+};
+
+const struct regmap_access_table rm3100_readable_table = {
+       .yes_ranges = rm3100_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(rm3100_readable_ranges),
+};
+EXPORT_SYMBOL_GPL(rm3100_readable_table);
+
+static const struct regmap_range rm3100_writable_ranges[] = {
+       regmap_reg_range(RM3100_W_REG_START, RM3100_W_REG_END),
+};
+
+const struct regmap_access_table rm3100_writable_table = {
+       .yes_ranges = rm3100_writable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(rm3100_writable_ranges),
+};
+EXPORT_SYMBOL_GPL(rm3100_writable_table);
+
+static const struct regmap_range rm3100_volatile_ranges[] = {
+       regmap_reg_range(RM3100_V_REG_START, RM3100_V_REG_END),
+};
+
+const struct regmap_access_table rm3100_volatile_table = {
+       .yes_ranges = rm3100_volatile_ranges,
+       .n_yes_ranges = ARRAY_SIZE(rm3100_volatile_ranges),
+};
+EXPORT_SYMBOL_GPL(rm3100_volatile_table);
+
+static irqreturn_t rm3100_thread_fn(int irq, void *d)
+{
+       struct iio_dev *indio_dev = d;
+       struct rm3100_data *data = iio_priv(indio_dev);
+
+       /*
+        * Write operation to any register or read operation
+        * to first byte of results will clear the interrupt.
+        */
+       regmap_write(data->regmap, RM3100_REG_POLL, 0);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t rm3100_irq_handler(int irq, void *d)
+{
+       struct iio_dev *indio_dev = d;
+       struct rm3100_data *data = iio_priv(indio_dev);
+
+       switch (indio_dev->currentmode) {
+       case INDIO_DIRECT_MODE:
+               complete(&data->measuring_done);
+               break;
+       case INDIO_BUFFER_TRIGGERED:
+               iio_trigger_poll(data->drdy_trig);
+               break;
+       default:
+               dev_err(indio_dev->dev.parent,
+                       "device mode out of control, current mode: %d",
+                       indio_dev->currentmode);
+       }
+
+       return IRQ_WAKE_THREAD;
+}
+
+static int rm3100_wait_measurement(struct rm3100_data *data)
+{
+       struct regmap *regmap = data->regmap;
+       unsigned int val;
+       int tries = 20;
+       int ret;
+
+       /*
+        * A read cycle of 400kbits i2c bus is about 20us, plus the time
+        * used for scheduling, a read cycle of fast mode of this device
+        * can reach 1.7ms, it may be possible for data to arrive just
+        * after we check the RM3100_REG_STATUS. In this case, irq_handler is
+        * called before measuring_done is reinitialized, it will wait
+        * forever for data that has already been ready.
+        * Reinitialize measuring_done before looking up makes sure we
+        * will always capture interrupt no matter when it happens.
+        */
+       if (data->use_interrupt)
+               reinit_completion(&data->measuring_done);
+
+       ret = regmap_read(regmap, RM3100_REG_STATUS, &val);
+       if (ret < 0)
+               return ret;
+
+       if ((val & RM3100_STATUS_DRDY) != RM3100_STATUS_DRDY) {
+               if (data->use_interrupt) {
+                       ret = wait_for_completion_timeout(&data->measuring_done,
+                               msecs_to_jiffies(data->conversion_time));
+                       if (!ret)
+                               return -ETIMEDOUT;
+               } else {
+                       do {
+                               usleep_range(1000, 5000);
+
+                               ret = regmap_read(regmap, RM3100_REG_STATUS,
+                                                 &val);
+                               if (ret < 0)
+                                       return ret;
+
+                               if (val & RM3100_STATUS_DRDY)
+                                       break;
+                       } while (--tries);
+                       if (!tries)
+                               return -ETIMEDOUT;
+               }
+       }
+       return 0;
+}
+
+static int rm3100_read_mag(struct rm3100_data *data, int idx, int *val)
+{
+       struct regmap *regmap = data->regmap;
+       u8 buffer[3];
+       int ret;
+
+       mutex_lock(&data->lock);
+       ret = regmap_write(regmap, RM3100_REG_POLL, BIT(4 + idx));
+       if (ret < 0)
+               goto unlock_return;
+
+       ret = rm3100_wait_measurement(data);
+       if (ret < 0)
+               goto unlock_return;
+
+       ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * idx, buffer, 3);
+       if (ret < 0)
+               goto unlock_return;
+       mutex_unlock(&data->lock);
+
+       *val = sign_extend32((buffer[0] << 16) | (buffer[1] << 8) | buffer[2],
+                            23);
+
+       return IIO_VAL_INT;
+
+unlock_return:
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+#define RM3100_CHANNEL(axis, idx)                                      \
+       {                                                               \
+               .type = IIO_MAGN,                                       \
+               .modified = 1,                                          \
+               .channel2 = IIO_MOD_##axis,                             \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |  \
+                       BIT(IIO_CHAN_INFO_SAMP_FREQ),                   \
+               .scan_index = idx,                                      \
+               .scan_type = {                                          \
+                       .sign = 's',                                    \
+                       .realbits = 24,                                 \
+                       .storagebits = 32,                              \
+                       .shift = 8,                                     \
+                       .endianness = IIO_BE,                           \
+               },                                                      \
+       }
+
+static const struct iio_chan_spec rm3100_channels[] = {
+       RM3100_CHANNEL(X, 0),
+       RM3100_CHANNEL(Y, 1),
+       RM3100_CHANNEL(Z, 2),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+       "600 300 150 75 37 18 9 4.5 2.3 1.2 0.6 0.3 0.015 0.075"
+);
+
+static struct attribute *rm3100_attributes[] = {
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group rm3100_attribute_group = {
+       .attrs = rm3100_attributes,
+};
+
+#define RM3100_SAMP_NUM                        14
+
+/*
+ * Frequency : rm3100_samp_rates[][0].rm3100_samp_rates[][1]Hz.
+ * Time between reading: rm3100_sam_rates[][2]ms.
+ * The first one is actually 1.7ms.
+ */
+static const int rm3100_samp_rates[RM3100_SAMP_NUM][3] = {
+       {600, 0, 2}, {300, 0, 3}, {150, 0, 7}, {75, 0, 13}, {37, 0, 27},
+       {18, 0, 55}, {9, 0, 110}, {4, 500000, 220}, {2, 300000, 440},
+       {1, 200000, 800}, {0, 600000, 1600}, {0, 300000, 3300},
+       {0, 15000, 6700},  {0, 75000, 13000}
+};
+
+static int rm3100_get_samp_freq(struct rm3100_data *data, int *val, int *val2)
+{
+       unsigned int tmp;
+       int ret;
+
+       mutex_lock(&data->lock);
+       ret = regmap_read(data->regmap, RM3100_REG_TMRC, &tmp);
+       mutex_unlock(&data->lock);
+       if (ret < 0)
+               return ret;
+       *val = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][0];
+       *val2 = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][1];
+
+       return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int rm3100_set_cycle_count(struct rm3100_data *data, int val)
+{
+       int ret;
+       u8 i;
+
+       for (i = 0; i < 3; i++) {
+               ret = regmap_write(data->regmap, RM3100_REG_CC_X + 2 * i, val);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /*
+        * The scale of this sensor depends on the cycle count value, these
+        * three values are corresponding to the cycle count value 50, 100,
+        * 200. scale = output / gain * 10^4.
+        */
+       switch (val) {
+       case 50:
+               data->scale = 500;
+               break;
+       case 100:
+               data->scale = 263;
+               break;
+       /*
+        * case 200:
+        * This function will never be called by users' code, so here we
+        * assume that it will never get a wrong parameter.
+        */
+       default:
+               data->scale = 133;
+       }
+
+       return 0;
+}
+
+static int rm3100_set_samp_freq(struct iio_dev *indio_dev, int val, int val2)
+{
+       struct rm3100_data *data = iio_priv(indio_dev);
+       struct regmap *regmap = data->regmap;
+       unsigned int cycle_count;
+       int ret;
+       int i;
+
+       mutex_lock(&data->lock);
+       /* All cycle count registers use the same value. */
+       ret = regmap_read(regmap, RM3100_REG_CC_X, &cycle_count);
+       if (ret < 0)
+               goto unlock_return;
+
+       for (i = 0; i < RM3100_SAMP_NUM; i++) {
+               if (val == rm3100_samp_rates[i][0] &&
+                   val2 == rm3100_samp_rates[i][1])
+                       break;
+       }
+       if (i == RM3100_SAMP_NUM) {
+               ret = -EINVAL;
+               goto unlock_return;
+       }
+
+       ret = regmap_write(regmap, RM3100_REG_TMRC, i + RM3100_TMRC_OFFSET);
+       if (ret < 0)
+               goto unlock_return;
+
+       /* Checking if cycle count registers need changing. */
+       if (val == 600 && cycle_count == 200) {
+               ret = rm3100_set_cycle_count(data, 100);
+               if (ret < 0)
+                       goto unlock_return;
+       } else if (val != 600 && cycle_count == 100) {
+               ret = rm3100_set_cycle_count(data, 200);
+               if (ret < 0)
+                       goto unlock_return;
+       }
+
+       if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
+               /* Writing TMRC registers requires CMM reset. */
+               ret = regmap_write(regmap, RM3100_REG_CMM, 0);
+               if (ret < 0)
+                       goto unlock_return;
+               ret = regmap_write(data->regmap, RM3100_REG_CMM,
+                       (*indio_dev->active_scan_mask & 0x7) <<
+                       RM3100_CMM_AXIS_SHIFT | RM3100_CMM_START);
+               if (ret < 0)
+                       goto unlock_return;
+       }
+       mutex_unlock(&data->lock);
+
+       data->conversion_time = rm3100_samp_rates[i][2] * 2;
+       return 0;
+
+unlock_return:
+       mutex_unlock(&data->lock);
+       return ret;
+}
+
+static int rm3100_read_raw(struct iio_dev *indio_dev,
+                          const struct iio_chan_spec *chan,
+                          int *val, int *val2, long mask)
+{
+       struct rm3100_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret < 0)
+                       return ret;
+
+               ret = rm3100_read_mag(data, chan->scan_index, val);
+               iio_device_release_direct_mode(indio_dev);
+
+               return ret;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = data->scale;
+
+               return IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return rm3100_get_samp_freq(data, val, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int rm3100_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int val, int val2, long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               return rm3100_set_samp_freq(indio_dev, val, val2);
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info rm3100_info = {
+       .attrs = &rm3100_attribute_group,
+       .read_raw = rm3100_read_raw,
+       .write_raw = rm3100_write_raw,
+};
+
+static int rm3100_buffer_preenable(struct iio_dev *indio_dev)
+{
+       struct rm3100_data *data = iio_priv(indio_dev);
+
+       /* Starting channels enabled. */
+       return regmap_write(data->regmap, RM3100_REG_CMM,
+               (*indio_dev->active_scan_mask & 0x7) << RM3100_CMM_AXIS_SHIFT |
+               RM3100_CMM_START);
+}
+
+static int rm3100_buffer_postdisable(struct iio_dev *indio_dev)
+{
+       struct rm3100_data *data = iio_priv(indio_dev);
+
+       return regmap_write(data->regmap, RM3100_REG_CMM, 0);
+}
+
+static const struct iio_buffer_setup_ops rm3100_buffer_ops = {
+       .preenable = rm3100_buffer_preenable,
+       .postenable = iio_triggered_buffer_postenable,
+       .predisable = iio_triggered_buffer_predisable,
+       .postdisable = rm3100_buffer_postdisable,
+};
+
+static irqreturn_t rm3100_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       unsigned long scan_mask = *indio_dev->active_scan_mask;
+       unsigned int mask_len = indio_dev->masklength;
+       struct rm3100_data *data = iio_priv(indio_dev);
+       struct regmap *regmap = data->regmap;
+       int ret, i, bit;
+
+       mutex_lock(&data->lock);
+       switch (scan_mask) {
+       case BIT(0) | BIT(1) | BIT(2):
+               ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       goto done;
+               /* Convert XXXYYYZZZxxx to XXXxYYYxZZZx. x for paddings. */
+               for (i = 2; i > 0; i--)
+                       memmove(data->buffer + i * 4, data->buffer + i * 3, 3);
+               break;
+       case BIT(0) | BIT(1):
+               ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 6);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       goto done;
+               memmove(data->buffer + 4, data->buffer + 3, 3);
+               break;
+       case BIT(1) | BIT(2):
+               ret = regmap_bulk_read(regmap, RM3100_REG_MY2, data->buffer, 6);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       goto done;
+               memmove(data->buffer + 4, data->buffer + 3, 3);
+               break;
+       case BIT(0) | BIT(2):
+               ret = regmap_bulk_read(regmap, RM3100_REG_MX2, data->buffer, 9);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       goto done;
+               memmove(data->buffer + 4, data->buffer + 6, 3);
+               break;
+       default:
+               for_each_set_bit(bit, &scan_mask, mask_len) {
+                       ret = regmap_bulk_read(regmap, RM3100_REG_MX2 + 3 * bit,
+                                              data->buffer, 3);
+                       if (ret < 0) {
+                               mutex_unlock(&data->lock);
+                               goto done;
+                       }
+               }
+               mutex_unlock(&data->lock);
+       }
+       /*
+        * Always using the same buffer so that we wouldn't need to set the
+        * paddings to 0 in case of leaking any data.
+        */
+       iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+                                          pf->timestamp);
+done:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq)
+{
+       struct iio_dev *indio_dev;
+       struct rm3100_data *data;
+       unsigned int tmp;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       data = iio_priv(indio_dev);
+       data->regmap = regmap;
+
+       mutex_init(&data->lock);
+
+       indio_dev->dev.parent = dev;
+       indio_dev->name = "rm3100";
+       indio_dev->info = &rm3100_info;
+       indio_dev->channels = rm3100_channels;
+       indio_dev->num_channels = ARRAY_SIZE(rm3100_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED;
+       indio_dev->currentmode = INDIO_DIRECT_MODE;
+
+       if (!irq)
+               data->use_interrupt = false;
+       else {
+               data->use_interrupt = true;
+
+               init_completion(&data->measuring_done);
+               ret = devm_request_threaded_irq(dev,
+                                               irq,
+                                               rm3100_irq_handler,
+                                               rm3100_thread_fn,
+                                               IRQF_TRIGGER_HIGH |
+                                               IRQF_ONESHOT,
+                                               indio_dev->name,
+                                               indio_dev);
+               if (ret < 0) {
+                       dev_err(dev, "request irq line failed.\n");
+                       return ret;
+               }
+
+               data->drdy_trig = devm_iio_trigger_alloc(dev, "%s-drdy%d",
+                                                        indio_dev->name,
+                                                        indio_dev->id);
+               if (!data->drdy_trig)
+                       return -ENOMEM;
+
+               data->drdy_trig->dev.parent = dev;
+               ret = devm_iio_trigger_register(dev, data->drdy_trig);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+                                             &iio_pollfunc_store_time,
+                                             rm3100_trigger_handler,
+                                             &rm3100_buffer_ops);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(regmap, RM3100_REG_TMRC, &tmp);
+       if (ret < 0)
+               return ret;
+       /* Initializing max wait time, which is double conversion time. */
+       data->conversion_time = rm3100_samp_rates[tmp - RM3100_TMRC_OFFSET][2]
+                               * 2;
+
+       /* Cycle count values may not be what we want. */
+       if ((tmp - RM3100_TMRC_OFFSET) == 0)
+               rm3100_set_cycle_count(data, 100);
+       else
+               rm3100_set_cycle_count(data, 200);
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_GPL(rm3100_common_probe);
+
+MODULE_AUTHOR("Song Qiang <songqiang1304521@gmail.com>");
+MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/rm3100-i2c.c b/drivers/iio/magnetometer/rm3100-i2c.c
new file mode 100644 (file)
index 0000000..1ac622c
--- /dev/null
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for PNI RM3100 3-axis geomagnetic sensor on a i2c bus.
+ *
+ * Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
+ *
+ * i2c slave address: 0x20 + SA1 << 1 + SA0.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+
+#include "rm3100.h"
+
+static const struct regmap_config rm3100_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .rd_table = &rm3100_readable_table,
+       .wr_table = &rm3100_writable_table,
+       .volatile_table = &rm3100_volatile_table,
+
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int rm3100_probe(struct i2c_client *client)
+{
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_i2c(client, &rm3100_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return rm3100_common_probe(&client->dev, regmap, client->irq);
+}
+
+static const struct of_device_id rm3100_dt_match[] = {
+       { .compatible = "pni,rm3100", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rm3100_dt_match);
+
+static struct i2c_driver rm3100_driver = {
+       .driver = {
+               .name = "rm3100-i2c",
+               .of_match_table = rm3100_dt_match,
+       },
+       .probe_new = rm3100_probe,
+};
+module_i2c_driver(rm3100_driver);
+
+MODULE_AUTHOR("Song Qiang <songqiang1304521@gmail.com>");
+MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/rm3100-spi.c b/drivers/iio/magnetometer/rm3100-spi.c
new file mode 100644 (file)
index 0000000..65d5eb9
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for PNI RM3100 3-axis geomagnetic sensor on a spi bus.
+ *
+ * Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "rm3100.h"
+
+static const struct regmap_config rm3100_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .rd_table = &rm3100_readable_table,
+       .wr_table = &rm3100_writable_table,
+       .volatile_table = &rm3100_volatile_table,
+
+       .read_flag_mask = 0x80,
+
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int rm3100_probe(struct spi_device *spi)
+{
+       struct regmap *regmap;
+       int ret;
+
+       /* Actually this device supports both mode 0 and mode 3. */
+       spi->mode = SPI_MODE_0;
+       /* Data rates cannot exceed 1Mbits. */
+       spi->max_speed_hz = 1000000;
+       spi->bits_per_word = 8;
+       ret = spi_setup(spi);
+       if (ret)
+               return ret;
+
+       regmap = devm_regmap_init_spi(spi, &rm3100_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return rm3100_common_probe(&spi->dev, regmap, spi->irq);
+}
+
+static const struct of_device_id rm3100_dt_match[] = {
+       { .compatible = "pni,rm3100", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rm3100_dt_match);
+
+static struct spi_driver rm3100_driver = {
+       .driver = {
+               .name = "rm3100-spi",
+               .of_match_table = rm3100_dt_match,
+       },
+       .probe = rm3100_probe,
+};
+module_spi_driver(rm3100_driver);
+
+MODULE_AUTHOR("Song Qiang <songqiang1304521@gmail.com>");
+MODULE_DESCRIPTION("PNI RM3100 3-axis magnetometer spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/magnetometer/rm3100.h b/drivers/iio/magnetometer/rm3100.h
new file mode 100644 (file)
index 0000000..c350821
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Song Qiang <songqiang1304521@gmail.com>
+ */
+
+#ifndef RM3100_CORE_H
+#define RM3100_CORE_H
+
+#include <linux/regmap.h>
+
+extern const struct regmap_access_table rm3100_readable_table;
+extern const struct regmap_access_table rm3100_writable_table;
+extern const struct regmap_access_table rm3100_volatile_table;
+
+int rm3100_common_probe(struct device *dev, struct regmap *regmap, int irq);
+
+#endif /* RM3100_CORE_H */
index 8fe51ce427bd64f3e98f06062767dd100209f024..bc14ad4f1b262c4d9f2273db04f716415fc2ed55 100644 (file)
@@ -20,6 +20,7 @@
 #define LIS3MDL_MAGN_DEV_NAME          "lis3mdl"
 #define LSM303AGR_MAGN_DEV_NAME                "lsm303agr_magn"
 #define LIS2MDL_MAGN_DEV_NAME          "lis2mdl"
+#define LSM9DS1_MAGN_DEV_NAME          "lsm9ds1_magn"
 
 int st_magn_common_probe(struct iio_dev *indio_dev);
 void st_magn_common_remove(struct iio_dev *indio_dev);
index 72f6d1335a04d363c030a3167e3032794b05f888..5d056bdb3b376c7d3c8b3c179c8269042e0e642b 100644 (file)
@@ -29,9 +29,9 @@
 #define ST_MAGN_NUMBER_DATA_CHANNELS           3
 
 /* DEFAULT VALUE FOR SENSORS */
-#define ST_MAGN_DEFAULT_OUT_X_H_ADDR           0X03
-#define ST_MAGN_DEFAULT_OUT_Y_H_ADDR           0X07
-#define ST_MAGN_DEFAULT_OUT_Z_H_ADDR           0X05
+#define ST_MAGN_DEFAULT_OUT_X_H_ADDR           0x03
+#define ST_MAGN_DEFAULT_OUT_Y_H_ADDR           0x07
+#define ST_MAGN_DEFAULT_OUT_Z_H_ADDR           0x05
 
 /* FULLSCALE */
 #define ST_MAGN_FS_AVL_1300MG                  1300
@@ -267,6 +267,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
                .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
                .sensors_supported = {
                        [0] = LIS3MDL_MAGN_DEV_NAME,
+                       [1] = LSM9DS1_MAGN_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_magn_2_16bit_channels,
                .odr = {
@@ -315,6 +316,10 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
                                },
                        },
                },
+               .bdu = {
+                       .addr = 0x24,
+                       .mask = 0x40,
+               },
                .drdy_irq = {
                        /* drdy line is routed drdy pin */
                        .stat_drdy = {
index feaa28cf6a779fbe8c0cc1c80842c0afd7c615a5..68650f5f5c19b20eb0bfd758f87a55501e71e953 100644 (file)
@@ -44,6 +44,10 @@ static const struct of_device_id st_magn_of_match[] = {
                .compatible = "st,lis2mdl",
                .data = LIS2MDL_MAGN_DEV_NAME,
        },
+       {
+               .compatible = "st,lsm9ds1-magn",
+               .data = LSM9DS1_MAGN_DEV_NAME,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -90,6 +94,7 @@ static const struct i2c_device_id st_magn_id_table[] = {
        { LIS3MDL_MAGN_DEV_NAME },
        { LSM303AGR_MAGN_DEV_NAME },
        { LIS2MDL_MAGN_DEV_NAME },
+       { LSM9DS1_MAGN_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_magn_id_table);
index 7b7cd08fcc32cf21de2a5c6a1e49d388daa3d14b..cb05fcd9ddfe2cfa872ee64fea65538d7c898610 100644 (file)
@@ -23,6 +23,8 @@
  * For new single-chip sensors use <device_name> as compatible string.
  * For old single-chip devices keep <device_name>-magn to maintain
  * compatibility
+ * For multi-chip devices, use <device_name>-magn to distinguish which
+ * capability is being used
  */
 static const struct of_device_id st_magn_of_match[] = {
        {
@@ -37,6 +39,10 @@ static const struct of_device_id st_magn_of_match[] = {
                .compatible = "st,lis2mdl",
                .data = LIS2MDL_MAGN_DEV_NAME,
        },
+       {
+               .compatible = "st,lsm9ds1-magn",
+               .data = LSM9DS1_MAGN_DEV_NAME,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, st_magn_of_match);
@@ -79,6 +85,7 @@ static const struct spi_device_id st_magn_id_table[] = {
        { LIS3MDL_MAGN_DEV_NAME },
        { LSM303AGR_MAGN_DEV_NAME },
        { LIS2MDL_MAGN_DEV_NAME },
+       { LSM9DS1_MAGN_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_magn_id_table);
index b3e30db246cc0d0aceb656e2d1fce405378316f3..efe035ce010de788f80322cf9c63d4bbfb89dbfd 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/spi/spi.h>
 
 #define MCP4131_WRITE          (0x00 << 2)
@@ -243,7 +244,7 @@ static int mcp4131_probe(struct spi_device *spi)
 {
        int err;
        struct device *dev = &spi->dev;
-       unsigned long devid = spi_get_device_id(spi)->driver_data;
+       unsigned long devid;
        struct mcp4131_data *data;
        struct iio_dev *indio_dev;
 
@@ -254,7 +255,11 @@ static int mcp4131_probe(struct spi_device *spi)
        data = iio_priv(indio_dev);
        spi_set_drvdata(spi, indio_dev);
        data->spi = spi;
-       data->cfg = &mcp4131_cfg[devid];
+       data->cfg = of_device_get_match_data(&spi->dev);
+       if (!data->cfg) {
+               devid = spi_get_device_id(spi)->driver_data;
+               data->cfg = &mcp4131_cfg[devid];
+       }
 
        mutex_init(&data->lock);
 
@@ -273,7 +278,6 @@ static int mcp4131_probe(struct spi_device *spi)
        return 0;
 }
 
-#if defined(CONFIG_OF)
 static const struct of_device_id mcp4131_dt_ids[] = {
        { .compatible = "microchip,mcp4131-502",
                .data = &mcp4131_cfg[MCP413x_502] },
@@ -406,7 +410,6 @@ static const struct of_device_id mcp4131_dt_ids[] = {
        {}
 };
 MODULE_DEVICE_TABLE(of, mcp4131_dt_ids);
-#endif /* CONFIG_OF */
 
 static const struct spi_device_id mcp4131_id[] = {
        { "mcp4131-502", MCP413x_502 },
index ca1cce58fe2036586892beccd5932aa621659736..a0a07e47f13f278b055ffcf8b1a0cc3a2bcf1f88 100644 (file)
@@ -15,7 +15,7 @@
 
 struct tpl0102_cfg {
        int wipers;
-       int max_pos;
+       int avail[3];
        int kohms;
 };
 
@@ -28,16 +28,16 @@ enum tpl0102_type {
 
 static const struct tpl0102_cfg tpl0102_cfg[] = {
        /* on-semiconductor parts */
-       [CAT5140_503] = { .wipers = 1, .max_pos = 256, .kohms = 50, },
-       [CAT5140_104] = { .wipers = 1, .max_pos = 256, .kohms = 100, },
+       [CAT5140_503] = { .wipers = 1, .avail = { 0, 1, 255 }, .kohms = 50, },
+       [CAT5140_104] = { .wipers = 1, .avail = { 0, 1, 255 }, .kohms = 100, },
        /* ti parts */
-       [TPL0102_104] = { .wipers = 2, .max_pos = 256, .kohms = 100 },
-       [TPL0401_103] = { .wipers = 1, .max_pos = 128, .kohms = 10, },
+       [TPL0102_104] = { .wipers = 2, .avail = { 0, 1, 255 }, .kohms = 100 },
+       [TPL0401_103] = { .wipers = 1, .avail = { 0, 1, 127 }, .kohms = 10, },
 };
 
 struct tpl0102_data {
        struct regmap *regmap;
-       unsigned long devid;
+       const struct tpl0102_cfg *cfg;
 };
 
 static const struct regmap_config tpl0102_regmap_config = {
@@ -52,6 +52,7 @@ static const struct regmap_config tpl0102_regmap_config = {
        .channel = (ch),                                        \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+       .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), \
 }
 
 static const struct iio_chan_spec tpl0102_channels[] = {
@@ -72,14 +73,32 @@ static int tpl0102_read_raw(struct iio_dev *indio_dev,
                return ret ? ret : IIO_VAL_INT;
        }
        case IIO_CHAN_INFO_SCALE:
-               *val = 1000 * tpl0102_cfg[data->devid].kohms;
-               *val2 = tpl0102_cfg[data->devid].max_pos;
+               *val = 1000 * data->cfg->kohms;
+               *val2 = data->cfg->avail[2] + 1;
                return IIO_VAL_FRACTIONAL;
        }
 
        return -EINVAL;
 }
 
+static int tpl0102_read_avail(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             const int **vals, int *type, int *length,
+                             long mask)
+{
+       struct tpl0102_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               *length = ARRAY_SIZE(data->cfg->avail);
+               *vals = data->cfg->avail;
+               *type = IIO_VAL_INT;
+               return IIO_AVAIL_RANGE;
+       }
+
+       return -EINVAL;
+}
+
 static int tpl0102_write_raw(struct iio_dev *indio_dev,
                             struct iio_chan_spec const *chan,
                             int val, int val2, long mask)
@@ -89,7 +108,7 @@ static int tpl0102_write_raw(struct iio_dev *indio_dev,
        if (mask != IIO_CHAN_INFO_RAW)
                return -EINVAL;
 
-       if (val >= tpl0102_cfg[data->devid].max_pos || val < 0)
+       if (val > data->cfg->avail[2] || val < 0)
                return -EINVAL;
 
        return regmap_write(data->regmap, chan->channel, val);
@@ -97,6 +116,7 @@ static int tpl0102_write_raw(struct iio_dev *indio_dev,
 
 static const struct iio_info tpl0102_info = {
        .read_raw = tpl0102_read_raw,
+       .read_avail = tpl0102_read_avail,
        .write_raw = tpl0102_write_raw,
 };
 
@@ -113,7 +133,7 @@ static int tpl0102_probe(struct i2c_client *client,
        data = iio_priv(indio_dev);
        i2c_set_clientdata(client, indio_dev);
 
-       data->devid = id->driver_data;
+       data->cfg = &tpl0102_cfg[id->driver_data];
        data->regmap = devm_regmap_init_i2c(client, &tpl0102_regmap_config);
        if (IS_ERR(data->regmap)) {
                dev_err(dev, "regmap initialization failed\n");
@@ -123,7 +143,7 @@ static int tpl0102_probe(struct i2c_client *client,
        indio_dev->dev.parent = dev;
        indio_dev->info = &tpl0102_info;
        indio_dev->channels = tpl0102_channels;
-       indio_dev->num_channels = tpl0102_cfg[data->devid].wipers;
+       indio_dev->num_channels = data->cfg->wipers;
        indio_dev->name = client->name;
 
        return devm_iio_device_register(dev, indio_dev);
index 9d3062a0746059141144b4239a377e77d253868a..fc23059f1673148d3c26a2b35d9f9f62145ba3c8 100644 (file)
@@ -73,6 +73,7 @@ config AD7192
 config AD7280
        tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System"
        depends on SPI
+       select CRC8
        help
          Say yes here to build support for Analog Devices AD7280A
          Lithium Ion Battery Monitoring System.
index 58420dcb406d9fb85cf54032e8baf14da5baf754..0bb9ab174f2ac0a0824b5a5d4543f5bf8c3df5ce 100644 (file)
@@ -6,6 +6,7 @@
  * Licensed under the GPL-2.
  */
 
+#include <linux/crc8.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -121,8 +122,6 @@ static unsigned int ad7280a_devaddr(unsigned int addr)
  * P(x) = x^8 + x^5 + x^3 + x^2 + x^1 + x^0 = 0b100101111 => 0x2F
  */
 #define POLYNOM                0x2F
-#define POLYNOM_ORDER  8
-#define HIGHBIT                (1 << (POLYNOM_ORDER - 1))
 
 struct ad7280_state {
        struct spi_device               *spi;
@@ -131,7 +130,7 @@ struct ad7280_state {
        int                             slave_num;
        int                             scan_cnt;
        int                             readback_delay_us;
-       unsigned char                   crc_tab[256];
+       unsigned char                   crc_tab[CRC8_TABLE_SIZE];
        unsigned char                   ctrl_hb;
        unsigned char                   ctrl_lb;
        unsigned char                   cell_threshhigh;
@@ -144,23 +143,6 @@ struct ad7280_state {
        __be32                          buf[2] ____cacheline_aligned;
 };
 
-static void ad7280_crc8_build_table(unsigned char *crc_tab)
-{
-       unsigned char bit, crc;
-       int cnt, i;
-
-       for (cnt = 0; cnt < 256; cnt++) {
-               crc = cnt;
-               for (i = 0; i < 8; i++) {
-                       bit = crc & HIGHBIT;
-                       crc <<= 1;
-                       if (bit)
-                               crc ^= POLYNOM;
-               }
-               crc_tab[cnt] = crc;
-       }
-}
-
 static unsigned char ad7280_calc_crc8(unsigned char *crc_tab, unsigned int val)
 {
        unsigned char crc;
@@ -256,7 +238,9 @@ static int ad7280_read(struct ad7280_state *st, unsigned int devaddr,
        if (ret)
                return ret;
 
-       __ad7280_read32(st, &tmp);
+       ret = __ad7280_read32(st, &tmp);
+       if (ret)
+               return ret;
 
        if (ad7280_check_crc(st, tmp))
                return -EIO;
@@ -294,7 +278,9 @@ static int ad7280_read_channel(struct ad7280_state *st, unsigned int devaddr,
 
        ad7280_delay(st);
 
-       __ad7280_read32(st, &tmp);
+       ret = __ad7280_read32(st, &tmp);
+       if (ret)
+               return ret;
 
        if (ad7280_check_crc(st, tmp))
                return -EIO;
@@ -327,7 +313,9 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt,
        ad7280_delay(st);
 
        for (i = 0; i < cnt; i++) {
-               __ad7280_read32(st, &tmp);
+               ret = __ad7280_read32(st, &tmp);
+               if (ret)
+                       return ret;
 
                if (ad7280_check_crc(st, tmp))
                        return -EIO;
@@ -342,6 +330,14 @@ static int ad7280_read_all_channels(struct ad7280_state *st, unsigned int cnt,
        return sum;
 }
 
+static void ad7280_sw_power_down(void *data)
+{
+       struct ad7280_state *st = data;
+
+       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
+                    AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb);
+}
+
 static int ad7280_chain_setup(struct ad7280_state *st)
 {
        unsigned int val, n;
@@ -362,26 +358,38 @@ static int ad7280_chain_setup(struct ad7280_state *st)
                           AD7280A_CTRL_LB_MUST_SET |
                           st->ctrl_lb);
        if (ret)
-               return ret;
+               goto error_power_down;
 
        ret = ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_READ, 1,
                           AD7280A_CONTROL_LB << 2);
        if (ret)
-               return ret;
+               goto error_power_down;
 
        for (n = 0; n <= AD7280A_MAX_CHAIN; n++) {
-               __ad7280_read32(st, &val);
+               ret = __ad7280_read32(st, &val);
+               if (ret)
+                       goto error_power_down;
+
                if (val == 0)
                        return n - 1;
 
-               if (ad7280_check_crc(st, val))
-                       return -EIO;
+               if (ad7280_check_crc(st, val)) {
+                       ret = -EIO;
+                       goto error_power_down;
+               }
 
-               if (n != ad7280a_devaddr(val >> 27))
-                       return -EIO;
+               if (n != ad7280a_devaddr(val >> 27)) {
+                       ret = -EIO;
+                       goto error_power_down;
+               }
        }
+       ret = -EFAULT;
 
-       return -EFAULT;
+error_power_down:
+       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
+                    AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb);
+
+       return ret;
 }
 
 static ssize_t ad7280_show_balance_sw(struct device *dev,
@@ -492,8 +500,8 @@ static int ad7280_channel_init(struct ad7280_state *st)
 {
        int dev, ch, cnt;
 
-       st->channels = kcalloc((st->slave_num + 1) * 12 + 2,
-                              sizeof(*st->channels), GFP_KERNEL);
+       st->channels = devm_kcalloc(&st->spi->dev, (st->slave_num + 1) * 12 + 2,
+                                   sizeof(*st->channels), GFP_KERNEL);
        if (!st->channels)
                return -ENOMEM;
 
@@ -552,16 +560,18 @@ static int ad7280_channel_init(struct ad7280_state *st)
 static int ad7280_attr_init(struct ad7280_state *st)
 {
        int dev, ch, cnt;
+       unsigned int index;
 
-       st->iio_attr = kcalloc(2, sizeof(*st->iio_attr) *
-                              (st->slave_num + 1) * AD7280A_CELLS_PER_DEV,
-                              GFP_KERNEL);
+       st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) *
+                                   (st->slave_num + 1) * AD7280A_CELLS_PER_DEV,
+                                   GFP_KERNEL);
        if (!st->iio_attr)
                return -ENOMEM;
 
        for (dev = 0, cnt = 0; dev <= st->slave_num; dev++)
                for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6;
                        ch++, cnt++) {
+                       index = dev * AD7280A_CELLS_PER_DEV + ch;
                        st->iio_attr[cnt].address =
                                ad7280a_devaddr(dev) << 8 | ch;
                        st->iio_attr[cnt].dev_attr.attr.mode =
@@ -571,10 +581,9 @@ static int ad7280_attr_init(struct ad7280_state *st)
                        st->iio_attr[cnt].dev_attr.store =
                                ad7280_store_balance_sw;
                        st->iio_attr[cnt].dev_attr.attr.name =
-                               kasprintf(GFP_KERNEL,
-                                         "in%d-in%d_balance_switch_en",
-                                         dev * AD7280A_CELLS_PER_DEV + ch,
-                                         dev * AD7280A_CELLS_PER_DEV + ch + 1);
+                               devm_kasprintf(&st->spi->dev, GFP_KERNEL,
+                                              "in%d-in%d_balance_switch_en",
+                                              index, index + 1);
                        ad7280_attributes[cnt] =
                                &st->iio_attr[cnt].dev_attr.attr;
                        cnt++;
@@ -588,10 +597,9 @@ static int ad7280_attr_init(struct ad7280_state *st)
                        st->iio_attr[cnt].dev_attr.store =
                                ad7280_store_balance_timer;
                        st->iio_attr[cnt].dev_attr.attr.name =
-                               kasprintf(GFP_KERNEL,
-                                         "in%d-in%d_balance_timer",
-                                         dev * AD7280A_CELLS_PER_DEV + ch,
-                                         dev * AD7280A_CELLS_PER_DEV + ch + 1);
+                               devm_kasprintf(&st->spi->dev, GFP_KERNEL,
+                                              "in%d-in%d_balance_timer",
+                                              index, index + 1);
                        ad7280_attributes[cnt] =
                                &st->iio_attr[cnt].dev_attr.attr;
                }
@@ -610,7 +618,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev,
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        unsigned int val;
 
-       switch ((u32)this_attr->address) {
+       switch (this_attr->address) {
        case AD7280A_CELL_OVERVOLTAGE:
                val = 1000 + (st->cell_threshhigh * 1568) / 100;
                break;
@@ -646,7 +654,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev,
        if (ret)
                return ret;
 
-       switch ((u32)this_attr->address) {
+       switch (this_attr->address) {
        case AD7280A_CELL_OVERVOLTAGE:
        case AD7280A_CELL_UNDERVOLTAGE:
                val = ((val - 1000) * 100) / 1568; /* LSB 15.68mV */
@@ -662,7 +670,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev,
        val = clamp(val, 0L, 0xFFL);
 
        mutex_lock(&st->lock);
-       switch ((u32)this_attr->address) {
+       switch (this_attr->address) {
        case AD7280A_CELL_OVERVOLTAGE:
                st->cell_threshhigh = val;
                break;
@@ -857,7 +865,7 @@ static int ad7280_probe(struct spi_device *spi)
        if (!pdata)
                pdata = &ad7793_default_pdata;
 
-       ad7280_crc8_build_table(st->crc_tab);
+       crc8_populate_msb(st->crc_tab, POLYNOM);
 
        st->spi->max_speed_hz = AD7280A_MAX_SPI_CLK_HZ;
        st->spi->mode = SPI_MODE_1;
@@ -872,6 +880,10 @@ static int ad7280_probe(struct spi_device *spi)
        if (ret < 0)
                return ret;
 
+       ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st);
+       if (ret)
+               return ret;
+
        st->slave_num = ret;
        st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH;
        st->cell_threshhigh = 0xFF;
@@ -909,65 +921,37 @@ static int ad7280_probe(struct spi_device *spi)
 
        ret = ad7280_attr_init(st);
        if (ret < 0)
-               goto error_free_channels;
+               return ret;
 
-       ret = iio_device_register(indio_dev);
+       ret = devm_iio_device_register(&spi->dev, indio_dev);
        if (ret)
-               goto error_free_attr;
+               return ret;
 
        if (spi->irq > 0) {
                ret = ad7280_write(st, AD7280A_DEVADDR_MASTER,
                                   AD7280A_ALERT, 1,
                                   AD7280A_ALERT_RELAY_SIG_CHAIN_DOWN);
                if (ret)
-                       goto error_unregister;
+                       return ret;
 
                ret = ad7280_write(st, ad7280a_devaddr(st->slave_num),
                                   AD7280A_ALERT, 0,
                                   AD7280A_ALERT_GEN_STATIC_HIGH |
                                   (pdata->chain_last_alert_ignore & 0xF));
                if (ret)
-                       goto error_unregister;
-
-               ret = request_threaded_irq(spi->irq,
-                                          NULL,
-                                          ad7280_event_handler,
-                                          IRQF_TRIGGER_FALLING |
-                                          IRQF_ONESHOT,
-                                          indio_dev->name,
-                                          indio_dev);
+                       return ret;
+
+               ret = devm_request_threaded_irq(&spi->dev, spi->irq,
+                                               NULL,
+                                               ad7280_event_handler,
+                                               IRQF_TRIGGER_FALLING |
+                                               IRQF_ONESHOT,
+                                               indio_dev->name,
+                                               indio_dev);
                if (ret)
-                       goto error_unregister;
+                       return ret;
        }
 
-       return 0;
-error_unregister:
-       iio_device_unregister(indio_dev);
-
-error_free_attr:
-       kfree(st->iio_attr);
-
-error_free_channels:
-       kfree(st->channels);
-
-       return ret;
-}
-
-static int ad7280_remove(struct spi_device *spi)
-{
-       struct iio_dev *indio_dev = spi_get_drvdata(spi);
-       struct ad7280_state *st = iio_priv(indio_dev);
-
-       if (spi->irq > 0)
-               free_irq(spi->irq, indio_dev);
-       iio_device_unregister(indio_dev);
-
-       ad7280_write(st, AD7280A_DEVADDR_MASTER, AD7280A_CONTROL_HB, 1,
-                    AD7280A_CTRL_HB_PWRDN_SW | st->ctrl_hb);
-
-       kfree(st->channels);
-       kfree(st->iio_attr);
-
        return 0;
 }
 
@@ -982,7 +966,6 @@ static struct spi_driver ad7280_driver = {
                .name   = "ad7280",
        },
        .probe          = ad7280_probe,
-       .remove         = ad7280_remove,
        .id_table       = ad7280_id,
 };
 module_spi_driver(ad7280_driver);
index 048c205b979ecbceb5a325e60d478d7c3c1561fb..7308fa8fbb4cab4991ca73dd5062a83359bc26f1 100644 (file)
@@ -374,7 +374,7 @@ static int ad7606_request_gpios(struct ad7606_state *st)
                return 0;
 
        st->gpio_os = devm_gpiod_get_array_optional(dev, "oversampling-ratio",
-                       GPIOD_OUT_LOW);
+                                                   GPIOD_OUT_LOW);
        return PTR_ERR_OR_ZERO(st->gpio_os);
 }
 
index b67412db0318a5a312a4993b31209568156f7f83..c4a85789c2db6bb7af680c427dbbdba3dfb1847b 100644 (file)
 #include <linux/iio/sysfs.h>
 #include <linux/iio/adc/ad_sigma_delta.h>
 
-#define AD7780_RDY     BIT(7)
-#define AD7780_FILTER  BIT(6)
-#define AD7780_ERR     BIT(5)
-#define AD7780_ID1     BIT(4)
-#define AD7780_ID0     BIT(3)
-#define AD7780_GAIN    BIT(2)
-#define AD7780_PAT1    BIT(1)
-#define AD7780_PAT0    BIT(0)
+#define AD7780_RDY             BIT(7)
+#define AD7780_FILTER          BIT(6)
+#define AD7780_ERR             BIT(5)
+#define AD7780_ID1             BIT(4)
+#define AD7780_ID0             BIT(3)
+#define AD7780_GAIN            BIT(2)
+#define AD7780_PAT1            BIT(1)
+#define AD7780_PAT0            BIT(0)
+
+#define AD7780_PATTERN         (AD7780_PAT0)
+#define AD7780_PATTERN_MASK    (AD7780_PAT0 | AD7780_PAT1)
+
+#define AD7170_PAT2            BIT(2)
+
+#define AD7170_PATTERN         (AD7780_PAT0 | AD7170_PAT2)
+#define AD7170_PATTERN_MASK    (AD7780_PAT0 | AD7780_PAT1 | AD7170_PAT2)
 
 struct ad7780_chip_info {
        struct iio_chan_spec    channel;
        unsigned int            pattern_mask;
        unsigned int            pattern;
+       bool                    is_ad778x;
 };
 
 struct ad7780_state {
@@ -42,7 +51,6 @@ struct ad7780_state {
        struct regulator                *reg;
        struct gpio_desc                *powerdown_gpio;
        unsigned int    gain;
-       u16                             int_vref_mv;
 
        struct ad_sigma_delta sd;
 };
@@ -87,16 +95,20 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
                           long m)
 {
        struct ad7780_state *st = iio_priv(indio_dev);
+       int voltage_uv;
 
        switch (m) {
        case IIO_CHAN_INFO_RAW:
                return ad_sigma_delta_single_conversion(indio_dev, chan, val);
        case IIO_CHAN_INFO_SCALE:
-               *val = st->int_vref_mv * st->gain;
+               voltage_uv = regulator_get_voltage(st->reg);
+               if (voltage_uv < 0)
+                       return voltage_uv;
+               *val = (voltage_uv / 1000) * st->gain;
                *val2 = chan->scan_type.realbits - 1;
                return IIO_VAL_FRACTIONAL_LOG2;
        case IIO_CHAN_INFO_OFFSET:
-               *val -= (1 << (chan->scan_type.realbits - 1));
+               *val = -(1 << (chan->scan_type.realbits - 1));
                return IIO_VAL_INT;
        }
 
@@ -113,10 +125,12 @@ static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta,
            ((raw_sample & chip_info->pattern_mask) != chip_info->pattern))
                return -EIO;
 
-       if (raw_sample & AD7780_GAIN)
-               st->gain = 1;
-       else
-               st->gain = 128;
+       if (chip_info->is_ad778x) {
+               if (raw_sample & AD7780_GAIN)
+                       st->gain = 1;
+               else
+                       st->gain = 128;
+       }
 
        return 0;
 }
@@ -133,23 +147,27 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = {
 static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
        [ID_AD7170] = {
                .channel = AD7780_CHANNEL(12, 24),
-               .pattern = 0x5,
-               .pattern_mask = 0x7,
+               .pattern = AD7170_PATTERN,
+               .pattern_mask = AD7170_PATTERN_MASK,
+               .is_ad778x = false,
        },
        [ID_AD7171] = {
                .channel = AD7780_CHANNEL(16, 24),
-               .pattern = 0x5,
-               .pattern_mask = 0x7,
+               .pattern = AD7170_PATTERN,
+               .pattern_mask = AD7170_PATTERN_MASK,
+               .is_ad778x = false,
        },
        [ID_AD7780] = {
                .channel = AD7780_CHANNEL(24, 32),
-               .pattern = 0x1,
-               .pattern_mask = 0x3,
+               .pattern = AD7780_PATTERN,
+               .pattern_mask = AD7780_PATTERN_MASK,
+               .is_ad778x = true,
        },
        [ID_AD7781] = {
                .channel = AD7780_CHANNEL(20, 32),
-               .pattern = 0x1,
-               .pattern_mask = 0x3,
+               .pattern = AD7780_PATTERN,
+               .pattern_mask = AD7780_PATTERN_MASK,
+               .is_ad778x = true,
        },
 };
 
@@ -161,7 +179,7 @@ static int ad7780_probe(struct spi_device *spi)
 {
        struct ad7780_state *st;
        struct iio_dev *indio_dev;
-       int ret, voltage_uv = 0;
+       int ret;
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
        if (!indio_dev)
@@ -181,16 +199,10 @@ static int ad7780_probe(struct spi_device *spi)
                dev_err(&spi->dev, "Failed to enable specified AVdd supply\n");
                return ret;
        }
-       voltage_uv = regulator_get_voltage(st->reg);
 
        st->chip_info =
                &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-       if (voltage_uv)
-               st->int_vref_mv = voltage_uv / 1000;
-       else
-               dev_warn(&spi->dev, "Reference voltage unspecified\n");
-
        spi_set_drvdata(spi, indio_dev);
 
        indio_dev->dev.parent = &spi->dev;
index bf76a8620bdbc5fe5f1391033762251a45ace636..5209651a1b25aba4f291b3f0f8713cc1d9ca3004 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
  */
 
 struct ad7816_chip_info {
+       kernel_ulong_t id;
        struct spi_device *spi_dev;
-       u16 rdwr_pin;
-       u16 convert_pin;
-       u16 busy_pin;
+       struct gpio_desc *rdwr_pin;
+       struct gpio_desc *convert_pin;
+       struct gpio_desc *busy_pin;
        u8  oti_data[AD7816_CS_MAX + 1];
        u8  channel_id; /* 0 always be temperature */
        u8  mode;
 };
 
+enum ad7816_type {
+       ID_AD7816,
+       ID_AD7817,
+       ID_AD7818,
+};
+
 /*
  * ad7816 data access by SPI
  */
@@ -61,28 +68,30 @@ static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
        int ret = 0;
        __be16 buf;
 
-       gpio_set_value(chip->rdwr_pin, 1);
-       gpio_set_value(chip->rdwr_pin, 0);
+       gpiod_set_value(chip->rdwr_pin, 1);
+       gpiod_set_value(chip->rdwr_pin, 0);
        ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
        if (ret < 0) {
                dev_err(&spi_dev->dev, "SPI channel setting error\n");
                return ret;
        }
-       gpio_set_value(chip->rdwr_pin, 1);
+       gpiod_set_value(chip->rdwr_pin, 1);
 
        if (chip->mode == AD7816_PD) { /* operating mode 2 */
-               gpio_set_value(chip->convert_pin, 1);
-               gpio_set_value(chip->convert_pin, 0);
+               gpiod_set_value(chip->convert_pin, 1);
+               gpiod_set_value(chip->convert_pin, 0);
        } else { /* operating mode 1 */
-               gpio_set_value(chip->convert_pin, 0);
-               gpio_set_value(chip->convert_pin, 1);
+               gpiod_set_value(chip->convert_pin, 0);
+               gpiod_set_value(chip->convert_pin, 1);
        }
 
-       while (gpio_get_value(chip->busy_pin))
-               cpu_relax();
+       if (chip->id == ID_AD7816 || chip->id == ID_AD7817) {
+               while (gpiod_get_value(chip->busy_pin))
+                       cpu_relax();
+       }
 
-       gpio_set_value(chip->rdwr_pin, 0);
-       gpio_set_value(chip->rdwr_pin, 1);
+       gpiod_set_value(chip->rdwr_pin, 0);
+       gpiod_set_value(chip->rdwr_pin, 1);
        ret = spi_read(spi_dev, &buf, sizeof(*data));
        if (ret < 0) {
                dev_err(&spi_dev->dev, "SPI data read error\n");
@@ -99,8 +108,8 @@ static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
        struct spi_device *spi_dev = chip->spi_dev;
        int ret = 0;
 
-       gpio_set_value(chip->rdwr_pin, 1);
-       gpio_set_value(chip->rdwr_pin, 0);
+       gpiod_set_value(chip->rdwr_pin, 1);
+       gpiod_set_value(chip->rdwr_pin, 0);
        ret = spi_write(spi_dev, &data, sizeof(data));
        if (ret < 0)
                dev_err(&spi_dev->dev, "SPI oti data write error\n");
@@ -129,10 +138,10 @@ static ssize_t ad7816_store_mode(struct device *dev,
        struct ad7816_chip_info *chip = iio_priv(indio_dev);
 
        if (strcmp(buf, "full")) {
-               gpio_set_value(chip->rdwr_pin, 1);
+               gpiod_set_value(chip->rdwr_pin, 1);
                chip->mode = AD7816_FULL;
        } else {
-               gpio_set_value(chip->rdwr_pin, 0);
+               gpiod_set_value(chip->rdwr_pin, 0);
                chip->mode = AD7816_PD;
        }
 
@@ -345,15 +354,9 @@ static int ad7816_probe(struct spi_device *spi_dev)
 {
        struct ad7816_chip_info *chip;
        struct iio_dev *indio_dev;
-       unsigned short *pins = dev_get_platdata(&spi_dev->dev);
        int ret = 0;
        int i;
 
-       if (!pins) {
-               dev_err(&spi_dev->dev, "No necessary GPIO platform data.\n");
-               return -EINVAL;
-       }
-
        indio_dev = devm_iio_device_alloc(&spi_dev->dev, sizeof(*chip));
        if (!indio_dev)
                return -ENOMEM;
@@ -364,34 +367,33 @@ static int ad7816_probe(struct spi_device *spi_dev)
        chip->spi_dev = spi_dev;
        for (i = 0; i <= AD7816_CS_MAX; i++)
                chip->oti_data[i] = 203;
-       chip->rdwr_pin = pins[0];
-       chip->convert_pin = pins[1];
-       chip->busy_pin = pins[2];
-
-       ret = devm_gpio_request(&spi_dev->dev, chip->rdwr_pin,
-                               spi_get_device_id(spi_dev)->name);
-       if (ret) {
-               dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n",
-                       chip->rdwr_pin);
+
+       chip->id = spi_get_device_id(spi_dev)->driver_data;
+       chip->rdwr_pin = devm_gpiod_get(&spi_dev->dev, "rdwr", GPIOD_OUT_HIGH);
+       if (IS_ERR(chip->rdwr_pin)) {
+               ret = PTR_ERR(chip->rdwr_pin);
+               dev_err(&spi_dev->dev, "Failed to request rdwr GPIO: %d\n",
+                       ret);
                return ret;
        }
-       gpio_direction_input(chip->rdwr_pin);
-       ret = devm_gpio_request(&spi_dev->dev, chip->convert_pin,
-                               spi_get_device_id(spi_dev)->name);
-       if (ret) {
-               dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n",
-                       chip->convert_pin);
+       chip->convert_pin = devm_gpiod_get(&spi_dev->dev, "convert",
+                                          GPIOD_OUT_HIGH);
+       if (IS_ERR(chip->convert_pin)) {
+               ret = PTR_ERR(chip->convert_pin);
+               dev_err(&spi_dev->dev, "Failed to request convert GPIO: %d\n",
+                       ret);
                return ret;
        }
-       gpio_direction_input(chip->convert_pin);
-       ret = devm_gpio_request(&spi_dev->dev, chip->busy_pin,
-                               spi_get_device_id(spi_dev)->name);
-       if (ret) {
-               dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
-                       chip->busy_pin);
-               return ret;
+       if (chip->id == ID_AD7816 || chip->id == ID_AD7817) {
+               chip->busy_pin = devm_gpiod_get(&spi_dev->dev, "busy",
+                                               GPIOD_IN);
+               if (IS_ERR(chip->busy_pin)) {
+                       ret = PTR_ERR(chip->busy_pin);
+                       dev_err(&spi_dev->dev, "Failed to request busy GPIO: %d\n",
+                               ret);
+                       return ret;
+               }
        }
-       gpio_direction_input(chip->busy_pin);
 
        indio_dev->name = spi_get_device_id(spi_dev)->name;
        indio_dev->dev.parent = &spi_dev->dev;
@@ -420,10 +422,18 @@ static int ad7816_probe(struct spi_device *spi_dev)
        return 0;
 }
 
+static const struct of_device_id ad7816_of_match[] = {
+       { .compatible = "adi,ad7816", },
+       { .compatible = "adi,ad7817", },
+       { .compatible = "adi,ad7818", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ad7816_of_match);
+
 static const struct spi_device_id ad7816_id[] = {
-       { "ad7816", 0 },
-       { "ad7817", 0 },
-       { "ad7818", 0 },
+       { "ad7816", ID_AD7816 },
+       { "ad7817", ID_AD7817 },
+       { "ad7818", ID_AD7818 },
        {}
 };
 
@@ -432,6 +442,7 @@ MODULE_DEVICE_TABLE(spi, ad7816_id);
 static struct spi_driver ad7816_driver = {
        .driver = {
                .name = "ad7816",
+               .of_match_table = ad7816_of_match,
        },
        .probe = ad7816_probe,
        .id_table = ad7816_id,
index f66dd3ebbab1fe787fccc180b70441a4e598ab09..473e5e34ec0032ce94425dace224d933892efa32 100644 (file)
@@ -30,11 +30,17 @@ static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
        }
 
        ret = i2c_smbus_read_byte(client);
+
+       if (!ret)
+               return -EIO;
+
        if (ret < 0) {
                dev_err(&cl->dev, "I2C read error\n");
                return ret;
        }
 
+       *data = ret;
+
        return 0;
 }
 
index 3f22d10887139b58c2c554870e5ebf47cdd51c48..2f8a122f475dcbcd0db72f7cfd83b046e9e2fc5f 100644 (file)
@@ -217,8 +217,8 @@ struct adt7316_limit_regs {
 };
 
 static ssize_t adt7316_show_enabled(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                   struct device_attribute *attr,
+                                   char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -227,7 +227,7 @@ static ssize_t adt7316_show_enabled(struct device *dev,
 }
 
 static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
-               int enable)
+                                     int enable)
 {
        u8 config1;
        int ret;
@@ -247,9 +247,9 @@ static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
 }
 
 static ssize_t adt7316_store_enabled(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                    struct device_attribute *attr,
+                                    const char *buf,
+                                    size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -272,8 +272,8 @@ static IIO_DEVICE_ATTR(enabled, 0644,
                0);
 
 static ssize_t adt7316_show_select_ex_temp(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                          struct device_attribute *attr,
+                                          char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -285,9 +285,9 @@ static ssize_t adt7316_show_select_ex_temp(struct device *dev,
 }
 
 static ssize_t adt7316_store_select_ex_temp(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                           struct device_attribute *attr,
+                                           const char *buf,
+                                           size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -316,8 +316,8 @@ static IIO_DEVICE_ATTR(select_ex_temp, 0644,
                0);
 
 static ssize_t adt7316_show_mode(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                struct device_attribute *attr,
+                                char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -329,9 +329,9 @@ static ssize_t adt7316_show_mode(struct device *dev,
 }
 
 static ssize_t adt7316_store_mode(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                 struct device_attribute *attr,
+                                 const char *buf,
+                                 size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -357,8 +357,8 @@ static IIO_DEVICE_ATTR(mode, 0644,
                0);
 
 static ssize_t adt7316_show_all_modes(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
        return sprintf(buf, "single_channel\nround_robin\n");
 }
@@ -366,8 +366,8 @@ static ssize_t adt7316_show_all_modes(struct device *dev,
 static IIO_DEVICE_ATTR(all_modes, 0444, adt7316_show_all_modes, NULL, 0);
 
 static ssize_t adt7316_show_ad_channel(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                      struct device_attribute *attr,
+                                      char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -382,7 +382,7 @@ static ssize_t adt7316_show_ad_channel(struct device *dev,
                return sprintf(buf, "1 - Internal Temperature\n");
        case ADT7316_AD_SINGLE_CH_EX:
                if (((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) &&
-                       (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
+                   (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
                        return sprintf(buf, "2 - AIN1\n");
 
                return sprintf(buf, "2 - External Temperature\n");
@@ -404,9 +404,9 @@ static ssize_t adt7316_show_ad_channel(struct device *dev,
 }
 
 static ssize_t adt7316_store_ad_channel(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -450,8 +450,8 @@ static IIO_DEVICE_ATTR(ad_channel, 0644,
                0);
 
 static ssize_t adt7316_show_all_ad_channels(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                           struct device_attribute *attr,
+                                           char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -471,8 +471,8 @@ static IIO_DEVICE_ATTR(all_ad_channels, 0444,
                adt7316_show_all_ad_channels, NULL, 0);
 
 static ssize_t adt7316_show_disable_averaging(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                             struct device_attribute *attr,
+                                             char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -482,9 +482,9 @@ static ssize_t adt7316_show_disable_averaging(struct device *dev,
 }
 
 static ssize_t adt7316_store_disable_averaging(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                              struct device_attribute *attr,
+                                              const char *buf,
+                                              size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -510,8 +510,8 @@ static IIO_DEVICE_ATTR(disable_averaging, 0644,
                0);
 
 static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                                struct device_attribute *attr,
+                                                char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -521,9 +521,9 @@ static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
 }
 
 static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                                 struct device_attribute *attr,
+                                                 const char *buf,
+                                                 size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -549,8 +549,8 @@ static IIO_DEVICE_ATTR(enable_smbus_timeout, 0644,
                0);
 
 static ssize_t adt7316_show_powerdown(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -559,9 +559,9 @@ static ssize_t adt7316_show_powerdown(struct device *dev,
 }
 
 static ssize_t adt7316_store_powerdown(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -587,8 +587,8 @@ static IIO_DEVICE_ATTR(powerdown, 0644,
                0);
 
 static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                         struct device_attribute *attr,
+                                         char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -597,9 +597,9 @@ static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
 }
 
 static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                          struct device_attribute *attr,
+                                          const char *buf,
+                                          size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -625,8 +625,8 @@ static IIO_DEVICE_ATTR(fast_ad_clock, 0644,
                0);
 
 static ssize_t adt7316_show_da_high_resolution(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                              struct device_attribute *attr,
+                                              char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -642,9 +642,9 @@ static ssize_t adt7316_show_da_high_resolution(struct device *dev,
 }
 
 static ssize_t adt7316_store_da_high_resolution(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                               struct device_attribute *attr,
+                                               const char *buf,
+                                               size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -678,8 +678,8 @@ static IIO_DEVICE_ATTR(da_high_resolution, 0644,
                0);
 
 static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                             struct device_attribute *attr,
+                                             char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -692,9 +692,9 @@ static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
 }
 
 static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                              struct device_attribute *attr,
+                                              const char *buf,
+                                              size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -724,8 +724,8 @@ static IIO_DEVICE_ATTR(AIN_internal_Vref, 0644,
                0);
 
 static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                            struct device_attribute *attr,
+                                            char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -735,9 +735,9 @@ static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
 }
 
 static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                             struct device_attribute *attr,
+                                             const char *buf,
+                                             size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -758,13 +758,13 @@ static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(enable_proportion_DACA, 0644,
-               adt7316_show_enable_prop_DACA,
-               adt7316_store_enable_prop_DACA,
-               0);
+                      adt7316_show_enable_prop_DACA,
+                      adt7316_store_enable_prop_DACA,
+                      0);
 
 static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                            struct device_attribute *attr,
+                                            char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -774,9 +774,9 @@ static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
 }
 
 static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                             struct device_attribute *attr,
+                                             const char *buf,
+                                             size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -797,13 +797,13 @@ static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(enable_proportion_DACB, 0644,
-               adt7316_show_enable_prop_DACB,
-               adt7316_store_enable_prop_DACB,
-               0);
+                      adt7316_show_enable_prop_DACB,
+                      adt7316_store_enable_prop_DACB,
+                      0);
 
 static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                             struct device_attribute *attr,
+                                             char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -813,9 +813,9 @@ static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                              struct device_attribute *attr,
+                                              const char *buf,
+                                              size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -840,13 +840,13 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, 0644,
-               adt7316_show_DAC_2Vref_ch_mask,
-               adt7316_store_DAC_2Vref_ch_mask,
-               0);
+                      adt7316_show_DAC_2Vref_ch_mask,
+                      adt7316_store_DAC_2Vref_ch_mask,
+                      0);
 
 static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                           struct device_attribute *attr,
+                                           char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -870,9 +870,9 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                            struct device_attribute *attr,
+                                            const char *buf,
+                                            size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -900,13 +900,13 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_update_mode, 0644,
-               adt7316_show_DAC_update_mode,
-               adt7316_store_DAC_update_mode,
-               0);
+                      adt7316_show_DAC_update_mode,
+                      adt7316_store_DAC_update_mode,
+                      0);
 
 static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                                struct device_attribute *attr,
+                                                char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -920,12 +920,12 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(all_DAC_update_modes, 0444,
-               adt7316_show_all_DAC_update_modes, NULL, 0);
+                      adt7316_show_all_DAC_update_modes, NULL, 0);
 
 static ssize_t adt7316_store_update_DAC(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -958,13 +958,13 @@ static ssize_t adt7316_store_update_DAC(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(update_DAC, 0644,
-               NULL,
-               adt7316_store_update_DAC,
-               0);
+                      NULL,
+                      adt7316_store_update_DAC,
+                      0);
 
 static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                             struct device_attribute *attr,
+                                             char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -977,9 +977,9 @@ static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
 }
 
 static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                              struct device_attribute *attr,
+                                              const char *buf,
+                                              size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1003,13 +1003,13 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, 0644,
-               adt7316_show_DA_AB_Vref_bypass,
-               adt7316_store_DA_AB_Vref_bypass,
-               0);
+                      adt7316_show_DA_AB_Vref_bypass,
+                      adt7316_store_DA_AB_Vref_bypass,
+                      0);
 
 static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                             struct device_attribute *attr,
+                                             char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1022,9 +1022,9 @@ static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
 }
 
 static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                              struct device_attribute *attr,
+                                              const char *buf,
+                                              size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1048,13 +1048,13 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, 0644,
-               adt7316_show_DA_CD_Vref_bypass,
-               adt7316_store_DA_CD_Vref_bypass,
-               0);
+                      adt7316_show_DA_CD_Vref_bypass,
+                      adt7316_store_DA_CD_Vref_bypass,
+                      0);
 
 static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                             struct device_attribute *attr,
+                                             char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1068,9 +1068,9 @@ static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                              struct device_attribute *attr,
+                                              const char *buf,
+                                              size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1109,12 +1109,12 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_internal_Vref, 0644,
-               adt7316_show_DAC_internal_Vref,
-               adt7316_store_DAC_internal_Vref,
-               0);
+                      adt7316_show_DAC_internal_Vref,
+                      adt7316_store_DAC_internal_Vref,
+                      0);
 
 static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip,
-               int channel, char *buf)
+                              int channel, char *buf)
 {
        u16 data;
        u8 msb, lsb;
@@ -1122,7 +1122,7 @@ static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip,
        int ret;
 
        if ((chip->config2 & ADT7316_AD_SINGLE_CH_MODE) &&
-               channel != (chip->config2 & ADT7516_AD_SINGLE_CH_MASK))
+           channel != (chip->config2 & ADT7516_AD_SINGLE_CH_MASK))
                return -EPERM;
 
        switch (channel) {
@@ -1189,8 +1189,8 @@ static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip,
 }
 
 static ssize_t adt7316_show_VDD(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                               struct device_attribute *attr,
+                               char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1200,8 +1200,8 @@ static ssize_t adt7316_show_VDD(struct device *dev,
 static IIO_DEVICE_ATTR(VDD, 0444, adt7316_show_VDD, NULL, 0);
 
 static ssize_t adt7316_show_in_temp(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                   struct device_attribute *attr,
+                                   char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1212,8 +1212,8 @@ static ssize_t adt7316_show_in_temp(struct device *dev,
 static IIO_DEVICE_ATTR(in_temp, 0444, adt7316_show_in_temp, NULL, 0);
 
 static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1222,12 +1222,12 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(ex_temp_AIN1, 0444, adt7316_show_ex_temp_AIN1,
-               NULL, 0);
+                      NULL, 0);
 static IIO_DEVICE_ATTR(ex_temp, 0444, adt7316_show_ex_temp_AIN1, NULL, 0);
 
 static ssize_t adt7316_show_AIN2(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                struct device_attribute *attr,
+                                char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1237,8 +1237,8 @@ static ssize_t adt7316_show_AIN2(struct device *dev,
 static IIO_DEVICE_ATTR(AIN2, 0444, adt7316_show_AIN2, NULL, 0);
 
 static ssize_t adt7316_show_AIN3(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                struct device_attribute *attr,
+                                char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1248,8 +1248,8 @@ static ssize_t adt7316_show_AIN3(struct device *dev,
 static IIO_DEVICE_ATTR(AIN3, 0444, adt7316_show_AIN3, NULL, 0);
 
 static ssize_t adt7316_show_AIN4(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                struct device_attribute *attr,
+                                char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1259,7 +1259,7 @@ static ssize_t adt7316_show_AIN4(struct device *dev,
 static IIO_DEVICE_ATTR(AIN4, 0444, adt7316_show_AIN4, NULL, 0);
 
 static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip,
-               int offset_addr, char *buf)
+                                       int offset_addr, char *buf)
 {
        int data;
        u8 val;
@@ -1277,7 +1277,9 @@ static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip,
 }
 
 static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip,
-               int offset_addr, const char *buf, size_t len)
+                                        int offset_addr,
+                                        const char *buf,
+                                        size_t len)
 {
        int data;
        u8 val;
@@ -1300,8 +1302,8 @@ static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip,
 }
 
 static ssize_t adt7316_show_in_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                          struct device_attribute *attr,
+                                          char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1310,9 +1312,9 @@ static ssize_t adt7316_show_in_temp_offset(struct device *dev,
 }
 
 static ssize_t adt7316_store_in_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                           struct device_attribute *attr,
+                                           const char *buf,
+                                           size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1322,12 +1324,12 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(in_temp_offset, 0644,
-               adt7316_show_in_temp_offset,
-               adt7316_store_in_temp_offset, 0);
+                      adt7316_show_in_temp_offset,
+                      adt7316_store_in_temp_offset, 0);
 
 static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                          struct device_attribute *attr,
+                                          char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1336,9 +1338,9 @@ static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
 }
 
 static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                           struct device_attribute *attr,
+                                           const char *buf,
+                                           size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1348,12 +1350,12 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(ex_temp_offset, 0644,
-               adt7316_show_ex_temp_offset,
-               adt7316_store_ex_temp_offset, 0);
+                      adt7316_show_ex_temp_offset,
+                      adt7316_store_ex_temp_offset, 0);
 
 static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                                 struct device_attribute *attr,
+                                                 char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1363,9 +1365,9 @@ static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
 }
 
 static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                               struct device_attribute *attr,
+                                               const char *buf,
+                                               size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1375,12 +1377,12 @@ static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(in_analog_temp_offset, 0644,
-               adt7316_show_in_analog_temp_offset,
-               adt7316_store_in_analog_temp_offset, 0);
+                      adt7316_show_in_analog_temp_offset,
+                      adt7316_store_in_analog_temp_offset, 0);
 
 static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                                 struct device_attribute *attr,
+                                                 char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1390,9 +1392,9 @@ static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
 }
 
 static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                               struct device_attribute *attr,
+                                               const char *buf,
+                                               size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1402,21 +1404,21 @@ static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(ex_analog_temp_offset, 0644,
-               adt7316_show_ex_analog_temp_offset,
-               adt7316_store_ex_analog_temp_offset, 0);
+                      adt7316_show_ex_analog_temp_offset,
+                      adt7316_store_ex_analog_temp_offset, 0);
 
 static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
-               int channel, char *buf)
+                               int channel, char *buf)
 {
        u16 data;
        u8 msb, lsb, offset;
        int ret;
 
        if (channel >= ADT7316_DA_MSB_DATA_REGS ||
-               (channel == 0 &&
-               (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
-               (channel == 1 &&
-               (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
+           (channel == 0 &&
+           (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
+           (channel == 1 &&
+           (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
                return -EPERM;
 
        offset = chip->dac_bits - 8;
@@ -1439,17 +1441,17 @@ static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
 }
 
 static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
-               int channel, const char *buf, size_t len)
+                                int channel, const char *buf, size_t len)
 {
        u8 msb, lsb, offset;
        u16 data;
        int ret;
 
        if (channel >= ADT7316_DA_MSB_DATA_REGS ||
-               (channel == 0 &&
-               (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
-               (channel == 1 &&
-               (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
+           (channel == 0 &&
+           (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
+           (channel == 1 &&
+           (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
                return -EPERM;
 
        offset = chip->dac_bits - 8;
@@ -1476,8 +1478,8 @@ static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
 }
 
 static ssize_t adt7316_show_DAC_A(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1486,9 +1488,9 @@ static ssize_t adt7316_show_DAC_A(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_A(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1497,11 +1499,11 @@ static ssize_t adt7316_store_DAC_A(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_A, 0644, adt7316_show_DAC_A,
-               adt7316_store_DAC_A, 0);
+                      adt7316_store_DAC_A, 0);
 
 static ssize_t adt7316_show_DAC_B(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1510,9 +1512,9 @@ static ssize_t adt7316_show_DAC_B(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_B(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1521,11 +1523,11 @@ static ssize_t adt7316_store_DAC_B(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_B, 0644, adt7316_show_DAC_B,
-               adt7316_store_DAC_B, 0);
+                      adt7316_store_DAC_B, 0);
 
 static ssize_t adt7316_show_DAC_C(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1534,9 +1536,9 @@ static ssize_t adt7316_show_DAC_C(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_C(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1545,11 +1547,11 @@ static ssize_t adt7316_store_DAC_C(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_C, 0644, adt7316_show_DAC_C,
-               adt7316_store_DAC_C, 0);
+                      adt7316_store_DAC_C, 0);
 
 static ssize_t adt7316_show_DAC_D(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1558,9 +1560,9 @@ static ssize_t adt7316_show_DAC_D(struct device *dev,
 }
 
 static ssize_t adt7316_store_DAC_D(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1569,11 +1571,11 @@ static ssize_t adt7316_store_DAC_D(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(DAC_D, 0644, adt7316_show_DAC_D,
-               adt7316_store_DAC_D, 0);
+                      adt7316_store_DAC_D, 0);
 
 static ssize_t adt7316_show_device_id(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1590,8 +1592,8 @@ static ssize_t adt7316_show_device_id(struct device *dev,
 static IIO_DEVICE_ATTR(device_id, 0444, adt7316_show_device_id, NULL, 0);
 
 static ssize_t adt7316_show_manufactorer_id(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                           struct device_attribute *attr,
+                                           char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1606,11 +1608,11 @@ static ssize_t adt7316_show_manufactorer_id(struct device *dev,
 }
 
 static IIO_DEVICE_ATTR(manufactorer_id, 0444,
-               adt7316_show_manufactorer_id, NULL, 0);
+                      adt7316_show_manufactorer_id, NULL, 0);
 
 static ssize_t adt7316_show_device_rev(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                      struct device_attribute *attr,
+                                      char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1627,8 +1629,8 @@ static ssize_t adt7316_show_device_rev(struct device *dev,
 static IIO_DEVICE_ATTR(device_rev, 0444, adt7316_show_device_rev, NULL, 0);
 
 static ssize_t adt7316_show_bus_type(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                    struct device_attribute *attr,
+                                    char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1811,8 +1813,8 @@ static irqreturn_t adt7316_event_handler(int irq, void *private)
  * Show mask of enabled interrupts in Hex.
  */
 static ssize_t adt7316_show_int_mask(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                    struct device_attribute *attr,
+                                    char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1824,9 +1826,9 @@ static ssize_t adt7316_show_int_mask(struct device *dev,
  * Set 1 to the mask in Hex to enabled interrupts.
  */
 static ssize_t adt7316_set_int_mask(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                   struct device_attribute *attr,
+                                   const char *buf,
+                                   size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1865,8 +1867,8 @@ static ssize_t adt7316_set_int_mask(struct device *dev,
 }
 
 static inline ssize_t adt7316_show_ad_bound(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                           struct device_attribute *attr,
+                                           char *buf)
 {
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
@@ -1876,7 +1878,7 @@ static inline ssize_t adt7316_show_ad_bound(struct device *dev,
        int ret;
 
        if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
-               this_attr->address > ADT7316_EX_TEMP_LOW)
+           this_attr->address > ADT7316_EX_TEMP_LOW)
                return -EPERM;
 
        ret = chip->bus.read(chip->bus.client, this_attr->address, &val);
@@ -1886,7 +1888,7 @@ static inline ssize_t adt7316_show_ad_bound(struct device *dev,
        data = (int)val;
 
        if (!((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
-               (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)) {
+             (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)) {
                if (data & 0x80)
                        data -= 256;
        }
@@ -1895,9 +1897,9 @@ static inline ssize_t adt7316_show_ad_bound(struct device *dev,
 }
 
 static inline ssize_t adt7316_set_ad_bound(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                          struct device_attribute *attr,
+                                          const char *buf,
+                                          size_t len)
 {
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
@@ -1907,7 +1909,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev,
        int ret;
 
        if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
-               this_attr->address > ADT7316_EX_TEMP_LOW)
+           this_attr->address > ADT7316_EX_TEMP_LOW)
                return -EPERM;
 
        ret = kstrtoint(buf, 10, &data);
@@ -1915,7 +1917,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev,
                return -EINVAL;
 
        if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
-               (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) {
+           (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) {
                if (data > 255 || data < 0)
                        return -EINVAL;
        } else {
@@ -1936,8 +1938,8 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev,
 }
 
 static ssize_t adt7316_show_int_enabled(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -1946,9 +1948,9 @@ static ssize_t adt7316_show_int_enabled(struct device *dev,
 }
 
 static ssize_t adt7316_set_int_enabled(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t len)
 {
        struct iio_dev *dev_info = dev_to_iio_dev(dev);
        struct adt7316_chip_info *chip = iio_priv(dev_info);
@@ -2097,7 +2099,7 @@ static const struct iio_info adt7516_info = {
  * device probe and remove
  */
 int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
-               const char *name)
+                 const char *name)
 {
        struct adt7316_chip_info *chip;
        struct iio_dev *indio_dev;
@@ -2169,7 +2171,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
                return ret;
 
        dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n",
-                       indio_dev->name);
+                indio_dev->name);
 
        return 0;
 }
index ec40fbb698a663ec2be2e38047bf2e4eb36cb5ff..b954dcbc92dbe791257e1f257895b6f26192ee49 100644 (file)
@@ -31,6 +31,6 @@ extern const struct dev_pm_ops adt7316_pm_ops;
 #define ADT7316_PM_OPS NULL
 #endif
 int adt7316_probe(struct device *dev, struct adt7316_bus *bus,
-                  const char *name);
+                 const char *name);
 
 #endif
index d16084d7068ce06a94e0adca5f5f517fc8c97045..24f74ce60f80b0434b19e2576ecedb214e0b764d 100644 (file)
@@ -102,18 +102,19 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,
 {
        int ret;
        struct ad7150_chip_info *chip = iio_priv(indio_dev);
+       int channel = chan->channel;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
                ret = i2c_smbus_read_word_data(chip->client,
-                                       ad7150_addresses[chan->channel][0]);
+                                              ad7150_addresses[channel][0]);
                if (ret < 0)
                        return ret;
                *val = swab16(ret);
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_AVERAGE_RAW:
                ret = i2c_smbus_read_word_data(chip->client,
-                                       ad7150_addresses[chan->channel][1]);
+                                              ad7150_addresses[channel][1]);
                if (ret < 0)
                        return ret;
                *val = swab16(ret);
@@ -182,8 +183,8 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev,
        case IIO_EV_TYPE_THRESH:
                value = chip->threshold[rising][chan];
                return i2c_smbus_write_word_data(chip->client,
-                                               ad7150_addresses[chan][3],
-                                               swab16(value));
+                                                ad7150_addresses[chan][3],
+                                                swab16(value));
        case IIO_EV_TYPE_MAG_ADAPTIVE:
                sens = chip->mag_sensitivity[rising][chan];
                timeout = chip->mag_timeout[rising][chan];
index a2370dd1e1a8fd51f849f4f96a37a94070b48eb1..f9bcb8310e21bb846f364dfc4d4168aa19a1437a 100644 (file)
 
 /**
  * struct ad5933_platform_data - platform specific data
- * @ext_clk_Hz:                the external clock frequency in Hz, if not set
+ * @ext_clk_hz:                the external clock frequency in Hz, if not set
  *                     the driver uses the internal clock (16.776 MHz)
  * @vref_mv:           the external reference voltage in millivolt
  */
 
 struct ad5933_platform_data {
-       unsigned long                   ext_clk_Hz;
+       unsigned long                   ext_clk_hz;
        unsigned short                  vref_mv;
 };
 
@@ -210,7 +210,7 @@ static int ad5933_set_freq(struct ad5933_state *st,
                u8 d8[4];
        } dat;
 
-       freqreg = (u64) freq * (u64) (1 << 27);
+       freqreg = (u64)freq * (u64)(1 << 27);
        do_div(freqreg, st->mclk_hz / 4);
 
        switch (reg) {
@@ -267,7 +267,6 @@ static void ad5933_calc_out_ranges(struct ad5933_state *st)
 
        for (i = 0; i < 4; i++)
                st->range_avail[i] = normalized_3v3[i] * st->vref_mv / 3300;
-
 }
 
 /*
@@ -726,8 +725,8 @@ static int ad5933_probe(struct i2c_client *client,
        else
                st->vref_mv = pdata->vref_mv;
 
-       if (pdata->ext_clk_Hz) {
-               st->mclk_hz = pdata->ext_clk_Hz;
+       if (pdata->ext_clk_hz) {
+               st->mclk_hz = pdata->ext_clk_hz;
                st->ctrl_lb = AD5933_CTRL_EXT_SYSCLK;
        } else {
                st->mclk_hz = AD5933_INT_OSC_FREQ_Hz;
index ac13b99bd9cb33af56a0dbf68d4c9ec9a68b1ea5..cec9d995b3df438a1dc2beb8caafb44be61e99f4 100644 (file)
 #include <linux/slab.h>
 #include <linux/sysfs.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
-#include "ad2s1210.h"
 
 #define DRV_NAME "ad2s1210"
 
@@ -67,12 +66,33 @@ enum ad2s1210_mode {
        MOD_RESERVED,
 };
 
+enum ad2s1210_gpios {
+       AD2S1210_SAMPLE,
+       AD2S1210_A0,
+       AD2S1210_A1,
+       AD2S1210_RES0,
+       AD2S1210_RES1,
+};
+
+struct ad2s1210_gpio {
+       const char *name;
+       unsigned long flags;
+};
+
+static const struct ad2s1210_gpio gpios[] = {
+       [AD2S1210_SAMPLE] = { .name = "adi,sample", .flags = GPIOD_OUT_LOW },
+       [AD2S1210_A0] = { .name = "adi,a0", .flags = GPIOD_OUT_LOW },
+       [AD2S1210_A1] = { .name = "adi,a1", .flags = GPIOD_OUT_LOW },
+       [AD2S1210_RES0] = { .name = "adi,res0", .flags = GPIOD_OUT_LOW },
+       [AD2S1210_RES1] = { .name = "adi,res1", .flags = GPIOD_OUT_LOW },
+};
+
 static const unsigned int ad2s1210_resolution_value[] = { 10, 12, 14, 16 };
 
 struct ad2s1210_state {
-       const struct ad2s1210_platform_data *pdata;
        struct mutex lock;
        struct spi_device *sdev;
+       struct gpio_desc *gpios[5];
        unsigned int fclkin;
        unsigned int fexcit;
        bool hysteresis;
@@ -91,8 +111,8 @@ static const int ad2s1210_mode_vals[4][2] = {
 static inline void ad2s1210_set_mode(enum ad2s1210_mode mode,
                                     struct ad2s1210_state *st)
 {
-       gpio_set_value(st->pdata->a[0], ad2s1210_mode_vals[mode][0]);
-       gpio_set_value(st->pdata->a[1], ad2s1210_mode_vals[mode][1]);
+       gpiod_set_value(st->gpios[AD2S1210_A0], ad2s1210_mode_vals[mode][0]);
+       gpiod_set_value(st->gpios[AD2S1210_A1], ad2s1210_mode_vals[mode][1]);
        st->mode = mode;
 }
 
@@ -150,24 +170,16 @@ int ad2s1210_update_frequency_control_word(struct ad2s1210_state *st)
        return ad2s1210_config_write(st, fcw);
 }
 
-static unsigned char ad2s1210_read_resolution_pin(struct ad2s1210_state *st)
-{
-       int resolution = (gpio_get_value(st->pdata->res[0]) << 1) |
-                         gpio_get_value(st->pdata->res[1]);
-
-       return ad2s1210_resolution_value[resolution];
-}
-
 static const int ad2s1210_res_pins[4][2] = {
        { 0, 0 }, {0, 1}, {1, 0}, {1, 1}
 };
 
 static inline void ad2s1210_set_resolution_pin(struct ad2s1210_state *st)
 {
-       gpio_set_value(st->pdata->res[0],
-                      ad2s1210_res_pins[(st->resolution - 10) / 2][0]);
-       gpio_set_value(st->pdata->res[1],
-                      ad2s1210_res_pins[(st->resolution - 10) / 2][1]);
+       gpiod_set_value(st->gpios[AD2S1210_RES0],
+                       ad2s1210_res_pins[(st->resolution - 10) / 2][0]);
+       gpiod_set_value(st->gpios[AD2S1210_RES1],
+                       ad2s1210_res_pins[(st->resolution - 10) / 2][1]);
 }
 
 static inline int ad2s1210_soft_reset(struct ad2s1210_state *st)
@@ -301,15 +313,9 @@ static ssize_t ad2s1210_store_control(struct device *dev,
                        "ad2s1210: write control register fail\n");
                goto error_ret;
        }
-       st->resolution
-               = ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION];
-       if (st->pdata->gpioin) {
-               data = ad2s1210_read_resolution_pin(st);
-               if (data != st->resolution)
-                       dev_warn(dev, "ad2s1210: resolution settings not match\n");
-       } else {
-               ad2s1210_set_resolution_pin(st);
-       }
+       st->resolution =
+               ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION];
+       ad2s1210_set_resolution_pin(st);
        ret = len;
        st->hysteresis = !!(data & AD2S1210_ENABLE_HYSTERESIS);
 
@@ -363,15 +369,9 @@ static ssize_t ad2s1210_store_resolution(struct device *dev,
                dev_err(dev, "ad2s1210: setting resolution fail\n");
                goto error_ret;
        }
-       st->resolution
-               = ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION];
-       if (st->pdata->gpioin) {
-               data = ad2s1210_read_resolution_pin(st);
-               if (data != st->resolution)
-                       dev_warn(dev, "ad2s1210: resolution settings not match\n");
-       } else {
-               ad2s1210_set_resolution_pin(st);
-       }
+       st->resolution =
+               ad2s1210_resolution_value[data & AD2S1210_SET_RESOLUTION];
+       ad2s1210_set_resolution_pin(st);
        ret = len;
 error_ret:
        mutex_unlock(&st->lock);
@@ -401,15 +401,15 @@ static ssize_t ad2s1210_clear_fault(struct device *dev,
        int ret;
 
        mutex_lock(&st->lock);
-       gpio_set_value(st->pdata->sample, 0);
+       gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0);
        /* delay (2 * tck + 20) nano seconds */
        udelay(1);
-       gpio_set_value(st->pdata->sample, 1);
+       gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1);
        ret = ad2s1210_config_read(st, AD2S1210_REG_FAULT);
        if (ret < 0)
                goto error_ret;
-       gpio_set_value(st->pdata->sample, 0);
-       gpio_set_value(st->pdata->sample, 1);
+       gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0);
+       gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1);
 error_ret:
        mutex_unlock(&st->lock);
 
@@ -466,7 +466,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev,
        s16 vel;
 
        mutex_lock(&st->lock);
-       gpio_set_value(st->pdata->sample, 0);
+       gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 0);
        /* delay (6 * tck + 20) nano seconds */
        udelay(1);
 
@@ -512,7 +512,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev,
        }
 
 error_ret:
-       gpio_set_value(st->pdata->sample, 1);
+       gpiod_set_value(st->gpios[AD2S1210_SAMPLE], 1);
        /* delay (2 * tck + 20) nano seconds */
        udelay(1);
        mutex_unlock(&st->lock);
@@ -592,10 +592,7 @@ static int ad2s1210_initial(struct ad2s1210_state *st)
        int ret;
 
        mutex_lock(&st->lock);
-       if (st->pdata->gpioin)
-               st->resolution = ad2s1210_read_resolution_pin(st);
-       else
-               ad2s1210_set_resolution_pin(st);
+       ad2s1210_set_resolution_pin(st);
 
        ret = ad2s1210_config_write(st, AD2S1210_REG_CONTROL);
        if (ret < 0)
@@ -630,30 +627,22 @@ static const struct iio_info ad2s1210_info = {
 
 static int ad2s1210_setup_gpios(struct ad2s1210_state *st)
 {
-       unsigned long flags = st->pdata->gpioin ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
-       struct gpio ad2s1210_gpios[] = {
-               { st->pdata->sample, GPIOF_DIR_IN, "sample" },
-               { st->pdata->a[0], flags, "a0" },
-               { st->pdata->a[1], flags, "a1" },
-               { st->pdata->res[0], flags, "res0" },
-               { st->pdata->res[0], flags, "res1" },
-       };
-
-       return gpio_request_array(ad2s1210_gpios, ARRAY_SIZE(ad2s1210_gpios));
-}
-
-static void ad2s1210_free_gpios(struct ad2s1210_state *st)
-{
-       unsigned long flags = st->pdata->gpioin ? GPIOF_DIR_IN : GPIOF_DIR_OUT;
-       struct gpio ad2s1210_gpios[] = {
-               { st->pdata->sample, GPIOF_DIR_IN, "sample" },
-               { st->pdata->a[0], flags, "a0" },
-               { st->pdata->a[1], flags, "a1" },
-               { st->pdata->res[0], flags, "res0" },
-               { st->pdata->res[0], flags, "res1" },
-       };
+       struct spi_device *spi = st->sdev;
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+               st->gpios[i] = devm_gpiod_get(&spi->dev, gpios[i].name,
+                                             gpios[i].flags);
+               if (IS_ERR(st->gpios[i])) {
+                       ret = PTR_ERR(st->gpios[i]);
+                       dev_err(&spi->dev,
+                               "ad2s1210: failed to request %s GPIO: %d\n",
+                               gpios[i].name, ret);
+                       return ret;
+               }
+       }
 
-       gpio_free_array(ad2s1210_gpios, ARRAY_SIZE(ad2s1210_gpios));
+       return 0;
 }
 
 static int ad2s1210_probe(struct spi_device *spi)
@@ -669,7 +658,6 @@ static int ad2s1210_probe(struct spi_device *spi)
        if (!indio_dev)
                return -ENOMEM;
        st = iio_priv(indio_dev);
-       st->pdata = spi->dev.platform_data;
        ret = ad2s1210_setup_gpios(st);
        if (ret < 0)
                return ret;
@@ -692,7 +680,7 @@ static int ad2s1210_probe(struct spi_device *spi)
 
        ret = iio_device_register(indio_dev);
        if (ret)
-               goto error_free_gpios;
+               return ret;
 
        st->fclkin = spi->max_speed_hz;
        spi->mode = SPI_MODE_3;
@@ -700,10 +688,6 @@ static int ad2s1210_probe(struct spi_device *spi)
        ad2s1210_initial(st);
 
        return 0;
-
-error_free_gpios:
-       ad2s1210_free_gpios(st);
-       return ret;
 }
 
 static int ad2s1210_remove(struct spi_device *spi)
@@ -711,11 +695,16 @@ static int ad2s1210_remove(struct spi_device *spi)
        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 
        iio_device_unregister(indio_dev);
-       ad2s1210_free_gpios(iio_priv(indio_dev));
 
        return 0;
 }
 
+static const struct of_device_id ad2s1210_of_match[] = {
+       { .compatible = "adi,ad2s1210", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ad2s1210_of_match);
+
 static const struct spi_device_id ad2s1210_id[] = {
        { "ad2s1210" },
        {}
@@ -725,6 +714,7 @@ MODULE_DEVICE_TABLE(spi, ad2s1210_id);
 static struct spi_driver ad2s1210_driver = {
        .driver = {
                .name = DRV_NAME,
+               .of_match_table = of_match_ptr(ad2s1210_of_match),
        },
        .probe = ad2s1210_probe,
        .remove = ad2s1210_remove,
diff --git a/drivers/staging/iio/resolver/ad2s1210.h b/drivers/staging/iio/resolver/ad2s1210.h
deleted file mode 100644 (file)
index e9b2147..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * ad2s1210.h plaform data for the ADI Resolver to Digital Converters:
- * AD2S1210
- *
- * Copyright (c) 2010-2010 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef _AD2S1210_H
-#define _AD2S1210_H
-
-struct ad2s1210_platform_data {
-       unsigned int            sample;
-       unsigned int            a[2];
-       unsigned int            res[2];
-       bool                    gpioin;
-};
-#endif /* _AD2S1210_H */
index 59586947a9366c15ae4f2b857d358bd83ab6b1e9..3e257ac46f7af380289c14f40878dc248f5cc1a4 100644 (file)
@@ -34,16 +34,32 @@ static int ad2s90_read_raw(struct iio_dev *indio_dev,
        int ret;
        struct ad2s90_state *st = iio_priv(indio_dev);
 
-       mutex_lock(&st->lock);
-       ret = spi_read(st->sdev, st->rx, 2);
-       if (ret)
-               goto error_ret;
-       *val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
-
-error_ret:
-       mutex_unlock(&st->lock);
-
-       return IIO_VAL_INT;
+       if (chan->type != IIO_ANGL)
+               return -EINVAL;
+
+       switch (m) {
+       case IIO_CHAN_INFO_SCALE:
+               /* 2 * Pi / 2^12 */
+               *val = 6283; /* mV */
+               *val2 = 12;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&st->lock);
+               ret = spi_read(st->sdev, st->rx, 2);
+               if (ret < 0) {
+                       mutex_unlock(&st->lock);
+                       return ret;
+               }
+               *val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+
+               mutex_unlock(&st->lock);
+
+               return IIO_VAL_INT;
+       default:
+               break;
+       }
+
+       return -EINVAL;
 }
 
 static const struct iio_info ad2s90_info = {
@@ -54,14 +70,14 @@ static const struct iio_chan_spec ad2s90_chan = {
        .type = IIO_ANGL,
        .indexed = 1,
        .channel = 0,
-       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
 };
 
 static int ad2s90_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
        struct ad2s90_state *st;
-       int ret = 0;
+       int ret;
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
        if (!indio_dev)
@@ -78,16 +94,17 @@ static int ad2s90_probe(struct spi_device *spi)
        indio_dev->num_channels = 1;
        indio_dev->name = spi_get_device_id(spi)->name;
 
-       ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
-       if (ret)
-               return ret;
-
        /* need 600ns between CS and the first falling edge of SCLK */
        spi->max_speed_hz = 830000;
        spi->mode = SPI_MODE_3;
-       spi_setup(spi);
+       ret = spi_setup(spi);
+
+       if (ret < 0) {
+               dev_err(&spi->dev, "spi_setup failed!\n");
+               return ret;
+       }
 
-       return 0;
+       return devm_iio_device_register(indio_dev->dev.parent, indio_dev);
 }
 
 static const struct spi_device_id ad2s90_id[] = {
index 730ead1a46df6765343cdc50a39a23461c16d156..7e84351fa2c0532bea6aa77b0299a2ff4277f345 100644 (file)
@@ -39,6 +39,8 @@ struct iio_dev;
  *             if there is just one read-only sample data shift register.
  * @addr_shift: Shift of the register address in the communications register.
  * @read_mask: Mask for the communications register having the read bit set.
+ * @data_reg: Address of the data register, if 0 the default address of 0x3 will
+ *   be used.
  */
 struct ad_sigma_delta_info {
        int (*set_channel)(struct ad_sigma_delta *, unsigned int channel);
@@ -47,6 +49,7 @@ struct ad_sigma_delta_info {
        bool has_registers;
        unsigned int addr_shift;
        unsigned int read_mask;
+       unsigned int data_reg;
 };
 
 /**
index f9bd6e8ab1381c565226f8d7291084d4e5de1e26..8092b8e7f37e013805a023f2bcf9e457351c2459 100644 (file)
@@ -40,7 +40,7 @@
 #define ST_SENSORS_DEFAULT_STAT_ADDR           0x27
 
 #define ST_SENSORS_MAX_NAME                    17
-#define ST_SENSORS_MAX_4WAI                    7
+#define ST_SENSORS_MAX_4WAI                    8
 
 #define ST_SENSORS_LSM_CHANNELS(device_type, mask, index, mod, \
                                        ch2, s, endian, rbits, sbits, addr) \
index f8274b0c68880ccbd02de1a85ece46a3cab2053f..728193111c2fc88a2dba6002c66a70ed9f664b2c 100644 (file)
  *     Accelerometer DRDY on LSM330 available only on pin 1 (see datasheet).
  * @open_drain: set the interrupt line to be open drain if possible.
  * @spi_3wire: enable spi-3wire mode.
+ * @pullups: enable/disable i2c controller pullup resistors.
  */
 struct st_sensors_platform_data {
        u8 drdy_int_pin;
        bool open_drain;
        bool spi_3wire;
+       bool pullups;
 };
 
 #endif /* ST_SENSORS_PDATA_H */
index 332ed2f6c2c2e54ae776fba178551f05fbc38851..e22378dba244e95dca3376988369fb8ae44731e5 100644 (file)
@@ -12,7 +12,7 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
+override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := iio_event_monitor lsiio iio_generic_buffer
 ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))