Merge tag 'iio-for-4.20a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Sep 2018 08:38:48 +0000 (10:38 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 14 Sep 2018 08:38:48 +0000 (10:38 +0200)
Jonathan writes:

1st round of IIO new device support, features and cleanups in the 4.20 cycle.

There is a merge commit in here to pull in regmap support for repeatedly
reading the same register (to read out FIFOs).  Used by the adxl372 driver.
This will find uses elsewhere once we tidy up various drivers that are
effectively doing this and relying on not enabling regcache.

New device support
* Analog devices ADXL372 accelerometer
  - new driver for this accelerometer including fifo and and interrupt support.
    Follow up patches enforce trigger validation, add sampling frequency
    control and filter bandwidth control.  A later series added i2c support
    to the existing SPI support.
* ST lsm6dsx
  - rework and add support fo the LSM6DSO 6 axis mems sensor.
* Linear LTC 1660 DAC
  - new driver supporting the LTC 1660 and LTC 1665 SPI DACs.
* Microchip mcp3911 ADC.
  - new driver for this integrated analog front end and ADC.
* Qualcomm SPMI PMIC5 adc driver
  - using the spmi framework, new driver and bindings for this ADC.
    Follow up patch adds some missing channels.

Features
* ad5758
  - support hard reset using a gpio (if provided).
* mpu6050
  - Regulator support
* qcom-spmi-adc5
  - Sanity check the channel numbers provided by DT to make sure the
    driver actually knows about them.
* sc27xx
  - give raw data for channel 20 as it's used on all known boards for
    the headset which needs a custom converstion function.  If it turns
    out someone builds a board where this isn't true we will deal with it
    when it happens.
  - add ADC scale calibration.
* tsl2772
  - support device tree binding to set the proximity led settings.
  - regulator supprot.
  - binding for apds9930 - trivial addition as register compatible with tsl2772.

Cleanups / Minor fixes

* adxl345
  - supress a static checker warning but explicitly checking if the id
    object is null.
* bh1750
  - avoid CONFIG_PM_SLEEP checks.
  - SPDX.
* bme680
  - spelling mistake
  - use clamp rather than open coding.
  - white space and other similar fixes.
  - rename MSK to MASK for clarifty and use GENMASK to specify them.
  - use the FIELD_GET macro rather than a very odd accessor of dividing by
    16 to get the shift.
  - rework to share handing for oversampling of the various channels in a
    unified way.
  - check explicitly for val2 in write_raw function to ensure it is 0.
  - drop some field defines that don't add anything.
* dpot-adc
  - SPDX
* envelope detector
  - SPDX
* isl29501
  - fix an ancient compiler warning mostly because it results in much
    nicer code.
* max30102
  - mark switch fall throughs.
* max44000
  - drop an unused variable.
* max512
  - avoid CONFIG_PM_SLEEP checks.
* max5481
  - use of_device_get_match_data rather than open coding it.
* max5821
  - avoid CONFIG_PM_SLEEP checks.
* max9611
  - explicity cast an enum to an integer to make it totally clear that
    this is intended.
* mcp4018
  - fix an inconsistent MODULE_LICENSE.
  - use of_device_get_match_data rather than open coding it.
* mcp4531
  - use of_device_get_match_data rather than open coding it.
  - SPDX
* mcp4725
  - avoid CONFIG_PM_SLEEP checks.
* mcp4922
  - Fix error handling and prevent writing a negative to when setting the
    output voltage.
* ms5611
  - drop deprecated compatible strings without manufacturer from being
    explicitly listed.  They are handled anyway.
  - SPDX
* multiplexer
  - SPDX
* qcom-vadc
  - fix inconsistent documentation for reg.
* ti-dac5571
  - provide and of_match_table.

* treewide
  - update Michael Hennerich's email address.
  - Use %pOFn rather than device_node.name.
* documentation.
  - tidy up a wrong kernel version for the introduction of the
    position_relative ABI.

88 files changed:
Documentation/ABI/testing/sysfs-bus-iio
Documentation/devicetree/bindings/iio/accel/adxl372.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/mcp3911.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.txt
Documentation/devicetree/bindings/iio/adc/sprd,sc27xx-adc.txt
Documentation/devicetree/bindings/iio/dac/ad5758.txt
Documentation/devicetree/bindings/iio/dac/ltc1660.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt
Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
Documentation/devicetree/bindings/iio/light/tsl2772.txt [new file with mode: 0644]
Documentation/devicetree/bindings/trivial-devices.txt
MAINTAINERS
drivers/iio/accel/Kconfig
drivers/iio/accel/Makefile
drivers/iio/accel/adxl345_i2c.c
drivers/iio/accel/adxl372.c [new file with mode: 0644]
drivers/iio/accel/adxl372.h [new file with mode: 0644]
drivers/iio/accel/adxl372_i2c.c [new file with mode: 0644]
drivers/iio/accel/adxl372_spi.c [new file with mode: 0644]
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad7298.c
drivers/iio/adc/ad7476.c
drivers/iio/adc/ad7793.c
drivers/iio/adc/ad7887.c
drivers/iio/adc/ad7923.c
drivers/iio/adc/ad799x.c
drivers/iio/adc/envelope-detector.c
drivers/iio/adc/max9611.c
drivers/iio/adc/mcp3911.c [new file with mode: 0644]
drivers/iio/adc/qcom-pm8xxx-xoadc.c
drivers/iio/adc/qcom-spmi-adc5.c [new file with mode: 0644]
drivers/iio/adc/qcom-vadc-common.c
drivers/iio/adc/qcom-vadc-common.h
drivers/iio/adc/rcar-gyroadc.c
drivers/iio/adc/sc27xx_adc.c
drivers/iio/amplifiers/ad8366.c
drivers/iio/chemical/bme680.h
drivers/iio/chemical/bme680_core.c
drivers/iio/dac/Kconfig
drivers/iio/dac/Makefile
drivers/iio/dac/ad5446.c
drivers/iio/dac/ad5504.c
drivers/iio/dac/ad5686.c
drivers/iio/dac/ad5758.c
drivers/iio/dac/ad5791.c
drivers/iio/dac/dpot-dac.c
drivers/iio/dac/ltc1660.c [new file with mode: 0644]
drivers/iio/dac/max517.c
drivers/iio/dac/max5821.c
drivers/iio/dac/mcp4725.c
drivers/iio/dac/mcp4922.c
drivers/iio/dac/ti-dac5571.c
drivers/iio/frequency/ad9523.c
drivers/iio/frequency/adf4350.c
drivers/iio/health/max30102.c
drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
drivers/iio/imu/st_lsm6dsx/Kconfig
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_i2c.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
drivers/iio/light/bh1750.c
drivers/iio/light/max44000.c
drivers/iio/light/tsl2772.c
drivers/iio/multiplexer/iio-mux.c
drivers/iio/potentiometer/max5481.c
drivers/iio/potentiometer/mcp4018.c
drivers/iio/potentiometer/mcp4531.c
drivers/iio/pressure/ms5611.h
drivers/iio/pressure/ms5611_core.c
drivers/iio/pressure/ms5611_i2c.c
drivers/iio/pressure/ms5611_spi.c
drivers/iio/proximity/isl29501.c
drivers/iio/trigger/iio-trig-sysfs.c
drivers/staging/iio/adc/ad7192.c
drivers/staging/iio/adc/ad7280a.c
drivers/staging/iio/adc/ad7606.c
drivers/staging/iio/adc/ad7606_par.c
drivers/staging/iio/adc/ad7606_spi.c
drivers/staging/iio/adc/ad7780.c
drivers/staging/iio/cdc/ad7746.c
drivers/staging/iio/frequency/ad9832.c
drivers/staging/iio/frequency/ad9834.c
drivers/staging/iio/impedance-analyzer/ad5933.c
include/dt-bindings/iio/qcom,spmi-vadc.h

index a5b4f223641d909cac3bd09777a9502840530f13..8127a08e366d8f96b05f0dacf71cd55634f68a1d 100644 (file)
@@ -199,7 +199,7 @@ Description:
 
 What:          /sys/bus/iio/devices/iio:deviceX/in_positionrelative_x_raw
 What:          /sys/bus/iio/devices/iio:deviceX/in_positionrelative_y_raw
-KernelVersion: 4.18
+KernelVersion: 4.19
 Contact:       linux-iio@vger.kernel.org
 Description:
                Relative position in direction x or y on a pad (may be
diff --git a/Documentation/devicetree/bindings/iio/accel/adxl372.txt b/Documentation/devicetree/bindings/iio/accel/adxl372.txt
new file mode 100644 (file)
index 0000000..a289964
--- /dev/null
@@ -0,0 +1,33 @@
+Analog Devices ADXL372 3-Axis, +/-(200g) Digital Accelerometer
+
+http://www.analog.com/media/en/technical-documentation/data-sheets/adxl372.pdf
+
+Required properties:
+ - compatible : should be "adi,adxl372"
+ - reg: the I2C address or SPI chip select number for the device
+
+Required properties for SPI bus usage:
+ - spi-max-frequency: Max SPI frequency to use
+
+Optional properties:
+ - interrupts: interrupt mapping for IRQ as documented in
+   Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+Example for a I2C device node:
+
+       accelerometer@53 {
+               compatible = "adi,adxl372";
+               reg = <0x53>;
+               interrupt-parent = <&gpio>;
+               interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
+
+Example for a SPI device node:
+
+       accelerometer@0 {
+               compatible = "adi,adxl372";
+               reg = <0>;
+               spi-max-frequency = <1000000>;
+               interrupt-parent = <&gpio>;
+               interrupts = <25 IRQ_TYPE_EDGE_FALLING>;
+       };
diff --git a/Documentation/devicetree/bindings/iio/adc/mcp3911.txt b/Documentation/devicetree/bindings/iio/adc/mcp3911.txt
new file mode 100644 (file)
index 0000000..3071f48
--- /dev/null
@@ -0,0 +1,30 @@
+* Microchip MCP3911 Dual channel analog front end (ADC)
+
+Required properties:
+ - compatible: Should be "microchip,mcp3911"
+ - reg: SPI chip select number for the device
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+        Documentation/devicetree/bindings/spi/spi-bus.txt.
+        Max frequency for this chip is 20MHz.
+
+Optional properties:
+ - clocks: Phandle and clock identifier for sampling clock
+ - interrupt-parent: Phandle to the parent interrupt controller
+ - interrupts: IRQ line for the ADC
+ - microchip,device-addr: Device address when multiple MCP3911 chips are present on the
+       same SPI bus. Valid values are 0-3. Defaults to 0.
+ - vref-supply: Phandle to the external reference voltage supply.
+
+Example:
+adc@0 {
+       compatible = "microchip,mcp3911";
+       reg = <0>;
+       interrupt-parent = <&gpio5>;
+       interrupts = <15 IRQ_TYPE_EDGE_RISING>;
+       spi-max-frequency = <20000000>;
+       microchip,device-addr = <0>;
+       vref-supply = <&vref_reg>;
+       clocks = <&xtal>;
+};
index 0fb46137f9369c5c5e94080356e326e450551c06..b3c86f4ac7cdb95ee6674017aecc45fa422294a9 100644 (file)
@@ -1,7 +1,9 @@
-Qualcomm's SPMI PMIC voltage ADC
+Qualcomm's SPMI PMIC ADC
 
-SPMI PMIC voltage ADC (VADC) provides interface to clients to read
-voltage. The VADC is a 15-bit sigma-delta ADC.
+- SPMI PMIC voltage ADC (VADC) provides interface to clients to read
+  voltage. The VADC is a 15-bit sigma-delta ADC.
+- SPMI PMIC5 voltage ADC (ADC) provides interface to clients to read
+  voltage. The VADC is a 16-bit sigma-delta ADC.
 
 VADC node:
 
@@ -9,11 +11,13 @@ VADC node:
     Usage: required
     Value type: <string>
     Definition: Should contain "qcom,spmi-vadc".
+                Should contain "qcom,spmi-adc5" for PMIC5 ADC driver.
+                Should contain "qcom,spmi-adc-rev2" for PMIC rev2 ADC driver.
 
 - reg:
     Usage: required
     Value type: <prop-encoded-array>
-    Definition: VADC base address and length in the SPMI PMIC register map.
+    Definition: VADC base address in the SPMI PMIC register map.
 
 - #address-cells:
     Usage: required
@@ -45,13 +49,26 @@ Channel node properties:
     Definition: ADC channel number.
             See include/dt-bindings/iio/qcom,spmi-vadc.h
 
+- label:
+    Usage: required for "qcom,spmi-adc5" and "qcom,spmi-adc-rev2"
+    Value type: <empty>
+    Definition: ADC input of the platform as seen in the schematics.
+            For thermistor inputs connected to generic AMUX or GPIO inputs
+            these can vary across platform for the same pins. Hence select
+            the platform schematics name for this channel.
+
 - qcom,decimation:
     Usage: optional
     Value type: <u32>
     Definition: This parameter is used to decrease ADC sampling rate.
             Quicker measurements can be made by reducing decimation ratio.
-            Valid values are 512, 1024, 2048, 4096.
-            If property is not found, default value of 512 will be used.
+            - For compatible property "qcom,spmi-vadc", valid values are
+              512, 1024, 2048, 4096. If property is not found, default value
+              of 512 will be used.
+            - For compatible property "qcom,spmi-adc5", valid values are 250, 420
+              and 840. If property is not found, default value of 840 is used.
+            - For compatible property "qcom,spmi-adc-rev2", valid values are 256,
+              512 and 1024. If property is not present, default value is 1024.
 
 - qcom,pre-scaling:
     Usage: optional
@@ -66,21 +83,38 @@ Channel node properties:
 - qcom,ratiometric:
     Usage: optional
     Value type: <empty>
-    Definition: Channel calibration type. If this property is specified
-            VADC will use the VDD reference (1.8V) and GND for channel
-            calibration. If property is not found, channel will be
-            calibrated with 0.625V and 1.25V reference channels, also
-            known as absolute calibration.
+    Definition: Channel calibration type.
+            - For compatible property "qcom,spmi-vadc", if this property is
+              specified VADC will use the VDD reference (1.8V) and GND for
+              channel calibration. If property is not found, channel will be
+              calibrated with 0.625V and 1.25V reference channels, also
+              known as absolute calibration.
+            - For compatible property "qcom,spmi-adc5" and "qcom,spmi-adc-rev2",
+              if this property is specified VADC will use the VDD reference
+              (1.875V) and GND for channel calibration. If property is not found,
+              channel will be calibrated with 0V and 1.25V reference channels,
+              also known as absolute calibration.
 
 - qcom,hw-settle-time:
     Usage: optional
     Value type: <u32>
     Definition: Time between AMUX getting configured and the ADC starting
-            conversion. Delay = 100us * (value) for value < 11, and
-            2ms * (value - 10) otherwise.
-            Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800,
-            900 us and 1, 2, 4, 6, 8, 10 ms
-            If property is not found, channel will use 0us.
+            conversion. The 'hw_settle_time' is an index used from valid values
+            and programmed in hardware to achieve the hardware settling delay.
+            - For compatible property "qcom,spmi-vadc" and "qcom,spmi-adc-rev2",
+              Delay = 100us * (hw_settle_time) for hw_settle_time < 11,
+              and 2ms * (hw_settle_time - 10) otherwise.
+              Valid values are: 0, 100, 200, 300, 400, 500, 600, 700, 800,
+              900 us and 1, 2, 4, 6, 8, 10 ms.
+              If property is not found, channel will use 0us.
+            - For compatible property "qcom,spmi-adc5", delay = 15us for
+              value 0, 100us * (value) for values < 11,
+              and 2ms * (value - 10) otherwise.
+              Valid values are: 15, 100, 200, 300, 400, 500, 600, 700, 800,
+              900 us and 1, 2, 4, 6, 8, 10 ms
+              Certain controller digital versions have valid values of
+              15, 100, 200, 300, 400, 500, 600, 700, 1, 2, 4, 8, 16, 32, 64, 128 ms
+              If property is not found, channel will use 15us.
 
 - qcom,avg-samples:
     Usage: optional
@@ -89,13 +123,18 @@ Channel node properties:
             Averaging provides the option to obtain a single measurement
             from the ADC that is an average of multiple samples. The value
             selected is 2^(value).
-            Valid values are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
-            If property is not found, 1 sample will be used.
+            - For compatible property "qcom,spmi-vadc", valid values
+              are: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
+              If property is not found, 1 sample will be used.
+            - For compatible property "qcom,spmi-adc5" and "qcom,spmi-adc-rev2",
+              valid values are: 1, 2, 4, 8, 16
+              If property is not found, 1 sample will be used.
 
 NOTE:
 
-Following channels, also known as reference point channels, are used for
-result calibration and their channel configuration nodes should be defined:
+For compatible property "qcom,spmi-vadc" following channels, also known as
+reference point channels, are used for result calibration and their channel
+configuration nodes should be defined:
 VADC_REF_625MV and/or VADC_SPARE1(based on PMIC version) VADC_REF_1250MV,
 VADC_GND_REF and VADC_VDD_VADC.
 
@@ -104,7 +143,7 @@ Example:
        /* VADC node */
        pmic_vadc: vadc@3100 {
                compatible = "qcom,spmi-vadc";
-               reg = <0x3100 0x100>;
+               reg = <0x3100>;
                interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>;
                #address-cells = <1>;
                #size-cells = <0>;
index 8aad960de50bebdecd95ebbc899a4f9844804184..b4daa15dcf15f07d2fa2690e159d0501c27c6900 100644 (file)
@@ -12,6 +12,8 @@ Required properties:
 - interrupts: The interrupt number for the ADC device.
 - #io-channel-cells: Number of cells in an IIO specifier.
 - hwlocks: Reference to a phandle of a hwlock provider node.
+- nvmem-cells: A phandle to the calibration cells provided by eFuse device.
+- nvmem-cell-names: Should be "big_scale_calib", "small_scale_calib".
 
 Example:
 
@@ -32,5 +34,7 @@ Example:
                        interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
                        #io-channel-cells = <1>;
                        hwlocks = <&hwlock 4>;
+                       nvmem-cells = <&adc_big_scale>, <&adc_small_scale>;
+                       nvmem-cell-names = "big_scale_calib", "small_scale_calib";
                };
        };
index bba01a5cab1bad1a4ce5ca43f8fbe9ddd8fe3bf6..2f607f41f9d3139c1cebd4ef7a8c80a1abf4ea74 100644 (file)
@@ -50,6 +50,9 @@ Required properties:
 
 Optional properties:
 
+ - reset-gpios : GPIO spec for the RESET pin. If specified, it will be
+                asserted during driver probe.
+
  - adi,dc-dc-ilim-microamp: The dc-to-dc converter current limit
                   The following values are currently supported [uA]:
                        * 150000
@@ -71,6 +74,8 @@ AD5758 Example:
                spi-max-frequency = <1000000>;
                spi-cpha;
 
+               reset-gpios = <&gpio 22 0>;
+
                adi,dc-dc-mode = <2>;
                adi,range-microvolt = <0 10000000>;
                adi,dc-dc-ilim-microamp = <200000>;
diff --git a/Documentation/devicetree/bindings/iio/dac/ltc1660.txt b/Documentation/devicetree/bindings/iio/dac/ltc1660.txt
new file mode 100644 (file)
index 0000000..c5b5f22
--- /dev/null
@@ -0,0 +1,21 @@
+* Linear Technology Micropower octal 8-Bit and 10-Bit DACs
+
+Required properties:
+ - compatible: Must be one of the following:
+               "lltc,ltc1660"
+               "lltc,ltc1665"
+ - reg: SPI chip select number for the device
+ - vref-supply: Phandle to the voltage reference supply
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+        Documentation/devicetree/bindings/spi/spi-bus.txt.
+        Max frequency for this chip is 5 MHz.
+
+Example:
+dac@0 {
+       compatible = "lltc,ltc1660";
+       reg = <0>;
+       spi-max-frequency = <5000000>;
+       vref-supply = <&vref_reg>;
+};
index b2f27da847b88a23fd6c6642a9ee5f3f0a6789ba..6ab9a9d196b06f3600b1ad183dadfb5b194250c3 100644 (file)
@@ -20,6 +20,7 @@ Required properties:
   bindings.
 
 Optional properties:
+ - vddio-supply: regulator phandle for VDDIO supply
  - mount-matrix: an optional 3x3 mounting rotation matrix
  - i2c-gate node.  These devices also support an auxiliary i2c bus.  This is
    simple enough to be described using the i2c-gate binding. See
index ea2d6e0ae4c593be794ee2a948943dc6cc91fb04..879322ad50fdd2dcee6a30808e687f8994e3e2b7 100644 (file)
@@ -7,6 +7,7 @@ Required properties:
   "st,lsm6dsl"
   "st,lsm6dsm"
   "st,ism330dlc"
+  "st,lsm6dso"
 - reg: i2c address of the sensor / spi cs line
 
 Optional properties:
diff --git a/Documentation/devicetree/bindings/iio/light/tsl2772.txt b/Documentation/devicetree/bindings/iio/light/tsl2772.txt
new file mode 100644 (file)
index 0000000..1c5e6f1
--- /dev/null
@@ -0,0 +1,42 @@
+* AMS/TAOS ALS and proximity sensor
+
+Required properties:
+
+  - compatible: Should be one of
+               "amstaos,tsl2571"
+               "amstaos,tsl2671"
+               "amstaos,tmd2671"
+               "amstaos,tsl2771"
+               "amstaos,tmd2771"
+               "amstaos,tsl2572"
+               "amstaos,tsl2672"
+               "amstaos,tmd2672"
+               "amstaos,tsl2772"
+               "amstaos,tmd2772"
+               "avago,apds9930"
+  - reg: the I2C address of the device
+
+Optional properties:
+
+  - amstaos,proximity-diodes - proximity diodes to enable. <0>, <1>, or <0 1>
+                               are the only valid values.
+  - led-max-microamp - current for the proximity LED. Must be 100000, 50000,
+                       25000, or 13000.
+  - vdd-supply: phandle to the regulator that provides power to the sensor.
+  - vddio-supply: phandle to the regulator that provides power to the bus.
+  - interrupts: the sole interrupt generated by the device
+
+  Refer to interrupt-controller/interrupts.txt for generic interrupt client
+  node bindings.
+
+Example:
+
+tsl2772@39 {
+       compatible = "amstaos,tsl2772";
+       reg = <0x39>;
+       interrupts-extended = <&msmgpio 61 IRQ_TYPE_EDGE_FALLING>;
+       vdd-supply = <&pm8941_l17>;
+       vddio-supply = <&pm8941_lvs1>;
+       amstaos,proximity-diodes = <0>;
+       led-max-microamp = <100000>;
+};
index 763a2808a95c806a278111686cc75227f971f08d..a977ccef7230947958e17d12172dd865f8c27b75 100644 (file)
@@ -21,16 +21,6 @@ adi,adt7490          +/-1C TDM Extended Temp Range I.C
 adi,adxl345            Three-Axis Digital Accelerometer
 adi,adxl346            Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
 ams,iaq-core           AMS iAQ-Core VOC Sensor
-amstaos,tsl2571                AMS/TAOS ALS and proximity sensor
-amstaos,tsl2671                AMS/TAOS ALS and proximity sensor
-amstaos,tmd2671                AMS/TAOS ALS and proximity sensor
-amstaos,tsl2771                AMS/TAOS ALS and proximity sensor
-amstaos,tmd2771                AMS/TAOS ALS and proximity sensor
-amstaos,tsl2572                AMS/TAOS ALS and proximity sensor
-amstaos,tsl2672                AMS/TAOS ALS and proximity sensor
-amstaos,tmd2672                AMS/TAOS ALS and proximity sensor
-amstaos,tsl2772                AMS/TAOS ALS and proximity sensor
-amstaos,tmd2772                AMS/TAOS ALS and proximity sensor
 at,24c08               i2c serial eeprom  (24cxx)
 atmel,at97sc3204t      i2c trusted platform module (TPM)
 capella,cm32181                CM32181: Ambient Light Sensor
index a5b256b259057c564f76c508e0fcf648e47938d7..e483d8a06fcdeee39c7036700f7ffec00c0a1756 100644 (file)
@@ -550,6 +550,15 @@ W: http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/misc/adxl34x.c
 
+ADXL372 THREE-AXIS DIGITAL ACCELEROMETER DRIVER
+M:     Stefan Popa <stefan.popa@analog.com>
+W:     http://ez.analog.com/community/linux-device-drivers
+S:     Supported
+F:     drivers/iio/accel/adxl372.c
+F:     drivers/iio/accel/adxl372_spi.c
+F:     drivers/iio/accel/adxl372_i2c.c
+F:     Documentation/devicetree/bindings/iio/accel/adxl372.txt
+
 AF9013 MEDIA DRIVER
 M:     Antti Palosaari <crope@iki.fi>
 L:     linux-media@vger.kernel.org
@@ -8614,6 +8623,13 @@ L:       linux-scsi@vger.kernel.org
 S:     Maintained
 F:     drivers/scsi/sym53c8xx_2/
 
+LTC1660 DAC DRIVER
+M:     Marcus Folkesson <marcus.folkesson@gmail.com>
+L:     linux-iio@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/iio/dac/ltc1660.txt
+F:     drivers/iio/dac/ltc1660.c
+
 LTC4261 HARDWARE MONITOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
@@ -9550,6 +9566,14 @@ L:       netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/ethernet/microchip/lan743x_*
 
+MICROCHIP / ATMEL MCP3911 ADC DRIVER
+M:     Marcus Folkesson <marcus.folkesson@gmail.com>
+M:     Kent Gustavsson <kent@minoris.se>
+L:     linux-iio@vger.kernel.org
+S:     Supported
+F:     drivers/iio/adc/mcp3911.c
+F:     Documentation/devicetree/bindings/iio/adc/mcp3911.txt
+
 MICROCHIP USB251XB DRIVER
 M:     Richard Leitner <richard.leitner@skidata.com>
 L:     linux-usb@vger.kernel.org
index 829dc96c9dd6fe527a616bd3c1b14f768192223c..7993a67bd35156e3aed7586cd666d93eb9854b7b 100644 (file)
@@ -60,6 +60,33 @@ config ADXL345_SPI
          will be called adxl345_spi and you will also get adxl345_core
          for the core module.
 
+config ADXL372
+       tristate
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+
+config ADXL372_SPI
+       tristate "Analog Devices ADXL372 3-Axis Accelerometer SPI Driver"
+       depends on SPI
+       select ADXL372
+       select REGMAP_SPI
+       help
+         Say yes here to add support for the Analog Devices ADXL372 triaxial
+         acceleration sensor.
+         To compile this driver as a module, choose M here: the
+         module will be called adxl372_spi.
+
+config ADXL372_I2C
+       tristate "Analog Devices ADXL372 3-Axis Accelerometer I2C Driver"
+       depends on I2C
+       select ADXL372
+       select REGMAP_I2C
+       help
+         Say yes here to add support for the Analog Devices ADXL372 triaxial
+         acceleration sensor.
+         To compile this driver as a module, choose M here: the
+         module will be called adxl372_i2c.
+
 config BMA180
        tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver"
        depends on I2C
index 636d4d1b2990b70e703c22ca687af78016be03c3..56bd0215e0d4ded1be403b07b26d1aa4a3855305 100644 (file)
@@ -9,6 +9,9 @@ obj-$(CONFIG_ADIS16209) += adis16209.o
 obj-$(CONFIG_ADXL345) += adxl345_core.o
 obj-$(CONFIG_ADXL345_I2C) += adxl345_i2c.o
 obj-$(CONFIG_ADXL345_SPI) += adxl345_spi.o
+obj-$(CONFIG_ADXL372) += adxl372.o
+obj-$(CONFIG_ADXL372_I2C) += adxl372_i2c.o
+obj-$(CONFIG_ADXL372_SPI) += adxl372_spi.o
 obj-$(CONFIG_BMA180) += bma180.o
 obj-$(CONFIG_BMA220) += bma220_spi.o
 obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
index 785c89de91e7b28373addfcdda7c975147027d3d..f22f71315a0cdb912ffef6d5ed70adcfcfb7b71d 100644 (file)
@@ -27,6 +27,9 @@ static int adxl345_i2c_probe(struct i2c_client *client,
 {
        struct regmap *regmap;
 
+       if (!id)
+               return -ENODEV;
+
        regmap = devm_regmap_init_i2c(client, &adxl345_i2c_regmap_config);
        if (IS_ERR(regmap)) {
                dev_err(&client->dev, "Error initializing i2c regmap: %ld\n",
@@ -35,7 +38,7 @@ static int adxl345_i2c_probe(struct i2c_client *client,
        }
 
        return adxl345_core_probe(&client->dev, regmap, id->driver_data,
-                                 id ? id->name : NULL);
+                                 id->name);
 }
 
 static int adxl345_i2c_remove(struct i2c_client *client)
diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c
new file mode 100644 (file)
index 0000000..3b84cb2
--- /dev/null
@@ -0,0 +1,975 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADXL372 3-Axis Digital Accelerometer core driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#include "adxl372.h"
+
+/* ADXL372 registers definition */
+#define ADXL372_DEVID                  0x00
+#define ADXL372_DEVID_MST              0x01
+#define ADXL372_PARTID                 0x02
+#define ADXL372_STATUS_1               0x04
+#define ADXL372_STATUS_2               0x05
+#define ADXL372_FIFO_ENTRIES_2         0x06
+#define ADXL372_FIFO_ENTRIES_1         0x07
+#define ADXL372_X_DATA_H               0x08
+#define ADXL372_X_DATA_L               0x09
+#define ADXL372_Y_DATA_H               0x0A
+#define ADXL372_Y_DATA_L               0x0B
+#define ADXL372_Z_DATA_H               0x0C
+#define ADXL372_Z_DATA_L               0x0D
+#define ADXL372_X_MAXPEAK_H            0x15
+#define ADXL372_X_MAXPEAK_L            0x16
+#define ADXL372_Y_MAXPEAK_H            0x17
+#define ADXL372_Y_MAXPEAK_L            0x18
+#define ADXL372_Z_MAXPEAK_H            0x19
+#define ADXL372_Z_MAXPEAK_L            0x1A
+#define ADXL372_OFFSET_X               0x20
+#define ADXL372_OFFSET_Y               0x21
+#define ADXL372_OFFSET_Z               0x22
+#define ADXL372_X_THRESH_ACT_H         0x23
+#define ADXL372_X_THRESH_ACT_L         0x24
+#define ADXL372_Y_THRESH_ACT_H         0x25
+#define ADXL372_Y_THRESH_ACT_L         0x26
+#define ADXL372_Z_THRESH_ACT_H         0x27
+#define ADXL372_Z_THRESH_ACT_L         0x28
+#define ADXL372_TIME_ACT               0x29
+#define ADXL372_X_THRESH_INACT_H       0x2A
+#define ADXL372_X_THRESH_INACT_L       0x2B
+#define ADXL372_Y_THRESH_INACT_H       0x2C
+#define ADXL372_Y_THRESH_INACT_L       0x2D
+#define ADXL372_Z_THRESH_INACT_H       0x2E
+#define ADXL372_Z_THRESH_INACT_L       0x2F
+#define ADXL372_TIME_INACT_H           0x30
+#define ADXL372_TIME_INACT_L           0x31
+#define ADXL372_X_THRESH_ACT2_H                0x32
+#define ADXL372_X_THRESH_ACT2_L                0x33
+#define ADXL372_Y_THRESH_ACT2_H                0x34
+#define ADXL372_Y_THRESH_ACT2_L                0x35
+#define ADXL372_Z_THRESH_ACT2_H                0x36
+#define ADXL372_Z_THRESH_ACT2_L                0x37
+#define ADXL372_HPF                    0x38
+#define ADXL372_FIFO_SAMPLES           0x39
+#define ADXL372_FIFO_CTL               0x3A
+#define ADXL372_INT1_MAP               0x3B
+#define ADXL372_INT2_MAP               0x3C
+#define ADXL372_TIMING                 0x3D
+#define ADXL372_MEASURE                        0x3E
+#define ADXL372_POWER_CTL              0x3F
+#define ADXL372_SELF_TEST              0x40
+#define ADXL372_RESET                  0x41
+#define ADXL372_FIFO_DATA              0x42
+
+#define ADXL372_DEVID_VAL              0xAD
+#define ADXL372_PARTID_VAL             0xFA
+#define ADXL372_RESET_CODE             0x52
+
+/* ADXL372_POWER_CTL */
+#define ADXL372_POWER_CTL_MODE_MSK             GENMASK_ULL(1, 0)
+#define ADXL372_POWER_CTL_MODE(x)              (((x) & 0x3) << 0)
+
+/* ADXL372_MEASURE */
+#define ADXL372_MEASURE_LINKLOOP_MSK           GENMASK_ULL(5, 4)
+#define ADXL372_MEASURE_LINKLOOP_MODE(x)       (((x) & 0x3) << 4)
+#define ADXL372_MEASURE_BANDWIDTH_MSK          GENMASK_ULL(2, 0)
+#define ADXL372_MEASURE_BANDWIDTH_MODE(x)      (((x) & 0x7) << 0)
+
+/* ADXL372_TIMING */
+#define ADXL372_TIMING_ODR_MSK                 GENMASK_ULL(7, 5)
+#define ADXL372_TIMING_ODR_MODE(x)             (((x) & 0x7) << 5)
+
+/* ADXL372_FIFO_CTL */
+#define ADXL372_FIFO_CTL_FORMAT_MSK            GENMASK(5, 3)
+#define ADXL372_FIFO_CTL_FORMAT_MODE(x)                (((x) & 0x7) << 3)
+#define ADXL372_FIFO_CTL_MODE_MSK              GENMASK(2, 1)
+#define ADXL372_FIFO_CTL_MODE_MODE(x)          (((x) & 0x3) << 1)
+#define ADXL372_FIFO_CTL_SAMPLES_MSK           BIT(1)
+#define ADXL372_FIFO_CTL_SAMPLES_MODE(x)       (((x) > 0xFF) ? 1 : 0)
+
+/* ADXL372_STATUS_1 */
+#define ADXL372_STATUS_1_DATA_RDY(x)           (((x) >> 0) & 0x1)
+#define ADXL372_STATUS_1_FIFO_RDY(x)           (((x) >> 1) & 0x1)
+#define ADXL372_STATUS_1_FIFO_FULL(x)          (((x) >> 2) & 0x1)
+#define ADXL372_STATUS_1_FIFO_OVR(x)           (((x) >> 3) & 0x1)
+#define ADXL372_STATUS_1_USR_NVM_BUSY(x)       (((x) >> 5) & 0x1)
+#define ADXL372_STATUS_1_AWAKE(x)              (((x) >> 6) & 0x1)
+#define ADXL372_STATUS_1_ERR_USR_REGS(x)       (((x) >> 7) & 0x1)
+
+/* ADXL372_INT1_MAP */
+#define ADXL372_INT1_MAP_DATA_RDY_MSK          BIT(0)
+#define ADXL372_INT1_MAP_DATA_RDY_MODE(x)      (((x) & 0x1) << 0)
+#define ADXL372_INT1_MAP_FIFO_RDY_MSK          BIT(1)
+#define ADXL372_INT1_MAP_FIFO_RDY_MODE(x)      (((x) & 0x1) << 1)
+#define ADXL372_INT1_MAP_FIFO_FULL_MSK         BIT(2)
+#define ADXL372_INT1_MAP_FIFO_FULL_MODE(x)     (((x) & 0x1) << 2)
+#define ADXL372_INT1_MAP_FIFO_OVR_MSK          BIT(3)
+#define ADXL372_INT1_MAP_FIFO_OVR_MODE(x)      (((x) & 0x1) << 3)
+#define ADXL372_INT1_MAP_INACT_MSK             BIT(4)
+#define ADXL372_INT1_MAP_INACT_MODE(x)         (((x) & 0x1) << 4)
+#define ADXL372_INT1_MAP_ACT_MSK               BIT(5)
+#define ADXL372_INT1_MAP_ACT_MODE(x)           (((x) & 0x1) << 5)
+#define ADXL372_INT1_MAP_AWAKE_MSK             BIT(6)
+#define ADXL372_INT1_MAP_AWAKE_MODE(x)         (((x) & 0x1) << 6)
+#define ADXL372_INT1_MAP_LOW_MSK               BIT(7)
+#define ADXL372_INT1_MAP_LOW_MODE(x)           (((x) & 0x1) << 7)
+
+/* The ADXL372 includes a deep, 512 sample FIFO buffer */
+#define ADXL372_FIFO_SIZE                      512
+
+/*
+ * At +/- 200g with 12-bit resolution, scale is computed as:
+ * (200 + 200) * 9.81 / (2^12 - 1) = 0.958241
+ */
+#define ADXL372_USCALE 958241
+
+enum adxl372_op_mode {
+       ADXL372_STANDBY,
+       ADXL372_WAKE_UP,
+       ADXL372_INSTANT_ON,
+       ADXL372_FULL_BW_MEASUREMENT,
+};
+
+enum adxl372_act_proc_mode {
+       ADXL372_DEFAULT,
+       ADXL372_LINKED,
+       ADXL372_LOOPED,
+};
+
+enum adxl372_th_activity {
+       ADXL372_ACTIVITY,
+       ADXL372_ACTIVITY2,
+       ADXL372_INACTIVITY,
+};
+
+enum adxl372_odr {
+       ADXL372_ODR_400HZ,
+       ADXL372_ODR_800HZ,
+       ADXL372_ODR_1600HZ,
+       ADXL372_ODR_3200HZ,
+       ADXL372_ODR_6400HZ,
+};
+
+enum adxl372_bandwidth {
+       ADXL372_BW_200HZ,
+       ADXL372_BW_400HZ,
+       ADXL372_BW_800HZ,
+       ADXL372_BW_1600HZ,
+       ADXL372_BW_3200HZ,
+};
+
+static const unsigned int adxl372_th_reg_high_addr[3] = {
+       [ADXL372_ACTIVITY] = ADXL372_X_THRESH_ACT_H,
+       [ADXL372_ACTIVITY2] = ADXL372_X_THRESH_ACT2_H,
+       [ADXL372_INACTIVITY] = ADXL372_X_THRESH_INACT_H,
+};
+
+enum adxl372_fifo_format {
+       ADXL372_XYZ_FIFO,
+       ADXL372_X_FIFO,
+       ADXL372_Y_FIFO,
+       ADXL372_XY_FIFO,
+       ADXL372_Z_FIFO,
+       ADXL372_XZ_FIFO,
+       ADXL372_YZ_FIFO,
+       ADXL372_XYZ_PEAK_FIFO,
+};
+
+enum adxl372_fifo_mode {
+       ADXL372_FIFO_BYPASSED,
+       ADXL372_FIFO_STREAMED,
+       ADXL372_FIFO_TRIGGERED,
+       ADXL372_FIFO_OLD_SAVED
+};
+
+static const int adxl372_samp_freq_tbl[5] = {
+       400, 800, 1600, 3200, 6400,
+};
+
+static const int adxl372_bw_freq_tbl[5] = {
+       200, 400, 800, 1600, 3200,
+};
+
+struct adxl372_axis_lookup {
+       unsigned int bits;
+       enum adxl372_fifo_format fifo_format;
+};
+
+static const struct adxl372_axis_lookup adxl372_axis_lookup_table[] = {
+       { BIT(0), ADXL372_X_FIFO },
+       { BIT(1), ADXL372_Y_FIFO },
+       { BIT(2), ADXL372_Z_FIFO },
+       { BIT(0) | BIT(1), ADXL372_XY_FIFO },
+       { BIT(0) | BIT(2), ADXL372_XZ_FIFO },
+       { BIT(1) | BIT(2), ADXL372_YZ_FIFO },
+       { BIT(0) | BIT(1) | BIT(2), ADXL372_XYZ_FIFO },
+};
+
+#define ADXL372_ACCEL_CHANNEL(index, reg, axis) {                      \
+       .type = IIO_ACCEL,                                              \
+       .address = reg,                                                 \
+       .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) |      \
+               BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),       \
+       .scan_index = index,                                            \
+       .scan_type = {                                                  \
+               .sign = 's',                                            \
+               .realbits = 12,                                         \
+               .storagebits = 16,                                      \
+               .shift = 4,                                             \
+       },                                                              \
+}
+
+static const struct iio_chan_spec adxl372_channels[] = {
+       ADXL372_ACCEL_CHANNEL(0, ADXL372_X_DATA_H, X),
+       ADXL372_ACCEL_CHANNEL(1, ADXL372_Y_DATA_H, Y),
+       ADXL372_ACCEL_CHANNEL(2, ADXL372_Z_DATA_H, Z),
+};
+
+struct adxl372_state {
+       int                             irq;
+       struct device                   *dev;
+       struct regmap                   *regmap;
+       struct iio_trigger              *dready_trig;
+       enum adxl372_fifo_mode          fifo_mode;
+       enum adxl372_fifo_format        fifo_format;
+       enum adxl372_op_mode            op_mode;
+       enum adxl372_act_proc_mode      act_proc_mode;
+       enum adxl372_odr                odr;
+       enum adxl372_bandwidth          bw;
+       u32                             act_time_ms;
+       u32                             inact_time_ms;
+       u8                              fifo_set_size;
+       u8                              int1_bitmask;
+       u8                              int2_bitmask;
+       u16                             watermark;
+       __be16                          fifo_buf[ADXL372_FIFO_SIZE];
+};
+
+static const unsigned long adxl372_channel_masks[] = {
+       BIT(0), BIT(1), BIT(2),
+       BIT(0) | BIT(1),
+       BIT(0) | BIT(2),
+       BIT(1) | BIT(2),
+       BIT(0) | BIT(1) | BIT(2),
+       0
+};
+
+static int adxl372_read_axis(struct adxl372_state *st, u8 addr)
+{
+       __be16 regval;
+       int ret;
+
+       ret = regmap_bulk_read(st->regmap, addr, &regval, sizeof(regval));
+       if (ret < 0)
+               return ret;
+
+       return be16_to_cpu(regval);
+}
+
+static int adxl372_set_op_mode(struct adxl372_state *st,
+                              enum adxl372_op_mode op_mode)
+{
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, ADXL372_POWER_CTL,
+                                ADXL372_POWER_CTL_MODE_MSK,
+                                ADXL372_POWER_CTL_MODE(op_mode));
+       if (ret < 0)
+               return ret;
+
+       st->op_mode = op_mode;
+
+       return ret;
+}
+
+static int adxl372_set_odr(struct adxl372_state *st,
+                          enum adxl372_odr odr)
+{
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, ADXL372_TIMING,
+                                ADXL372_TIMING_ODR_MSK,
+                                ADXL372_TIMING_ODR_MODE(odr));
+       if (ret < 0)
+               return ret;
+
+       st->odr = odr;
+
+       return ret;
+}
+
+static int adxl372_find_closest_match(const int *array,
+                                     unsigned int size, int val)
+{
+       int i;
+
+       for (i = 0; i < size; i++) {
+               if (val <= array[i])
+                       return i;
+       }
+
+       return size - 1;
+}
+
+static int adxl372_set_bandwidth(struct adxl372_state *st,
+                                enum adxl372_bandwidth bw)
+{
+       int ret;
+
+       ret = regmap_update_bits(st->regmap, ADXL372_MEASURE,
+                                ADXL372_MEASURE_BANDWIDTH_MSK,
+                                ADXL372_MEASURE_BANDWIDTH_MODE(bw));
+       if (ret < 0)
+               return ret;
+
+       st->bw = bw;
+
+       return ret;
+}
+
+static int adxl372_set_act_proc_mode(struct adxl372_state *st,
+                                    enum adxl372_act_proc_mode mode)
+{
+       int ret;
+
+       ret = regmap_update_bits(st->regmap,
+                                ADXL372_MEASURE,
+                                ADXL372_MEASURE_LINKLOOP_MSK,
+                                ADXL372_MEASURE_LINKLOOP_MODE(mode));
+       if (ret < 0)
+               return ret;
+
+       st->act_proc_mode = mode;
+
+       return ret;
+}
+
+static int adxl372_set_activity_threshold(struct adxl372_state *st,
+                                         enum adxl372_th_activity act,
+                                         bool ref_en, bool enable,
+                                         unsigned int threshold)
+{
+       unsigned char buf[6];
+       unsigned char th_reg_high_val, th_reg_low_val, th_reg_high_addr;
+
+       /* scale factor is 100 mg/code */
+       th_reg_high_val = (threshold / 100) >> 3;
+       th_reg_low_val = ((threshold / 100) << 5) | (ref_en << 1) | enable;
+       th_reg_high_addr = adxl372_th_reg_high_addr[act];
+
+       buf[0] = th_reg_high_val;
+       buf[1] = th_reg_low_val;
+       buf[2] = th_reg_high_val;
+       buf[3] = th_reg_low_val;
+       buf[4] = th_reg_high_val;
+       buf[5] = th_reg_low_val;
+
+       return regmap_bulk_write(st->regmap, th_reg_high_addr,
+                                buf, ARRAY_SIZE(buf));
+}
+
+static int adxl372_set_activity_time_ms(struct adxl372_state *st,
+                                       unsigned int act_time_ms)
+{
+       unsigned int reg_val, scale_factor;
+       int ret;
+
+       /*
+        * 3.3 ms per code is the scale factor of the TIME_ACT register for
+        * ODR = 6400 Hz. It is 6.6 ms per code for ODR = 3200 Hz and below.
+        */
+       if (st->odr == ADXL372_ODR_6400HZ)
+               scale_factor = 3300;
+       else
+               scale_factor = 6600;
+
+       reg_val = DIV_ROUND_CLOSEST(act_time_ms * 1000, scale_factor);
+
+       /* TIME_ACT register is 8 bits wide */
+       if (reg_val > 0xFF)
+               reg_val = 0xFF;
+
+       ret = regmap_write(st->regmap, ADXL372_TIME_ACT, reg_val);
+       if (ret < 0)
+               return ret;
+
+       st->act_time_ms = act_time_ms;
+
+       return ret;
+}
+
+static int adxl372_set_inactivity_time_ms(struct adxl372_state *st,
+                                         unsigned int inact_time_ms)
+{
+       unsigned int reg_val_h, reg_val_l, res, scale_factor;
+       int ret;
+
+       /*
+        * 13 ms per code is the scale factor of the TIME_INACT register for
+        * ODR = 6400 Hz. It is 26 ms per code for ODR = 3200 Hz and below.
+        */
+       if (st->odr == ADXL372_ODR_6400HZ)
+               scale_factor = 13;
+       else
+               scale_factor = 26;
+
+       res = DIV_ROUND_CLOSEST(inact_time_ms, scale_factor);
+       reg_val_h = (res >> 8) & 0xFF;
+       reg_val_l = res & 0xFF;
+
+       ret = regmap_write(st->regmap, ADXL372_TIME_INACT_H, reg_val_h);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADXL372_TIME_INACT_L, reg_val_l);
+       if (ret < 0)
+               return ret;
+
+       st->inact_time_ms = inact_time_ms;
+
+       return ret;
+}
+
+static int adxl372_set_interrupts(struct adxl372_state *st,
+                                 unsigned char int1_bitmask,
+                                 unsigned char int2_bitmask)
+{
+       int ret;
+
+       ret = regmap_write(st->regmap, ADXL372_INT1_MAP, int1_bitmask);
+       if (ret < 0)
+               return ret;
+
+       return regmap_write(st->regmap, ADXL372_INT2_MAP, int2_bitmask);
+}
+
+static int adxl372_configure_fifo(struct adxl372_state *st)
+{
+       unsigned int fifo_samples, fifo_ctl;
+       int ret;
+
+       /* FIFO must be configured while in standby mode */
+       ret = adxl372_set_op_mode(st, ADXL372_STANDBY);
+       if (ret < 0)
+               return ret;
+
+       fifo_samples = st->watermark & 0xFF;
+       fifo_ctl = ADXL372_FIFO_CTL_FORMAT_MODE(st->fifo_format) |
+                  ADXL372_FIFO_CTL_MODE_MODE(st->fifo_mode) |
+                  ADXL372_FIFO_CTL_SAMPLES_MODE(st->watermark);
+
+       ret = regmap_write(st->regmap, ADXL372_FIFO_SAMPLES, fifo_samples);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_write(st->regmap, ADXL372_FIFO_CTL, fifo_ctl);
+       if (ret < 0)
+               return ret;
+
+       return adxl372_set_op_mode(st, ADXL372_FULL_BW_MEASUREMENT);
+}
+
+static int adxl372_get_status(struct adxl372_state *st,
+                             u8 *status1, u8 *status2,
+                             u16 *fifo_entries)
+{
+       __be32 buf;
+       u32 val;
+       int ret;
+
+       /* STATUS1, STATUS2, FIFO_ENTRIES2 and FIFO_ENTRIES are adjacent regs */
+       ret = regmap_bulk_read(st->regmap, ADXL372_STATUS_1,
+                              &buf, sizeof(buf));
+       if (ret < 0)
+               return ret;
+
+       val = be32_to_cpu(buf);
+
+       *status1 = (val >> 24) & 0x0F;
+       *status2 = (val >> 16) & 0x0F;
+       /*
+        * FIFO_ENTRIES contains the least significant byte, and FIFO_ENTRIES2
+        * contains the two most significant bits
+        */
+       *fifo_entries = val & 0x3FF;
+
+       return ret;
+}
+
+static irqreturn_t adxl372_trigger_handler(int irq, void  *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct adxl372_state *st = iio_priv(indio_dev);
+       u8 status1, status2;
+       u16 fifo_entries;
+       int i, ret;
+
+       ret = adxl372_get_status(st, &status1, &status2, &fifo_entries);
+       if (ret < 0)
+               goto err;
+
+       if (st->fifo_mode != ADXL372_FIFO_BYPASSED &&
+           ADXL372_STATUS_1_FIFO_FULL(status1)) {
+               /*
+                * When reading data from multiple axes from the FIFO,
+                * to ensure that data is not overwritten and stored out
+                * of order at least one sample set must be left in the
+                * FIFO after every read.
+                */
+               fifo_entries -= st->fifo_set_size;
+
+               /* Read data from the FIFO */
+               ret = regmap_noinc_read(st->regmap, ADXL372_FIFO_DATA,
+                                       st->fifo_buf,
+                                       fifo_entries * sizeof(u16));
+               if (ret < 0)
+                       goto err;
+
+               /* Each sample is 2 bytes */
+               for (i = 0; i < fifo_entries * sizeof(u16);
+                    i += st->fifo_set_size * sizeof(u16))
+                       iio_push_to_buffers(indio_dev, &st->fifo_buf[i]);
+       }
+err:
+       iio_trigger_notify_done(indio_dev->trig);
+       return IRQ_HANDLED;
+}
+
+static int adxl372_setup(struct adxl372_state *st)
+{
+       unsigned int regval;
+       int ret;
+
+       ret = regmap_read(st->regmap, ADXL372_DEVID, &regval);
+       if (ret < 0)
+               return ret;
+
+       if (regval != ADXL372_DEVID_VAL) {
+               dev_err(st->dev, "Invalid chip id %x\n", regval);
+               return -ENODEV;
+       }
+
+       ret = adxl372_set_op_mode(st, ADXL372_STANDBY);
+       if (ret < 0)
+               return ret;
+
+       /* Set threshold for activity detection to 1g */
+       ret = adxl372_set_activity_threshold(st, ADXL372_ACTIVITY,
+                                            true, true, 1000);
+       if (ret < 0)
+               return ret;
+
+       /* Set threshold for inactivity detection to 100mg */
+       ret = adxl372_set_activity_threshold(st, ADXL372_INACTIVITY,
+                                            true, true, 100);
+       if (ret < 0)
+               return ret;
+
+       /* Set activity processing in Looped mode */
+       ret = adxl372_set_act_proc_mode(st, ADXL372_LOOPED);
+       if (ret < 0)
+               return ret;
+
+       ret = adxl372_set_odr(st, ADXL372_ODR_6400HZ);
+       if (ret < 0)
+               return ret;
+
+       ret = adxl372_set_bandwidth(st, ADXL372_BW_3200HZ);
+       if (ret < 0)
+               return ret;
+
+       /* Set activity timer to 1ms */
+       ret = adxl372_set_activity_time_ms(st, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Set inactivity timer to 10s */
+       ret = adxl372_set_inactivity_time_ms(st, 10000);
+       if (ret < 0)
+               return ret;
+
+       /* Set the mode of operation to full bandwidth measurement mode */
+       return adxl372_set_op_mode(st, ADXL372_FULL_BW_MEASUREMENT);
+}
+
+static int adxl372_reg_access(struct iio_dev *indio_dev,
+                             unsigned int reg,
+                             unsigned int writeval,
+                             unsigned int *readval)
+{
+       struct adxl372_state *st = iio_priv(indio_dev);
+
+       if (readval)
+               return regmap_read(st->regmap, reg, readval);
+       else
+               return regmap_write(st->regmap, reg, writeval);
+}
+
+static int adxl372_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long info)
+{
+       struct adxl372_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = adxl372_read_axis(st, chan->address);
+               iio_device_release_direct_mode(indio_dev);
+               if (ret < 0)
+                       return ret;
+
+               *val = sign_extend32(ret >> chan->scan_type.shift,
+                                    chan->scan_type.realbits - 1);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = ADXL372_USCALE;
+               return IIO_VAL_INT_PLUS_MICRO;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *val = adxl372_samp_freq_tbl[st->odr];
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               *val = adxl372_bw_freq_tbl[st->bw];
+               return IIO_VAL_INT;
+       }
+
+       return -EINVAL;
+}
+
+static int adxl372_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long info)
+{
+       struct adxl372_state *st = iio_priv(indio_dev);
+       int odr_index, bw_index, ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               odr_index = adxl372_find_closest_match(adxl372_samp_freq_tbl,
+                                       ARRAY_SIZE(adxl372_samp_freq_tbl),
+                                       val);
+               ret = adxl372_set_odr(st, odr_index);
+               if (ret < 0)
+                       return ret;
+               /*
+                * The timer period depends on the ODR selected.
+                * At 3200 Hz and below, it is 6.6 ms; at 6400 Hz, it is 3.3 ms
+                */
+               ret = adxl372_set_activity_time_ms(st, st->act_time_ms);
+               if (ret < 0)
+                       return ret;
+               /*
+                * The timer period depends on the ODR selected.
+                * At 3200 Hz and below, it is 26 ms; at 6400 Hz, it is 13 ms
+                */
+               ret = adxl372_set_inactivity_time_ms(st, st->inact_time_ms);
+               if (ret < 0)
+                       return ret;
+               /*
+                * The maximum bandwidth is constrained to at most half of
+                * the ODR to ensure that the Nyquist criteria is not violated
+                */
+               if (st->bw > odr_index)
+                       ret = adxl372_set_bandwidth(st, odr_index);
+
+               return ret;
+       case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+               bw_index = adxl372_find_closest_match(adxl372_bw_freq_tbl,
+                                       ARRAY_SIZE(adxl372_bw_freq_tbl),
+                                       val);
+               return adxl372_set_bandwidth(st, bw_index);
+       default:
+               return -EINVAL;
+       }
+}
+
+static ssize_t adxl372_show_filter_freq_avail(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct adxl372_state *st = iio_priv(indio_dev);
+       int i;
+       size_t len = 0;
+
+       for (i = 0; i <= st->odr; i++)
+               len += scnprintf(buf + len, PAGE_SIZE - len,
+                                "%d ", adxl372_bw_freq_tbl[i]);
+
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static ssize_t adxl372_get_fifo_enabled(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct adxl372_state *st = iio_priv(indio_dev);
+
+       return sprintf(buf, "%d\n", st->fifo_mode);
+}
+
+static ssize_t adxl372_get_fifo_watermark(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct adxl372_state *st = iio_priv(indio_dev);
+
+       return sprintf(buf, "%d\n", st->watermark);
+}
+
+static IIO_CONST_ATTR(hwfifo_watermark_min, "1");
+static IIO_CONST_ATTR(hwfifo_watermark_max,
+                     __stringify(ADXL372_FIFO_SIZE));
+static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
+                      adxl372_get_fifo_watermark, NULL, 0);
+static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
+                      adxl372_get_fifo_enabled, NULL, 0);
+
+static const struct attribute *adxl372_fifo_attributes[] = {
+       &iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
+       &iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
+       &iio_dev_attr_hwfifo_watermark.dev_attr.attr,
+       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+       NULL,
+};
+
+static int adxl372_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+       struct adxl372_state *st  = iio_priv(indio_dev);
+
+       if (val > ADXL372_FIFO_SIZE)
+               val = ADXL372_FIFO_SIZE;
+
+       st->watermark = val;
+
+       return 0;
+}
+
+static int adxl372_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct adxl372_state *st = iio_priv(indio_dev);
+       unsigned int mask;
+       int i, ret;
+
+       ret = adxl372_set_interrupts(st, ADXL372_INT1_MAP_FIFO_FULL_MSK, 0);
+       if (ret < 0)
+               return ret;
+
+       mask = *indio_dev->active_scan_mask;
+
+       for (i = 0; i < ARRAY_SIZE(adxl372_axis_lookup_table); i++) {
+               if (mask == adxl372_axis_lookup_table[i].bits)
+                       break;
+       }
+
+       if (i == ARRAY_SIZE(adxl372_axis_lookup_table))
+               return -EINVAL;
+
+       st->fifo_format = adxl372_axis_lookup_table[i].fifo_format;
+       st->fifo_set_size = bitmap_weight(indio_dev->active_scan_mask,
+                                         indio_dev->masklength);
+       /*
+        * The 512 FIFO samples can be allotted in several ways, such as:
+        * 170 sample sets of concurrent 3-axis data
+        * 256 sample sets of concurrent 2-axis data (user selectable)
+        * 512 sample sets of single-axis data
+        */
+       if ((st->watermark * st->fifo_set_size) > ADXL372_FIFO_SIZE)
+               st->watermark = (ADXL372_FIFO_SIZE  / st->fifo_set_size);
+
+       st->fifo_mode = ADXL372_FIFO_STREAMED;
+
+       ret = adxl372_configure_fifo(st);
+       if (ret < 0) {
+               st->fifo_mode = ADXL372_FIFO_BYPASSED;
+               adxl372_set_interrupts(st, 0, 0);
+               return ret;
+       }
+
+       return iio_triggered_buffer_postenable(indio_dev);
+}
+
+static int adxl372_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct adxl372_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = iio_triggered_buffer_predisable(indio_dev);
+       if (ret < 0)
+               return ret;
+
+       adxl372_set_interrupts(st, 0, 0);
+       st->fifo_mode = ADXL372_FIFO_BYPASSED;
+       adxl372_configure_fifo(st);
+
+       return 0;
+}
+
+static const struct iio_buffer_setup_ops adxl372_buffer_ops = {
+       .postenable = adxl372_buffer_postenable,
+       .predisable = adxl372_buffer_predisable,
+};
+
+static int adxl372_dready_trig_set_state(struct iio_trigger *trig,
+                                        bool state)
+{
+       struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+       struct adxl372_state *st = iio_priv(indio_dev);
+       unsigned long int mask = 0;
+
+       if (state)
+               mask = ADXL372_INT1_MAP_FIFO_FULL_MSK;
+
+       return adxl372_set_interrupts(st, mask, 0);
+}
+
+static int adxl372_validate_trigger(struct iio_dev *indio_dev,
+                                   struct iio_trigger *trig)
+{
+       struct adxl372_state *st = iio_priv(indio_dev);
+
+       if (st->dready_trig != trig)
+               return -EINVAL;
+
+       return 0;
+}
+
+static const struct iio_trigger_ops adxl372_trigger_ops = {
+       .validate_device = &iio_trigger_validate_own_device,
+       .set_trigger_state = adxl372_dready_trig_set_state,
+};
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("400 800 1600 3200 6400");
+static IIO_DEVICE_ATTR(in_accel_filter_low_pass_3db_frequency_available,
+                      0444, adxl372_show_filter_freq_avail, NULL, 0);
+
+static struct attribute *adxl372_attributes[] = {
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_in_accel_filter_low_pass_3db_frequency_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group adxl372_attrs_group = {
+       .attrs = adxl372_attributes,
+};
+
+static const struct iio_info adxl372_info = {
+       .validate_trigger = &adxl372_validate_trigger,
+       .attrs = &adxl372_attrs_group,
+       .read_raw = adxl372_read_raw,
+       .write_raw = adxl372_write_raw,
+       .debugfs_reg_access = &adxl372_reg_access,
+       .hwfifo_set_watermark = adxl372_set_watermark,
+};
+
+bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg)
+{
+       return (reg == ADXL372_FIFO_DATA);
+}
+EXPORT_SYMBOL_GPL(adxl372_readable_noinc_reg);
+
+int adxl372_probe(struct device *dev, struct regmap *regmap,
+                 int irq, const char *name)
+{
+       struct iio_dev *indio_dev;
+       struct adxl372_state *st;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       dev_set_drvdata(dev, indio_dev);
+
+       st->dev = dev;
+       st->regmap = regmap;
+       st->irq = irq;
+
+       indio_dev->channels = adxl372_channels;
+       indio_dev->num_channels = ARRAY_SIZE(adxl372_channels);
+       indio_dev->available_scan_masks = adxl372_channel_masks;
+       indio_dev->dev.parent = dev;
+       indio_dev->name = name;
+       indio_dev->info = &adxl372_info;
+       indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+
+       ret = adxl372_setup(st);
+       if (ret < 0) {
+               dev_err(dev, "ADXL372 setup failed\n");
+               return ret;
+       }
+
+       ret = devm_iio_triggered_buffer_setup(dev,
+                                             indio_dev, NULL,
+                                             adxl372_trigger_handler,
+                                             &adxl372_buffer_ops);
+       if (ret < 0)
+               return ret;
+
+       iio_buffer_set_attrs(indio_dev->buffer, adxl372_fifo_attributes);
+
+       if (st->irq) {
+               st->dready_trig = devm_iio_trigger_alloc(dev,
+                                                        "%s-dev%d",
+                                                        indio_dev->name,
+                                                        indio_dev->id);
+               if (st->dready_trig == NULL)
+                       return -ENOMEM;
+
+               st->dready_trig->ops = &adxl372_trigger_ops;
+               st->dready_trig->dev.parent = dev;
+               iio_trigger_set_drvdata(st->dready_trig, indio_dev);
+               ret = devm_iio_trigger_register(dev, st->dready_trig);
+               if (ret < 0)
+                       return ret;
+
+               indio_dev->trig = iio_trigger_get(st->dready_trig);
+
+               ret = devm_request_threaded_irq(dev, st->irq,
+                                       iio_trigger_generic_data_rdy_poll,
+                                       NULL,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       indio_dev->name, st->dready_trig);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+EXPORT_SYMBOL_GPL(adxl372_probe);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl372.h b/drivers/iio/accel/adxl372.h
new file mode 100644 (file)
index 0000000..80a0aa9
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * ADXL372 3-Axis Digital Accelerometer
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#ifndef _ADXL372_H_
+#define _ADXL372_H_
+
+#define ADXL372_REVID  0x03
+
+int adxl372_probe(struct device *dev, struct regmap *regmap,
+                 int irq, const char *name);
+bool adxl372_readable_noinc_reg(struct device *dev, unsigned int reg);
+
+#endif /* _ADXL372_H_ */
diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c
new file mode 100644 (file)
index 0000000..e1affe4
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADXL372 3-Axis Digital Accelerometer I2C driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "adxl372.h"
+
+static const struct regmap_config adxl372_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .readable_noinc_reg = adxl372_readable_noinc_reg,
+};
+
+static int adxl372_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct regmap *regmap;
+       unsigned int regval;
+       int ret;
+
+       regmap = devm_regmap_init_i2c(client, &adxl372_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       ret = regmap_read(regmap, ADXL372_REVID, &regval);
+       if (ret < 0)
+               return ret;
+
+       /* Starting with the 3rd revision an I2C chip bug was fixed */
+       if (regval < 3)
+               dev_warn(&client->dev,
+               "I2C might not work properly with other devices on the bus");
+
+       return adxl372_probe(&client->dev, regmap, client->irq, id->name);
+}
+
+static const struct i2c_device_id adxl372_i2c_id[] = {
+       { "adxl372", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, adxl372_i2c_id);
+
+static struct i2c_driver adxl372_i2c_driver = {
+       .driver = {
+               .name = "adxl372_i2c",
+       },
+       .probe = adxl372_i2c_probe,
+       .id_table = adxl372_i2c_id,
+};
+
+module_i2c_driver(adxl372_i2c_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c
new file mode 100644 (file)
index 0000000..e14e655
--- /dev/null
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ADXL372 3-Axis Digital Accelerometer SPI driver
+ *
+ * Copyright 2018 Analog Devices Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "adxl372.h"
+
+static const struct regmap_config adxl372_spi_regmap_config = {
+       .reg_bits = 7,
+       .pad_bits = 1,
+       .val_bits = 8,
+       .read_flag_mask = BIT(0),
+       .readable_noinc_reg = adxl372_readable_noinc_reg,
+};
+
+static int adxl372_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_spi(spi, &adxl372_spi_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return adxl372_probe(&spi->dev, regmap, spi->irq, id->name);
+}
+
+static const struct spi_device_id adxl372_spi_id[] = {
+       { "adxl372", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, adxl372_spi_id);
+
+static struct spi_driver adxl372_spi_driver = {
+       .driver = {
+               .name = "adxl372_spi",
+       },
+       .probe = adxl372_spi_probe,
+       .id_table = adxl372_spi_id,
+};
+
+module_spi_driver(adxl372_spi_driver);
+
+MODULE_AUTHOR("Stefan Popa <stefan.popa@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADXL372 3-axis accelerometer SPI driver");
+MODULE_LICENSE("GPL");
index 4a754921fb6f9de7d488a2c7dc59bba0d3d11ddc..a52fea8749a9050a553842067a5c2032392ee8df 100644 (file)
@@ -501,6 +501,16 @@ config MCP3422
          This driver can also be built as a module. If so, the module will be
          called mcp3422.
 
+config MCP3911
+       tristate "Microchip Technology MCP3911 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Microchip Technology's MCP3911
+         analog to digital converter.
+
+         This driver can also be built as a module. If so, the module will be
+         called mcp3911.
+
 config MEDIATEK_MT6577_AUXADC
         tristate "MediaTek AUXADC driver"
         depends on ARCH_MEDIATEK || COMPILE_TEST
@@ -596,6 +606,26 @@ config QCOM_SPMI_VADC
          To compile this driver as a module, choose M here: the module will
          be called qcom-spmi-vadc.
 
+config QCOM_SPMI_ADC5
+       tristate "Qualcomm Technologies Inc. SPMI PMIC5 ADC"
+       depends on SPMI
+       select REGMAP_SPMI
+       select QCOM_VADC_COMMON
+       help
+         This is the IIO Voltage PMIC5 ADC driver for Qualcomm Technologies Inc.
+
+         The driver supports multiple channels read. The ADC is a 16-bit
+         sigma-delta ADC. The hardware supports calibrated results for
+         conversion requests and clients include reading voltage phone
+         power, on board system thermistors connected to the PMIC ADC,
+         PMIC die temperature, charger temperature, battery current, USB voltage
+         input, voltage signals connected to supported PMIC GPIO inputs. The
+         hardware supports internal pull-up for thermistors and can choose between
+         a 100k, 30k and 400k pull up using the ADC channels.
+
+         To compile this driver as a module, choose M here: the module will
+         be called qcom-spmi-adc5.
+
 config RCAR_GYRO_ADC
        tristate "Renesas R-Car GyroADC driver"
        depends on ARCH_RCAR_GEN2 || COMPILE_TEST
index 03db7b578f9c077c4a5790f79f8ba48beb8d56dd..a6e6a0b659e2ab3eb921080c1a7f436c9b93453a 100644 (file)
@@ -47,12 +47,14 @@ obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MAX9611) += max9611.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
+obj-$(CONFIG_MCP3911) += mcp3911.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
 obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
+obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
 obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
 obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
 obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
index 2b20c6c8ec7f631bd0b0f7d19da49d0a86aa4f0e..e0220825fde053e77cd475c961aef690a53cac1b 100644 (file)
@@ -385,6 +385,6 @@ static struct spi_driver ad7298_driver = {
 };
 module_spi_driver(ad7298_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7298 ADC");
 MODULE_LICENSE("GPL v2");
index fbaae47746a83d82cb29135007a7aa8d33b2e7c6..0549686b9ef840917744f857b0030d653f42c54c 100644 (file)
@@ -328,6 +328,6 @@ static struct spi_driver ad7476_driver = {
 };
 module_spi_driver(ad7476_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs");
 MODULE_LICENSE("GPL v2");
index d4bbe5b533189730437aa5a8a4c8593288fc10da..4ac3ae62f56f98943b6c719179066e98c716319b 100644 (file)
@@ -822,6 +822,6 @@ static struct spi_driver ad7793_driver = {
 };
 module_spi_driver(ad7793_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs");
 MODULE_LICENSE("GPL v2");
index 205c0f1761aa208abaefb4c39161a451a55c9491..9d4c2467d362b0067d03b53bcc508269f75d2609 100644 (file)
@@ -362,6 +362,6 @@ static struct spi_driver ad7887_driver = {
 };
 module_spi_driver(ad7887_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7887 ADC");
 MODULE_LICENSE("GPL v2");
index ffb7e089969c26a4ab2fd3edca7f742162ad4231..d62dbb62be458cd9652384fb1a2052f5bcde1519 100644 (file)
@@ -363,7 +363,7 @@ static struct spi_driver ad7923_driver = {
 };
 module_spi_driver(ad7923_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_AUTHOR("Patrick Vasseur <patrick.vasseur@c-s.fr>");
 MODULE_DESCRIPTION("Analog Devices AD7904/AD7914/AD7923/AD7924 ADC");
 MODULE_LICENSE("GPL v2");
index e1da67d5ee2204b6ad1e97281653cb3e89ffbc86..7a5b5d00a87ddf40adc4bef2533c927a8e9cec1e 100644 (file)
@@ -892,6 +892,6 @@ static struct i2c_driver ad799x_driver = {
 };
 module_i2c_driver(ad799x_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD799x ADC");
 MODULE_LICENSE("GPL v2");
index 4ebda8ab54fe7ae7caae11de4f32789d6b46714d..2f2b563c116223ae824f9f58b6c86ef5eff628c9 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Driver for an envelope detector using a DAC and a comparator
  *
  * Copyright (C) 2016 Axentia Technologies AB
  *
  * Author: Peter Rosin <peda@axentia.se>
- *
- * 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 0538ff8c4ac1d2f1e242898daf644d3b69345c4d..643a4e66eb80b2e1d0d11148b534536f8ac3f546 100644 (file)
@@ -289,7 +289,7 @@ static int max9611_read_csa_voltage(struct max9611_dev *max9611,
                        return ret;
 
                if (*adc_raw > 0) {
-                       *csa_gain = gain_selectors[i];
+                       *csa_gain = (enum max9611_csa_gain)gain_selectors[i];
                        return 0;
                }
        }
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
new file mode 100644 (file)
index 0000000..dd52f08
--- /dev/null
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Microchip MCP3911, Two-channel Analog Front End
+ *
+ * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
+ * Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#define MCP3911_REG_CHANNEL0           0x00
+#define MCP3911_REG_CHANNEL1           0x03
+#define MCP3911_REG_MOD                        0x06
+#define MCP3911_REG_PHASE              0x07
+#define MCP3911_REG_GAIN               0x09
+
+#define MCP3911_REG_STATUSCOM          0x0a
+#define MCP3911_STATUSCOM_CH1_24WIDTH  BIT(4)
+#define MCP3911_STATUSCOM_CH0_24WIDTH  BIT(3)
+#define MCP3911_STATUSCOM_EN_OFFCAL    BIT(2)
+#define MCP3911_STATUSCOM_EN_GAINCAL   BIT(1)
+
+#define MCP3911_REG_CONFIG             0x0c
+#define MCP3911_CONFIG_CLKEXT          BIT(1)
+#define MCP3911_CONFIG_VREFEXT         BIT(2)
+
+#define MCP3911_REG_OFFCAL_CH0         0x0e
+#define MCP3911_REG_GAINCAL_CH0                0x11
+#define MCP3911_REG_OFFCAL_CH1         0x14
+#define MCP3911_REG_GAINCAL_CH1                0x17
+#define MCP3911_REG_VREFCAL            0x1a
+
+#define MCP3911_CHANNEL(x)             (MCP3911_REG_CHANNEL0 + x * 3)
+#define MCP3911_OFFCAL(x)              (MCP3911_REG_OFFCAL_CH0 + x * 6)
+
+/* Internal voltage reference in uV */
+#define MCP3911_INT_VREF_UV            1200000
+
+#define MCP3911_REG_READ(reg, id)      ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff)
+#define MCP3911_REG_WRITE(reg, id)     ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff)
+
+#define MCP3911_NUM_CHANNELS           2
+
+struct mcp3911 {
+       struct spi_device *spi;
+       struct mutex lock;
+       struct regulator *vref;
+       struct clk *clki;
+       u32 dev_addr;
+};
+
+static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
+{
+       int ret;
+
+       reg = MCP3911_REG_READ(reg, adc->dev_addr);
+       ret = spi_write_then_read(adc->spi, &reg, 1, val, len);
+       if (ret < 0)
+               return ret;
+
+       be32_to_cpus(val);
+       *val >>= ((4 - len) * 8);
+       dev_dbg(&adc->spi->dev, "reading 0x%x from register 0x%x\n", *val,
+               reg >> 1);
+       return ret;
+}
+
+static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
+{
+       dev_dbg(&adc->spi->dev, "writing 0x%x to register 0x%x\n", val, reg);
+
+       val <<= (3 - len) * 8;
+       cpu_to_be32s(&val);
+       val |= MCP3911_REG_WRITE(reg, adc->dev_addr);
+
+       return spi_write(adc->spi, &val, len + 1);
+}
+
+static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
+               u32 val, u8 len)
+{
+       u32 tmp;
+       int ret;
+
+       ret = mcp3911_read(adc, reg, &tmp, len);
+       if (ret)
+               return ret;
+
+       val &= mask;
+       val |= tmp & ~mask;
+       return mcp3911_write(adc, reg, val, len);
+}
+
+static int mcp3911_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *channel, int *val,
+                           int *val2, long mask)
+{
+       struct mcp3911 *adc = iio_priv(indio_dev);
+       int ret = -EINVAL;
+
+       mutex_lock(&adc->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = mcp3911_read(adc,
+                                  MCP3911_CHANNEL(channel->channel), val, 3);
+               if (ret)
+                       goto out;
+
+               ret = IIO_VAL_INT;
+               break;
+
+       case IIO_CHAN_INFO_OFFSET:
+               ret = mcp3911_read(adc,
+                                  MCP3911_OFFCAL(channel->channel), val, 3);
+               if (ret)
+                       goto out;
+
+               ret = IIO_VAL_INT;
+               break;
+
+       case IIO_CHAN_INFO_SCALE:
+               if (adc->vref) {
+                       ret = regulator_get_voltage(adc->vref);
+                       if (ret < 0) {
+                               dev_err(indio_dev->dev.parent,
+                                       "failed to get vref voltage: %d\n",
+                                      ret);
+                               goto out;
+                       }
+
+                       *val = ret / 1000;
+               } else {
+                       *val = MCP3911_INT_VREF_UV;
+               }
+
+               *val2 = 24;
+               ret = IIO_VAL_FRACTIONAL_LOG2;
+               break;
+       }
+
+out:
+       mutex_unlock(&adc->lock);
+       return ret;
+}
+
+static int mcp3911_write_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *channel, int val,
+                           int val2, long mask)
+{
+       struct mcp3911 *adc = iio_priv(indio_dev);
+       int ret = -EINVAL;
+
+       mutex_lock(&adc->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_OFFSET:
+               if (val2 != 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /* Write offset */
+               ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val,
+                                   3);
+               if (ret)
+                       goto out;
+
+               /* Enable offset*/
+               ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM,
+                               MCP3911_STATUSCOM_EN_OFFCAL,
+                               MCP3911_STATUSCOM_EN_OFFCAL, 2);
+               break;
+       }
+
+out:
+       mutex_unlock(&adc->lock);
+       return ret;
+}
+
+#define MCP3911_CHAN(idx) {                                    \
+               .type = IIO_VOLTAGE,                            \
+               .indexed = 1,                                   \
+               .channel = idx,                                 \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
+                       BIT(IIO_CHAN_INFO_OFFSET) |             \
+                       BIT(IIO_CHAN_INFO_SCALE),               \
+}
+
+static const struct iio_chan_spec mcp3911_channels[] = {
+       MCP3911_CHAN(0),
+       MCP3911_CHAN(1),
+};
+
+static const struct iio_info mcp3911_info = {
+       .read_raw = mcp3911_read_raw,
+       .write_raw = mcp3911_write_raw,
+};
+
+static int mcp3911_config(struct mcp3911 *adc, struct device_node *of_node)
+{
+       u32 configreg;
+       int ret;
+
+       of_property_read_u32(of_node, "device-addr", &adc->dev_addr);
+       if (adc->dev_addr > 3) {
+               dev_err(&adc->spi->dev,
+                       "invalid device address (%i). Must be in range 0-3.\n",
+                       adc->dev_addr);
+               return -EINVAL;
+       }
+       dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
+
+       ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &configreg, 2);
+       if (ret)
+               return ret;
+
+       if (adc->vref) {
+               dev_dbg(&adc->spi->dev, "use external voltage reference\n");
+               configreg |= MCP3911_CONFIG_VREFEXT;
+       } else {
+               dev_dbg(&adc->spi->dev,
+                       "use internal voltage reference (1.2V)\n");
+               configreg &= ~MCP3911_CONFIG_VREFEXT;
+       }
+
+       if (adc->clki) {
+               dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
+               configreg |= MCP3911_CONFIG_CLKEXT;
+       } else {
+               dev_dbg(&adc->spi->dev,
+                       "use crystal oscillator as clocksource\n");
+               configreg &= ~MCP3911_CONFIG_CLKEXT;
+       }
+
+       return  mcp3911_write(adc, MCP3911_REG_CONFIG, configreg, 2);
+}
+
+static int mcp3911_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct mcp3911 *adc;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       adc = iio_priv(indio_dev);
+       adc->spi = spi;
+
+       adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref");
+       if (IS_ERR(adc->vref)) {
+               if (PTR_ERR(adc->vref) == -ENODEV) {
+                       adc->vref = NULL;
+               } else {
+                       dev_err(&adc->spi->dev,
+                               "failed to get regulator (%ld)\n",
+                               PTR_ERR(adc->vref));
+                       return PTR_ERR(adc->vref);
+               }
+
+       } else {
+               ret = regulator_enable(adc->vref);
+               if (ret)
+                       return ret;
+       }
+
+       adc->clki = devm_clk_get(&adc->spi->dev, NULL);
+       if (IS_ERR(adc->clki)) {
+               if (PTR_ERR(adc->clki) == -ENOENT) {
+                       adc->clki = NULL;
+               } else {
+                       dev_err(&adc->spi->dev,
+                               "failed to get adc clk (%ld)\n",
+                               PTR_ERR(adc->clki));
+                       ret = PTR_ERR(adc->clki);
+                       goto reg_disable;
+               }
+       } else {
+               ret = clk_prepare_enable(adc->clki);
+               if (ret < 0) {
+                       dev_err(&adc->spi->dev,
+                               "Failed to enable clki: %d\n", ret);
+                       goto reg_disable;
+               }
+       }
+
+       ret = mcp3911_config(adc, spi->dev.of_node);
+       if (ret)
+               goto clk_disable;
+
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->dev.of_node = spi->dev.of_node;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &mcp3911_info;
+       spi_set_drvdata(spi, indio_dev);
+
+       indio_dev->channels = mcp3911_channels;
+       indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels);
+
+       mutex_init(&adc->lock);
+
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto clk_disable;
+
+       return ret;
+
+clk_disable:
+       clk_disable_unprepare(adc->clki);
+reg_disable:
+       if (adc->vref)
+               regulator_disable(adc->vref);
+
+       return ret;
+}
+
+static int mcp3911_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct mcp3911 *adc = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       clk_disable_unprepare(adc->clki);
+       if (adc->vref)
+               regulator_disable(adc->vref);
+
+       return 0;
+}
+
+static const struct of_device_id mcp3911_dt_ids[] = {
+       { .compatible = "microchip,mcp3911" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
+
+static const struct spi_device_id mcp3911_id[] = {
+       { "mcp3911", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, mcp3911_id);
+
+static struct spi_driver mcp3911_driver = {
+       .driver = {
+               .name = "mcp3911",
+               .of_match_table = mcp3911_dt_ids,
+       },
+       .probe = mcp3911_probe,
+       .remove = mcp3911_remove,
+       .id_table = mcp3911_id,
+};
+module_spi_driver(mcp3911_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_AUTHOR("Kent Gustavsson <kent@minoris.se>");
+MODULE_DESCRIPTION("Microchip Technology MCP3911");
+MODULE_LICENSE("GPL v2");
index b093ecddf1a8ae4fc53410ed57cbd59a2472d9b8..c30c002f1fef78d35a9fca18dee6a8cce3277e3f 100644 (file)
@@ -708,8 +708,8 @@ static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
         * mux.
         */
        if (iiospec->args_count != 2) {
-               dev_err(&indio_dev->dev, "wrong number of arguments for %s need 2 got %d\n",
-                       iiospec->np->name,
+               dev_err(&indio_dev->dev, "wrong number of arguments for %pOFn need 2 got %d\n",
+                       iiospec->np,
                        iiospec->args_count);
                return -EINVAL;
        }
diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c
new file mode 100644 (file)
index 0000000..f9af6b0
--- /dev/null
@@ -0,0 +1,793 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/log2.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+#include "qcom-vadc-common.h"
+
+#define ADC5_USR_REVISION1                     0x0
+#define ADC5_USR_STATUS1                       0x8
+#define ADC5_USR_STATUS1_REQ_STS               BIT(1)
+#define ADC5_USR_STATUS1_EOC                   BIT(0)
+#define ADC5_USR_STATUS1_REQ_STS_EOC_MASK      0x3
+
+#define ADC5_USR_STATUS2                       0x9
+#define ADC5_USR_STATUS2_CONV_SEQ_MASK         0x70
+#define ADC5_USR_STATUS2_CONV_SEQ_MASK_SHIFT   0x5
+
+#define ADC5_USR_IBAT_MEAS                     0xf
+#define ADC5_USR_IBAT_MEAS_SUPPORTED           BIT(0)
+
+#define ADC5_USR_DIG_PARAM                     0x42
+#define ADC5_USR_DIG_PARAM_CAL_VAL             BIT(6)
+#define ADC5_USR_DIG_PARAM_CAL_VAL_SHIFT       6
+#define ADC5_USR_DIG_PARAM_CAL_SEL             0x30
+#define ADC5_USR_DIG_PARAM_CAL_SEL_SHIFT       4
+#define ADC5_USR_DIG_PARAM_DEC_RATIO_SEL       0xc
+#define ADC5_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT 2
+
+#define ADC5_USR_FAST_AVG_CTL                  0x43
+#define ADC5_USR_FAST_AVG_CTL_EN               BIT(7)
+#define ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK     0x7
+
+#define ADC5_USR_CH_SEL_CTL                    0x44
+
+#define ADC5_USR_DELAY_CTL                     0x45
+#define ADC5_USR_HW_SETTLE_DELAY_MASK          0xf
+
+#define ADC5_USR_EN_CTL1                       0x46
+#define ADC5_USR_EN_CTL1_ADC_EN                        BIT(7)
+
+#define ADC5_USR_CONV_REQ                      0x47
+#define ADC5_USR_CONV_REQ_REQ                  BIT(7)
+
+#define ADC5_USR_DATA0                         0x50
+
+#define ADC5_USR_DATA1                         0x51
+
+#define ADC5_USR_IBAT_DATA0                    0x52
+
+#define ADC5_USR_IBAT_DATA1                    0x53
+
+/*
+ * Conversion time varies based on the decimation, clock rate, fast average
+ * samples and measurements queued across different VADC peripherals.
+ * Set the timeout to a max of 100ms.
+ */
+#define ADC5_CONV_TIME_MIN_US                  263
+#define ADC5_CONV_TIME_MAX_US                  264
+#define ADC5_CONV_TIME_RETRY                   400
+#define ADC5_CONV_TIMEOUT                      msecs_to_jiffies(100)
+
+/* Digital version >= 5.3 supports hw_settle_2 */
+#define ADC5_HW_SETTLE_DIFF_MINOR              3
+#define ADC5_HW_SETTLE_DIFF_MAJOR              5
+
+enum adc5_cal_method {
+       ADC5_NO_CAL = 0,
+       ADC5_RATIOMETRIC_CAL,
+       ADC5_ABSOLUTE_CAL
+};
+
+enum adc5_cal_val {
+       ADC5_TIMER_CAL = 0,
+       ADC5_NEW_CAL
+};
+
+/**
+ * struct adc5_channel_prop - ADC channel property.
+ * @channel: channel number, refer to the channel list.
+ * @cal_method: calibration method.
+ * @cal_val: calibration value
+ * @decimation: sampling rate supported for the channel.
+ * @prescale: channel scaling performed on the input signal.
+ * @hw_settle_time: the time between AMUX being configured and the
+ *     start of conversion.
+ * @avg_samples: ability to provide single result from the ADC
+ *     that is an average of multiple measurements.
+ * @scale_fn_type: Represents the scaling function to convert voltage
+ *     physical units desired by the client for the channel.
+ * @datasheet_name: Channel name used in device tree.
+ */
+struct adc5_channel_prop {
+       unsigned int            channel;
+       enum adc5_cal_method    cal_method;
+       enum adc5_cal_val       cal_val;
+       unsigned int            decimation;
+       unsigned int            prescale;
+       unsigned int            hw_settle_time;
+       unsigned int            avg_samples;
+       enum vadc_scale_fn_type scale_fn_type;
+       const char              *datasheet_name;
+};
+
+/**
+ * struct adc5_chip - ADC private structure.
+ * @regmap: SPMI ADC5 peripheral register map field.
+ * @dev: SPMI ADC5 device.
+ * @base: base address for the ADC peripheral.
+ * @nchannels: number of ADC channels.
+ * @chan_props: array of ADC channel properties.
+ * @iio_chans: array of IIO channels specification.
+ * @poll_eoc: use polling instead of interrupt.
+ * @complete: ADC result notification after interrupt is received.
+ * @lock: ADC lock for access to the peripheral.
+ * @data: software configuration data.
+ */
+struct adc5_chip {
+       struct regmap           *regmap;
+       struct device           *dev;
+       u16                     base;
+       unsigned int            nchannels;
+       struct adc5_channel_prop        *chan_props;
+       struct iio_chan_spec    *iio_chans;
+       bool                    poll_eoc;
+       struct completion       complete;
+       struct mutex            lock;
+       const struct adc5_data  *data;
+};
+
+static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
+       {.num =  1, .den =  1},
+       {.num =  1, .den =  3},
+       {.num =  1, .den =  4},
+       {.num =  1, .den =  6},
+       {.num =  1, .den = 20},
+       {.num =  1, .den =  8},
+       {.num = 10, .den = 81},
+       {.num =  1, .den = 10},
+       {.num =  1, .den = 16}
+};
+
+static int adc5_read(struct adc5_chip *adc, u16 offset, u8 *data, int len)
+{
+       return regmap_bulk_read(adc->regmap, adc->base + offset, data, len);
+}
+
+static int adc5_write(struct adc5_chip *adc, u16 offset, u8 *data, int len)
+{
+       return regmap_bulk_write(adc->regmap, adc->base + offset, data, len);
+}
+
+static int adc5_prescaling_from_dt(u32 num, u32 den)
+{
+       unsigned int pre;
+
+       for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++)
+               if (adc5_prescale_ratios[pre].num == num &&
+                   adc5_prescale_ratios[pre].den == den)
+                       break;
+
+       if (pre == ARRAY_SIZE(adc5_prescale_ratios))
+               return -EINVAL;
+
+       return pre;
+}
+
+static int adc5_hw_settle_time_from_dt(u32 value,
+                                       const unsigned int *hw_settle)
+{
+       unsigned int i;
+
+       for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) {
+               if (value == hw_settle[i])
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int adc5_avg_samples_from_dt(u32 value)
+{
+       if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX)
+               return -EINVAL;
+
+       return __ffs(value);
+}
+
+static int adc5_decimation_from_dt(u32 value,
+                                       const unsigned int *decimation)
+{
+       unsigned int i;
+
+       for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) {
+               if (value == decimation[i])
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data)
+{
+       int ret;
+       u8 rslt_lsb, rslt_msb;
+
+       ret = adc5_read(adc, ADC5_USR_DATA0, &rslt_lsb, sizeof(rslt_lsb));
+       if (ret)
+               return ret;
+
+       ret = adc5_read(adc, ADC5_USR_DATA1, &rslt_msb, sizeof(rslt_lsb));
+       if (ret)
+               return ret;
+
+       *data = (rslt_msb << 8) | rslt_lsb;
+
+       if (*data == ADC5_USR_DATA_CHECK) {
+               pr_err("Invalid data:0x%x\n", *data);
+               return -EINVAL;
+       }
+
+       pr_debug("voltage raw code:0x%x\n", *data);
+
+       return 0;
+}
+
+static int adc5_poll_wait_eoc(struct adc5_chip *adc)
+{
+       unsigned int count, retry = ADC5_CONV_TIME_RETRY;
+       u8 status1;
+       int ret;
+
+       for (count = 0; count < retry; count++) {
+               ret = adc5_read(adc, ADC5_USR_STATUS1, &status1,
+                                                       sizeof(status1));
+               if (ret)
+                       return ret;
+
+               status1 &= ADC5_USR_STATUS1_REQ_STS_EOC_MASK;
+               if (status1 == ADC5_USR_STATUS1_EOC)
+                       return 0;
+
+               usleep_range(ADC5_CONV_TIME_MIN_US, ADC5_CONV_TIME_MAX_US);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static void adc5_update_dig_param(struct adc5_chip *adc,
+                       struct adc5_channel_prop *prop, u8 *data)
+{
+       /* Update calibration value */
+       *data &= ~ADC5_USR_DIG_PARAM_CAL_VAL;
+       *data |= (prop->cal_val << ADC5_USR_DIG_PARAM_CAL_VAL_SHIFT);
+
+       /* Update calibration select */
+       *data &= ~ADC5_USR_DIG_PARAM_CAL_SEL;
+       *data |= (prop->cal_method << ADC5_USR_DIG_PARAM_CAL_SEL_SHIFT);
+
+       /* Update decimation ratio select */
+       *data &= ~ADC5_USR_DIG_PARAM_DEC_RATIO_SEL;
+       *data |= (prop->decimation << ADC5_USR_DIG_PARAM_DEC_RATIO_SEL_SHIFT);
+}
+
+static int adc5_configure(struct adc5_chip *adc,
+                       struct adc5_channel_prop *prop)
+{
+       int ret;
+       u8 buf[6];
+
+       /* Read registers 0x42 through 0x46 */
+       ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
+       if (ret < 0)
+               return ret;
+
+       /* Digital param selection */
+       adc5_update_dig_param(adc, prop, &buf[0]);
+
+       /* Update fast average sample value */
+       buf[1] &= (u8) ~ADC5_USR_FAST_AVG_CTL_SAMPLES_MASK;
+       buf[1] |= prop->avg_samples;
+
+       /* Select ADC channel */
+       buf[2] = prop->channel;
+
+       /* Select HW settle delay for channel */
+       buf[3] &= (u8) ~ADC5_USR_HW_SETTLE_DELAY_MASK;
+       buf[3] |= prop->hw_settle_time;
+
+       /* Select ADC enable */
+       buf[4] |= ADC5_USR_EN_CTL1_ADC_EN;
+
+       /* Select CONV request */
+       buf[5] |= ADC5_USR_CONV_REQ_REQ;
+
+       if (!adc->poll_eoc)
+               reinit_completion(&adc->complete);
+
+       return adc5_write(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
+}
+
+static int adc5_do_conversion(struct adc5_chip *adc,
+                       struct adc5_channel_prop *prop,
+                       struct iio_chan_spec const *chan,
+                       u16 *data_volt, u16 *data_cur)
+{
+       int ret;
+
+       mutex_lock(&adc->lock);
+
+       ret = adc5_configure(adc, prop);
+       if (ret) {
+               pr_err("ADC configure failed with %d\n", ret);
+               goto unlock;
+       }
+
+       if (adc->poll_eoc) {
+               ret = adc5_poll_wait_eoc(adc);
+               if (ret < 0) {
+                       pr_err("EOC bit not set\n");
+                       goto unlock;
+               }
+       } else {
+               ret = wait_for_completion_timeout(&adc->complete,
+                                                       ADC5_CONV_TIMEOUT);
+               if (!ret) {
+                       pr_debug("Did not get completion timeout.\n");
+                       ret = adc5_poll_wait_eoc(adc);
+                       if (ret < 0) {
+                               pr_err("EOC bit not set\n");
+                               goto unlock;
+                       }
+               }
+       }
+
+       ret = adc5_read_voltage_data(adc, data_volt);
+unlock:
+       mutex_unlock(&adc->lock);
+
+       return ret;
+}
+
+static irqreturn_t adc5_isr(int irq, void *dev_id)
+{
+       struct adc5_chip *adc = dev_id;
+
+       complete(&adc->complete);
+
+       return IRQ_HANDLED;
+}
+
+static int adc5_of_xlate(struct iio_dev *indio_dev,
+                               const struct of_phandle_args *iiospec)
+{
+       struct adc5_chip *adc = iio_priv(indio_dev);
+       int i;
+
+       for (i = 0; i < adc->nchannels; i++)
+               if (adc->chan_props[i].channel == iiospec->args[0])
+                       return i;
+
+       return -EINVAL;
+}
+
+static int adc5_read_raw(struct iio_dev *indio_dev,
+                        struct iio_chan_spec const *chan, int *val, int *val2,
+                        long mask)
+{
+       struct adc5_chip *adc = iio_priv(indio_dev);
+       struct adc5_channel_prop *prop;
+       u16 adc_code_volt, adc_code_cur;
+       int ret;
+
+       prop = &adc->chan_props[chan->address];
+
+       switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               ret = adc5_do_conversion(adc, prop, chan,
+                               &adc_code_volt, &adc_code_cur);
+               if (ret)
+                       return ret;
+
+               ret = qcom_adc5_hw_scale(prop->scale_fn_type,
+                       &adc5_prescale_ratios[prop->prescale],
+                       adc->data,
+                       adc_code_volt, val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct iio_info adc5_info = {
+       .read_raw = adc5_read_raw,
+       .of_xlate = adc5_of_xlate,
+};
+
+struct adc5_channels {
+       const char *datasheet_name;
+       unsigned int prescale_index;
+       enum iio_chan_type type;
+       long info_mask;
+       enum vadc_scale_fn_type scale_fn_type;
+};
+
+#define ADC5_CHAN(_dname, _type, _mask, _pre, _scale)                  \
+       {                                                               \
+               .datasheet_name = _dname,                               \
+               .prescale_index = _pre,                                 \
+               .type = _type,                                          \
+               .info_mask = _mask,                                     \
+               .scale_fn_type = _scale,                                \
+       },                                                              \
+
+#define ADC5_CHAN_TEMP(_dname, _pre, _scale)                           \
+       ADC5_CHAN(_dname, IIO_TEMP,                                     \
+               BIT(IIO_CHAN_INFO_PROCESSED),                           \
+               _pre, _scale)                                           \
+
+#define ADC5_CHAN_VOLT(_dname, _pre, _scale)                           \
+       ADC5_CHAN(_dname, IIO_VOLTAGE,                                  \
+                 BIT(IIO_CHAN_INFO_PROCESSED),                         \
+                 _pre, _scale)                                         \
+
+static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
+       [ADC5_REF_GND]          = ADC5_CHAN_VOLT("ref_gnd", 1,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_1P25VREF]         = ADC5_CHAN_VOLT("vref_1p25", 1,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_VPH_PWR]          = ADC5_CHAN_VOLT("vph_pwr", 3,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_VBAT_SNS]         = ADC5_CHAN_VOLT("vbat_sns", 3,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_DIE_TEMP]         = ADC5_CHAN_TEMP("die_temp", 1,
+                                       SCALE_HW_CALIB_PMIC_THERM)
+       [ADC5_USB_IN_I]         = ADC5_CHAN_VOLT("usb_in_i_uv", 1,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_USB_IN_V_16]      = ADC5_CHAN_VOLT("usb_in_v_div_16", 16,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_CHG_TEMP]         = ADC5_CHAN_TEMP("chg_temp", 1,
+                                       SCALE_HW_CALIB_PM5_CHG_TEMP)
+       /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */
+       [ADC5_SBUx]             = ADC5_CHAN_VOLT("chg_sbux", 3,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_MID_CHG_DIV6]     = ADC5_CHAN_VOLT("chg_mid_chg", 6,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1,
+                                       SCALE_HW_CALIB_XOTHERM)
+       [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM2]        = ADC5_CHAN_TEMP("amux_thm2", 1,
+                                       SCALE_HW_CALIB_PM5_SMB_TEMP)
+};
+
+static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
+       [ADC5_REF_GND]          = ADC5_CHAN_VOLT("ref_gnd", 1,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_1P25VREF]         = ADC5_CHAN_VOLT("vref_1p25", 1,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_VPH_PWR]          = ADC5_CHAN_VOLT("vph_pwr", 3,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_VBAT_SNS]         = ADC5_CHAN_VOLT("vbat_sns", 3,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_VCOIN]            = ADC5_CHAN_VOLT("vcoin", 3,
+                                       SCALE_HW_CALIB_DEFAULT)
+       [ADC5_DIE_TEMP]         = ADC5_CHAN_TEMP("die_temp", 1,
+                                       SCALE_HW_CALIB_PMIC_THERM)
+       [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+       [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1,
+                                       SCALE_HW_CALIB_THERM_100K_PULLUP)
+};
+
+static int adc5_get_dt_channel_data(struct adc5_chip *adc,
+                                   struct adc5_channel_prop *prop,
+                                   struct device_node *node,
+                                   const struct adc5_data *data)
+{
+       const char *name = node->name, *channel_name;
+       u32 chan, value, varr[2];
+       int ret;
+       struct device *dev = adc->dev;
+
+       ret = of_property_read_u32(node, "reg", &chan);
+       if (ret) {
+               dev_err(dev, "invalid channel number %s\n", name);
+               return ret;
+       }
+
+       if (chan > ADC5_PARALLEL_ISENSE_VBAT_IDATA ||
+           !data->adc_chans[chan].datasheet_name) {
+               dev_err(dev, "%s invalid channel number %d\n", name, chan);
+               return -EINVAL;
+       }
+
+       /* the channel has DT description */
+       prop->channel = chan;
+
+       channel_name = of_get_property(node,
+                               "label", NULL) ? : node->name;
+       if (!channel_name) {
+               pr_err("Invalid channel name\n");
+               return -EINVAL;
+       }
+       prop->datasheet_name = channel_name;
+
+       ret = of_property_read_u32(node, "qcom,decimation", &value);
+       if (!ret) {
+               ret = adc5_decimation_from_dt(value, data->decimation);
+               if (ret < 0) {
+                       dev_err(dev, "%02x invalid decimation %d\n",
+                               chan, value);
+                       return ret;
+               }
+               prop->decimation = ret;
+       } else {
+               prop->decimation = ADC5_DECIMATION_DEFAULT;
+       }
+
+       ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
+       if (!ret) {
+               ret = adc5_prescaling_from_dt(varr[0], varr[1]);
+               if (ret < 0) {
+                       dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
+                               chan, varr[0], varr[1]);
+                       return ret;
+               }
+               prop->prescale = ret;
+       }
+
+       ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
+       if (!ret) {
+               u8 dig_version[2];
+
+               ret = adc5_read(adc, ADC5_USR_REVISION1, dig_version,
+                                                       sizeof(dig_version));
+               if (ret < 0) {
+                       dev_err(dev, "Invalid dig version read %d\n", ret);
+                       return ret;
+               }
+
+               pr_debug("dig_ver:minor:%d, major:%d\n", dig_version[0],
+                                               dig_version[1]);
+               /* Digital controller >= 5.3 have hw_settle_2 option */
+               if (dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR &&
+                       dig_version[1] >= ADC5_HW_SETTLE_DIFF_MAJOR)
+                       ret = adc5_hw_settle_time_from_dt(value,
+                                                       data->hw_settle_2);
+               else
+                       ret = adc5_hw_settle_time_from_dt(value,
+                                                       data->hw_settle_1);
+
+               if (ret < 0) {
+                       dev_err(dev, "%02x invalid hw-settle-time %d us\n",
+                               chan, value);
+                       return ret;
+               }
+               prop->hw_settle_time = ret;
+       } else {
+               prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
+       }
+
+       ret = of_property_read_u32(node, "qcom,avg-samples", &value);
+       if (!ret) {
+               ret = adc5_avg_samples_from_dt(value);
+               if (ret < 0) {
+                       dev_err(dev, "%02x invalid avg-samples %d\n",
+                               chan, value);
+                       return ret;
+               }
+               prop->avg_samples = ret;
+       } else {
+               prop->avg_samples = VADC_DEF_AVG_SAMPLES;
+       }
+
+       if (of_property_read_bool(node, "qcom,ratiometric"))
+               prop->cal_method = ADC5_RATIOMETRIC_CAL;
+       else
+               prop->cal_method = ADC5_ABSOLUTE_CAL;
+
+       /*
+        * Default to using timer calibration. Using a fresh calibration value
+        * for every conversion will increase the overall time for a request.
+        */
+       prop->cal_val = ADC5_TIMER_CAL;
+
+       dev_dbg(dev, "%02x name %s\n", chan, name);
+
+       return 0;
+}
+
+static const struct adc5_data adc5_data_pmic = {
+       .full_scale_code_volt = 0x70e4,
+       .full_scale_code_cur = 0x2710,
+       .adc_chans = adc5_chans_pmic,
+       .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
+                               {250, 420, 840},
+       .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+                               {15, 100, 200, 300, 400, 500, 600, 700,
+                               800, 900, 1, 2, 4, 6, 8, 10},
+       .hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+                               {15, 100, 200, 300, 400, 500, 600, 700,
+                               1, 2, 4, 8, 16, 32, 64, 128},
+};
+
+static const struct adc5_data adc5_data_pmic_rev2 = {
+       .full_scale_code_volt = 0x4000,
+       .full_scale_code_cur = 0x1800,
+       .adc_chans = adc5_chans_rev2,
+       .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX])
+                               {256, 512, 1024},
+       .hw_settle_1 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+                               {0, 100, 200, 300, 400, 500, 600, 700,
+                               800, 900, 1, 2, 4, 6, 8, 10},
+       .hw_settle_2 = (unsigned int [VADC_HW_SETTLE_SAMPLES_MAX])
+                               {15, 100, 200, 300, 400, 500, 600, 700,
+                               1, 2, 4, 8, 16, 32, 64, 128},
+};
+
+static const struct of_device_id adc5_match_table[] = {
+       {
+               .compatible = "qcom,spmi-adc5",
+               .data = &adc5_data_pmic,
+       },
+       {
+               .compatible = "qcom,spmi-adc-rev2",
+               .data = &adc5_data_pmic_rev2,
+       },
+       { }
+};
+
+static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
+{
+       const struct adc5_channels *adc_chan;
+       struct iio_chan_spec *iio_chan;
+       struct adc5_channel_prop prop, *chan_props;
+       struct device_node *child;
+       unsigned int index = 0;
+       const struct of_device_id *id;
+       const struct adc5_data *data;
+       int ret;
+
+       adc->nchannels = of_get_available_child_count(node);
+       if (!adc->nchannels)
+               return -EINVAL;
+
+       adc->iio_chans = devm_kcalloc(adc->dev, adc->nchannels,
+                                      sizeof(*adc->iio_chans), GFP_KERNEL);
+       if (!adc->iio_chans)
+               return -ENOMEM;
+
+       adc->chan_props = devm_kcalloc(adc->dev, adc->nchannels,
+                                       sizeof(*adc->chan_props), GFP_KERNEL);
+       if (!adc->chan_props)
+               return -ENOMEM;
+
+       chan_props = adc->chan_props;
+       iio_chan = adc->iio_chans;
+       id = of_match_node(adc5_match_table, node);
+       if (id)
+               data = id->data;
+       else
+               data = &adc5_data_pmic;
+       adc->data = data;
+
+       for_each_available_child_of_node(node, child) {
+               ret = adc5_get_dt_channel_data(adc, &prop, child, data);
+               if (ret) {
+                       of_node_put(child);
+                       return ret;
+               }
+
+               prop.scale_fn_type =
+                       data->adc_chans[prop.channel].scale_fn_type;
+               *chan_props = prop;
+               adc_chan = &data->adc_chans[prop.channel];
+
+               iio_chan->channel = prop.channel;
+               iio_chan->datasheet_name = prop.datasheet_name;
+               iio_chan->extend_name = prop.datasheet_name;
+               iio_chan->info_mask_separate = adc_chan->info_mask;
+               iio_chan->type = adc_chan->type;
+               iio_chan->address = index;
+               iio_chan++;
+               chan_props++;
+               index++;
+       }
+
+       return 0;
+}
+
+static int adc5_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device *dev = &pdev->dev;
+       struct iio_dev *indio_dev;
+       struct adc5_chip *adc;
+       struct regmap *regmap;
+       int ret, irq_eoc;
+       u32 reg;
+
+       regmap = dev_get_regmap(dev->parent, NULL);
+       if (!regmap)
+               return -ENODEV;
+
+       ret = of_property_read_u32(node, "reg", &reg);
+       if (ret < 0)
+               return ret;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       adc = iio_priv(indio_dev);
+       adc->regmap = regmap;
+       adc->dev = dev;
+       adc->base = reg;
+       init_completion(&adc->complete);
+       mutex_init(&adc->lock);
+
+       ret = adc5_get_dt_data(adc, node);
+       if (ret) {
+               pr_err("adc get dt data failed\n");
+               return ret;
+       }
+
+       irq_eoc = platform_get_irq(pdev, 0);
+       if (irq_eoc < 0) {
+               if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
+                       return irq_eoc;
+               adc->poll_eoc = true;
+       } else {
+               ret = devm_request_irq(dev, irq_eoc, adc5_isr, 0,
+                                      "pm-adc5", adc);
+               if (ret)
+                       return ret;
+       }
+
+       indio_dev->dev.parent = dev;
+       indio_dev->dev.of_node = node;
+       indio_dev->name = pdev->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &adc5_info;
+       indio_dev->channels = adc->iio_chans;
+       indio_dev->num_channels = adc->nchannels;
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static struct platform_driver adc5_driver = {
+       .driver = {
+               .name = "qcom-spmi-adc5.c",
+               .of_match_table = adc5_match_table,
+       },
+       .probe = adc5_probe,
+};
+module_platform_driver(adc5_driver);
+
+MODULE_ALIAS("platform:qcom-spmi-adc5");
+MODULE_DESCRIPTION("Qualcomm Technologies Inc. PMIC5 ADC driver");
+MODULE_LICENSE("GPL v2");
index fe3d7826783c0fcd0bae1831f356ba0d5acc86a4..dcd7fb5b9fb24ab21190d2769cb1238db1fdbc13 100644 (file)
@@ -47,8 +47,79 @@ static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
        {44,    125}
 };
 
+/*
+ * Voltage to temperature table for 100k pull up for NTCG104EF104 with
+ * 1.875V reference.
+ */
+static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
+       { 1831, -40000 },
+       { 1814, -35000 },
+       { 1791, -30000 },
+       { 1761, -25000 },
+       { 1723, -20000 },
+       { 1675, -15000 },
+       { 1616, -10000 },
+       { 1545, -5000 },
+       { 1463, 0 },
+       { 1370, 5000 },
+       { 1268, 10000 },
+       { 1160, 15000 },
+       { 1049, 20000 },
+       { 937,  25000 },
+       { 828,  30000 },
+       { 726,  35000 },
+       { 630,  40000 },
+       { 544,  45000 },
+       { 467,  50000 },
+       { 399,  55000 },
+       { 340,  60000 },
+       { 290,  65000 },
+       { 247,  70000 },
+       { 209,  75000 },
+       { 179,  80000 },
+       { 153,  85000 },
+       { 130,  90000 },
+       { 112,  95000 },
+       { 96,   100000 },
+       { 82,   105000 },
+       { 71,   110000 },
+       { 62,   115000 },
+       { 53,   120000 },
+       { 46,   125000 },
+};
+
+static int qcom_vadc_scale_hw_calib_volt(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_uv);
+static int qcom_vadc_scale_hw_calib_therm(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec);
+static int qcom_vadc_scale_hw_smb_temp(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec);
+static int qcom_vadc_scale_hw_chg5_temp(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec);
+static int qcom_vadc_scale_hw_calib_die_temp(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec);
+
+static struct qcom_adc5_scale_type scale_adc5_fn[] = {
+       [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
+       [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
+       [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
+       [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
+       [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
+       [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
+};
+
 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
-                                     u32 tablesize, s32 input, s64 *output)
+                                     u32 tablesize, s32 input, int *output)
 {
        bool descending = 1;
        u32 i = 0;
@@ -128,7 +199,7 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
                                 bool absolute, u16 adc_code,
                                 int *result_mdec)
 {
-       s64 voltage = 0, result = 0;
+       s64 voltage = 0;
        int ret;
 
        qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
@@ -138,12 +209,11 @@ static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
 
        ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
                                         ARRAY_SIZE(adcmap_100k_104ef_104fb),
-                                        voltage, &result);
+                                        voltage, result_mdec);
        if (ret)
                return ret;
 
-       result *= 1000;
-       *result_mdec = result;
+       *result_mdec *= 1000;
 
        return 0;
 }
@@ -191,6 +261,99 @@ static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
        return 0;
 }
 
+static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               unsigned int factor)
+{
+       s64 voltage, temp, adc_vdd_ref_mv = 1875;
+
+       /*
+        * The normal data range is between 0V to 1.875V. On cases where
+        * we read low voltage values, the ADC code can go beyond the
+        * range and the scale result is incorrect so we clamp the values
+        * for the cases where the code represents a value below 0V
+        */
+       if (adc_code > VADC5_MAX_CODE)
+               adc_code = 0;
+
+       /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
+       voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
+       voltage = div64_s64(voltage, data->full_scale_code_volt);
+       if (voltage > 0) {
+               voltage *= prescale->den;
+               temp = prescale->num * factor;
+               voltage = div64_s64(voltage, temp);
+       } else {
+               voltage = 0;
+       }
+
+       return (int) voltage;
+}
+
+static int qcom_vadc_scale_hw_calib_volt(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_uv)
+{
+       *result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
+                               prescale, data, 1);
+
+       return 0;
+}
+
+static int qcom_vadc_scale_hw_calib_therm(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec)
+{
+       int voltage;
+
+       voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
+                               prescale, data, 1000);
+
+       /* Map voltage to temperature from look-up table */
+       return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
+                                ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
+                                voltage, result_mdec);
+}
+
+static int qcom_vadc_scale_hw_calib_die_temp(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec)
+{
+       *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
+                               prescale, data, 2);
+       *result_mdec -= KELVINMIL_CELSIUSMIL;
+
+       return 0;
+}
+
+static int qcom_vadc_scale_hw_smb_temp(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec)
+{
+       *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
+                               prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
+       *result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
+
+       return 0;
+}
+
+static int qcom_vadc_scale_hw_chg5_temp(
+                               const struct vadc_prescale_ratio *prescale,
+                               const struct adc5_data *data,
+                               u16 adc_code, int *result_mdec)
+{
+       *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
+                               prescale, data, 4);
+       *result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
+
+       return 0;
+}
+
 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
                    const struct vadc_linear_graph *calib_graph,
                    const struct vadc_prescale_ratio *prescale,
@@ -221,6 +384,22 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
 }
 EXPORT_SYMBOL(qcom_vadc_scale);
 
+int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
+                   const struct vadc_prescale_ratio *prescale,
+                   const struct adc5_data *data,
+                   u16 adc_code, int *result)
+{
+       if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
+               scaletype < SCALE_HW_CALIB_INVALID)) {
+               pr_err("Invalid scale type %d\n", scaletype);
+               return -EINVAL;
+       }
+
+       return scale_adc5_fn[scaletype].scale_fn(prescale, data,
+                                       adc_code, result);
+}
+EXPORT_SYMBOL(qcom_adc5_hw_scale);
+
 int qcom_vadc_decimation_from_dt(u32 value)
 {
        if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
index 1d5354ff5c7297d5999fc4094e502a2b792592d4..bbb1fa02b382f56499b7dd8aaf4a71f38efb11e4 100644 (file)
 
 #define VADC_DECIMATION_MIN                    512
 #define VADC_DECIMATION_MAX                    4096
+#define ADC5_DEF_VBAT_PRESCALING               1 /* 1:3 */
+#define ADC5_DECIMATION_SHORT                  250
+#define ADC5_DECIMATION_MEDIUM                 420
+#define ADC5_DECIMATION_LONG                   840
+/* Default decimation - 1024 for rev2, 840 for pmic5 */
+#define ADC5_DECIMATION_DEFAULT                        2
+#define ADC5_DECIMATION_SAMPLES_MAX            3
 
 #define VADC_HW_SETTLE_DELAY_MAX               10000
+#define VADC_HW_SETTLE_SAMPLES_MAX             16
 #define VADC_AVG_SAMPLES_MAX                   512
+#define ADC5_AVG_SAMPLES_MAX                   16
 
 #define KELVINMIL_CELSIUSMIL                   273150
+#define PMIC5_CHG_TEMP_SCALE_FACTOR            377500
+#define PMIC5_SMB_TEMP_CONSTANT                        419400
+#define PMIC5_SMB_TEMP_SCALE_FACTOR            356
 
 #define PMI_CHG_SCALE_1                                -138890
 #define PMI_CHG_SCALE_2                                391750000000LL
 
+#define VADC5_MAX_CODE                         0x7fff
+#define ADC5_FULL_SCALE_CODE                   0x70e4
+#define ADC5_USR_DATA_CHECK                    0x8000
+
 /**
  * struct vadc_map_pt - Map the graph representation for ADC channel
  * @x: Represent the ADC digitized code.
@@ -89,6 +105,18 @@ struct vadc_prescale_ratio {
  * SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
  * SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
  * SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
+ * SCALE_HW_CALIB_DEFAULT: Default scaling to convert raw adc code to
+ *     voltage (uV) with hardware applied offset/slope values to adc code.
+ * SCALE_HW_CALIB_THERM_100K_PULLUP: Returns temperature in millidegC using
+ *     lookup table. The hardware applies offset/slope to adc code.
+ * SCALE_HW_CALIB_XOTHERM: Returns XO thermistor voltage in millidegC using
+ *     100k pullup. The hardware applies offset/slope to adc code.
+ * SCALE_HW_CALIB_PMIC_THERM: Returns result in milli degree's Centigrade.
+ *     The hardware applies offset/slope to adc code.
+ * SCALE_HW_CALIB_PM5_CHG_TEMP: Returns result in millidegrees for PMIC5
+ *     charger temperature.
+ * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5
+ *     SMB1390 temperature.
  */
 enum vadc_scale_fn_type {
        SCALE_DEFAULT = 0,
@@ -96,6 +124,22 @@ enum vadc_scale_fn_type {
        SCALE_PMIC_THERM,
        SCALE_XOTHERM,
        SCALE_PMI_CHG_TEMP,
+       SCALE_HW_CALIB_DEFAULT,
+       SCALE_HW_CALIB_THERM_100K_PULLUP,
+       SCALE_HW_CALIB_XOTHERM,
+       SCALE_HW_CALIB_PMIC_THERM,
+       SCALE_HW_CALIB_PM5_CHG_TEMP,
+       SCALE_HW_CALIB_PM5_SMB_TEMP,
+       SCALE_HW_CALIB_INVALID,
+};
+
+struct adc5_data {
+       const u32       full_scale_code_volt;
+       const u32       full_scale_code_cur;
+       const struct adc5_channels *adc_chans;
+       unsigned int    *decimation;
+       unsigned int    *hw_settle_1;
+       unsigned int    *hw_settle_2;
 };
 
 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
@@ -104,6 +148,16 @@ int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
                    bool absolute,
                    u16 adc_code, int *result_mdec);
 
+struct qcom_adc5_scale_type {
+       int (*scale_fn)(const struct vadc_prescale_ratio *prescale,
+               const struct adc5_data *data, u16 adc_code, int *result);
+};
+
+int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
+                   const struct vadc_prescale_ratio *prescale,
+                   const struct adc5_data *data,
+                   u16 adc_code, int *result_mdec);
+
 int qcom_vadc_decimation_from_dt(u32 value);
 
 #endif /* QCOM_VADC_COMMON_H */
index dcb50172186f49ab62722997cc34a55bdb667a06..4e982b51bcda7bc4dc1a1cdad5e7b29507e7aac9 100644 (file)
@@ -343,8 +343,8 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
        for_each_child_of_node(np, child) {
                of_id = of_match_node(rcar_gyroadc_child_match, child);
                if (!of_id) {
-                       dev_err(dev, "Ignoring unsupported ADC \"%s\".",
-                               child->name);
+                       dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".",
+                               child);
                        continue;
                }
 
@@ -381,16 +381,16 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
                        ret = of_property_read_u32(child, "reg", &reg);
                        if (ret) {
                                dev_err(dev,
-                                       "Failed to get child reg property of ADC \"%s\".\n",
-                                       child->name);
+                                       "Failed to get child reg property of ADC \"%pOFn\".\n",
+                                       child);
                                return ret;
                        }
 
                        /* Channel number is too high. */
                        if (reg >= num_channels) {
                                dev_err(dev,
-                                       "Only %i channels supported with %s, but reg = <%i>.\n",
-                                       num_channels, child->name, reg);
+                                       "Only %i channels supported with %pOFn, but reg = <%i>.\n",
+                                       num_channels, child, reg);
                                return ret;
                        }
                }
index 2b60efea0c39fdf27497ee4a5432337bf4126e99..7940b23dcad901baa00784ee48497e0f1dd99ec7 100644 (file)
@@ -5,10 +5,12 @@
 #include <linux/iio/iio.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/slab.h>
 
 /* PMIC global registers definition */
 #define SC27XX_MODULE_EN               0xc08
@@ -87,16 +89,73 @@ struct sc27xx_adc_linear_graph {
  * should use the small-scale graph, and if more than 1.2v, we should use the
  * big-scale graph.
  */
-static const struct sc27xx_adc_linear_graph big_scale_graph = {
+static struct sc27xx_adc_linear_graph big_scale_graph = {
        4200, 3310,
        3600, 2832,
 };
 
-static const struct sc27xx_adc_linear_graph small_scale_graph = {
+static struct sc27xx_adc_linear_graph small_scale_graph = {
        1000, 3413,
        100, 341,
 };
 
+static const struct sc27xx_adc_linear_graph big_scale_graph_calib = {
+       4200, 856,
+       3600, 733,
+};
+
+static const struct sc27xx_adc_linear_graph small_scale_graph_calib = {
+       1000, 833,
+       100, 80,
+};
+
+static int sc27xx_adc_get_calib_data(u32 calib_data, int calib_adc)
+{
+       return ((calib_data & 0xff) + calib_adc - 128) * 4;
+}
+
+static int sc27xx_adc_scale_calibration(struct sc27xx_adc_data *data,
+                                       bool big_scale)
+{
+       const struct sc27xx_adc_linear_graph *calib_graph;
+       struct sc27xx_adc_linear_graph *graph;
+       struct nvmem_cell *cell;
+       const char *cell_name;
+       u32 calib_data = 0;
+       void *buf;
+       size_t len;
+
+       if (big_scale) {
+               calib_graph = &big_scale_graph_calib;
+               graph = &big_scale_graph;
+               cell_name = "big_scale_calib";
+       } else {
+               calib_graph = &small_scale_graph_calib;
+               graph = &small_scale_graph;
+               cell_name = "small_scale_calib";
+       }
+
+       cell = nvmem_cell_get(data->dev, cell_name);
+       if (IS_ERR(cell))
+               return PTR_ERR(cell);
+
+       buf = nvmem_cell_read(cell, &len);
+       nvmem_cell_put(cell);
+
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       memcpy(&calib_data, buf, min(len, sizeof(u32)));
+
+       /* Only need to calibrate the adc values in the linear graph. */
+       graph->adc0 = sc27xx_adc_get_calib_data(calib_data, calib_graph->adc0);
+       graph->adc1 = sc27xx_adc_get_calib_data(calib_data >> 8,
+                                               calib_graph->adc1);
+
+       kfree(buf);
+       return 0;
+}
+
 static int sc27xx_adc_get_ratio(int channel, int scale)
 {
        switch (channel) {
@@ -209,7 +268,7 @@ static void sc27xx_adc_volt_ratio(struct sc27xx_adc_data *data,
        *div_denominator = ratio & SC27XX_RATIO_DENOMINATOR_MASK;
 }
 
-static int sc27xx_adc_to_volt(const struct sc27xx_adc_linear_graph *graph,
+static int sc27xx_adc_to_volt(struct sc27xx_adc_linear_graph *graph,
                              int raw_adc)
 {
        int tmp;
@@ -273,6 +332,17 @@ static int sc27xx_adc_read_raw(struct iio_dev *indio_dev,
        int ret, tmp;
 
        switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&indio_dev->mlock);
+               ret = sc27xx_adc_read(data, chan->channel, scale, &tmp);
+               mutex_unlock(&indio_dev->mlock);
+
+               if (ret)
+                       return ret;
+
+               *val = tmp;
+               return IIO_VAL_INT;
+
        case IIO_CHAN_INFO_PROCESSED:
                mutex_lock(&indio_dev->mlock);
                ret = sc27xx_adc_read_processed(data, chan->channel, scale,
@@ -315,48 +385,47 @@ static const struct iio_info sc27xx_info = {
        .write_raw = &sc27xx_adc_write_raw,
 };
 
-#define SC27XX_ADC_CHANNEL(index) {                            \
+#define SC27XX_ADC_CHANNEL(index, mask) {                      \
        .type = IIO_VOLTAGE,                                    \
        .channel = index,                                       \
-       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |    \
-                             BIT(IIO_CHAN_INFO_SCALE),         \
+       .info_mask_separate = mask | BIT(IIO_CHAN_INFO_SCALE),  \
        .datasheet_name = "CH##index",                          \
        .indexed = 1,                                           \
 }
 
 static const struct iio_chan_spec sc27xx_channels[] = {
-       SC27XX_ADC_CHANNEL(0),
-       SC27XX_ADC_CHANNEL(1),
-       SC27XX_ADC_CHANNEL(2),
-       SC27XX_ADC_CHANNEL(3),
-       SC27XX_ADC_CHANNEL(4),
-       SC27XX_ADC_CHANNEL(5),
-       SC27XX_ADC_CHANNEL(6),
-       SC27XX_ADC_CHANNEL(7),
-       SC27XX_ADC_CHANNEL(8),
-       SC27XX_ADC_CHANNEL(9),
-       SC27XX_ADC_CHANNEL(10),
-       SC27XX_ADC_CHANNEL(11),
-       SC27XX_ADC_CHANNEL(12),
-       SC27XX_ADC_CHANNEL(13),
-       SC27XX_ADC_CHANNEL(14),
-       SC27XX_ADC_CHANNEL(15),
-       SC27XX_ADC_CHANNEL(16),
-       SC27XX_ADC_CHANNEL(17),
-       SC27XX_ADC_CHANNEL(18),
-       SC27XX_ADC_CHANNEL(19),
-       SC27XX_ADC_CHANNEL(20),
-       SC27XX_ADC_CHANNEL(21),
-       SC27XX_ADC_CHANNEL(22),
-       SC27XX_ADC_CHANNEL(23),
-       SC27XX_ADC_CHANNEL(24),
-       SC27XX_ADC_CHANNEL(25),
-       SC27XX_ADC_CHANNEL(26),
-       SC27XX_ADC_CHANNEL(27),
-       SC27XX_ADC_CHANNEL(28),
-       SC27XX_ADC_CHANNEL(29),
-       SC27XX_ADC_CHANNEL(30),
-       SC27XX_ADC_CHANNEL(31),
+       SC27XX_ADC_CHANNEL(0, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(1, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(2, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(3, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(4, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(5, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(6, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(7, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(8, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(9, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(10, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(11, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(12, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(13, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(14, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(15, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(16, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(17, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(18, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(19, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(20, BIT(IIO_CHAN_INFO_RAW)),
+       SC27XX_ADC_CHANNEL(21, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(22, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(23, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(24, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(25, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(26, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(27, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(28, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(29, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(30, BIT(IIO_CHAN_INFO_PROCESSED)),
+       SC27XX_ADC_CHANNEL(31, BIT(IIO_CHAN_INFO_PROCESSED)),
 };
 
 static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
@@ -380,6 +449,15 @@ static int sc27xx_adc_enable(struct sc27xx_adc_data *data)
        if (ret)
                goto disable_clk;
 
+       /* ADC channel scales' calibration from nvmem device */
+       ret = sc27xx_adc_scale_calibration(data, true);
+       if (ret)
+               goto disable_clk;
+
+       ret = sc27xx_adc_scale_calibration(data, false);
+       if (ret)
+               goto disable_clk;
+
        return 0;
 
 disable_clk:
index 0138337aedd10d52660a42fdcc333dfe9ac169dd..4b76b61ba4bee2e2c15e919e11349d020059ea81 100644 (file)
@@ -209,6 +209,6 @@ static struct spi_driver ad8366_driver = {
 
 module_spi_driver(ad8366_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
 MODULE_LICENSE("GPL v2");
index e049323f209ae83ba8a8fd35deec4e9934cc146e..0ae89b87e2d6451fbe177e0978b2179ab4c4487b 100644 (file)
@@ -4,10 +4,10 @@
 
 #define BME680_REG_CHIP_I2C_ID                 0xD0
 #define BME680_REG_CHIP_SPI_ID                 0x50
-#define BME680_CHIP_ID_VAL                     0x61
+#define   BME680_CHIP_ID_VAL                   0x61
 #define BME680_REG_SOFT_RESET_I2C              0xE0
 #define BME680_REG_SOFT_RESET_SPI              0x60
-#define BME680_CMD_SOFTRESET                   0xB6
+#define   BME680_CMD_SOFTRESET                 0xB6
 #define BME680_REG_STATUS                      0x73
 #define   BME680_SPI_MEM_PAGE_BIT              BIT(4)
 #define     BME680_SPI_MEM_PAGE_1_VAL          1
@@ -18,6 +18,7 @@
 #define BME680_REG_GAS_MSB                     0x2A
 #define BME680_REG_GAS_R_LSB                   0x2B
 #define   BME680_GAS_STAB_BIT                  BIT(4)
+#define   BME680_GAS_RANGE_MASK                        GENMASK(3, 0)
 
 #define BME680_REG_CTRL_HUMIDITY               0x72
 #define   BME680_OSRS_HUMIDITY_MASK            GENMASK(2, 0)
@@ -26,9 +27,8 @@
 #define   BME680_OSRS_TEMP_MASK                        GENMASK(7, 5)
 #define   BME680_OSRS_PRESS_MASK               GENMASK(4, 2)
 #define   BME680_MODE_MASK                     GENMASK(1, 0)
-
-#define BME680_MODE_FORCED                     1
-#define BME680_MODE_SLEEP                      0
+#define     BME680_MODE_FORCED                 1
+#define     BME680_MODE_SLEEP                  0
 
 #define BME680_REG_CONFIG                      0x75
 #define   BME680_FILTER_MASK                   GENMASK(4, 2)
 
 #define BME680_MAX_OVERFLOW_VAL                        0x40000000
 #define BME680_HUM_REG_SHIFT_VAL               4
-#define BME680_BIT_H1_DATA_MSK                 0x0F
+#define BME680_BIT_H1_DATA_MASK                        GENMASK(3, 0)
 
 #define BME680_REG_RES_HEAT_RANGE              0x02
-#define BME680_RHRANGE_MSK                     0x30
+#define   BME680_RHRANGE_MASK                  GENMASK(5, 4)
 #define BME680_REG_RES_HEAT_VAL                        0x00
 #define BME680_REG_RANGE_SW_ERR                        0x04
-#define BME680_RSERROR_MSK                     0xF0
+#define   BME680_RSERROR_MASK                  GENMASK(7, 4)
 #define BME680_REG_RES_HEAT_0                  0x5A
 #define BME680_REG_GAS_WAIT_0                  0x64
-#define BME680_GAS_RANGE_MASK                  0x0F
 #define BME680_ADC_GAS_RES_SHIFT               6
 #define BME680_AMB_TEMP                                25
 
 #define BME680_REG_CTRL_GAS_1                  0x71
 #define   BME680_RUN_GAS_MASK                  BIT(4)
 #define   BME680_NB_CONV_MASK                  GENMASK(3, 0)
-#define     BME680_RUN_GAS_EN_BIT              BIT(4)
-#define     BME680_NB_CONV_0_VAL               0
 
 #define BME680_REG_MEAS_STAT_0                 0x1D
 #define   BME680_GAS_MEAS_BIT                  BIT(6)
index 7d9bb62baa3fd3e8620f377143ecaca9dae69ae4..70c1fe4366f4c6a17100b469452f8903281e665e 100644 (file)
@@ -91,8 +91,6 @@ static const struct iio_chan_spec bme680_channels[] = {
        },
 };
 
-static const int bme680_oversampling_avail[] = { 1, 2, 4, 8, 16 };
-
 static int bme680_read_calib(struct bme680_data *data,
                             struct bme680_calib *calib)
 {
@@ -102,16 +100,14 @@ static int bme680_read_calib(struct bme680_data *data,
        __le16 buf;
 
        /* Temperature related coefficients */
-       ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_T1_LSB_REG\n");
                return ret;
        }
        calib->par_t1 = le16_to_cpu(buf);
 
-       ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_T2_LSB_REG\n");
                return ret;
@@ -126,16 +122,14 @@ static int bme680_read_calib(struct bme680_data *data,
        calib->par_t3 = tmp;
 
        /* Pressure related coefficients */
-       ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_P1_LSB_REG\n");
                return ret;
        }
        calib->par_p1 = le16_to_cpu(buf);
 
-       ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_P2_LSB_REG\n");
                return ret;
@@ -149,16 +143,14 @@ static int bme680_read_calib(struct bme680_data *data,
        }
        calib->par_p3 = tmp;
 
-       ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_P4_LSB_REG\n");
                return ret;
        }
        calib->par_p4 = le16_to_cpu(buf);
 
-       ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_P5_LSB_REG\n");
                return ret;
@@ -179,16 +171,14 @@ static int bme680_read_calib(struct bme680_data *data,
        }
        calib->par_p7 = tmp;
 
-       ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_P8_LSB_REG\n");
                return ret;
        }
        calib->par_p8 = le16_to_cpu(buf);
 
-       ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG, (u8 *) &buf, 2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_P9_LSB_REG\n");
                return ret;
@@ -208,30 +198,26 @@ static int bme680_read_calib(struct bme680_data *data,
                dev_err(dev, "failed to read BME680_H1_MSB_REG\n");
                return ret;
        }
-
        ret = regmap_read(data->regmap, BME680_H1_LSB_REG, &tmp_lsb);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_H1_LSB_REG\n");
                return ret;
        }
-
        calib->par_h1 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
-                               (tmp_lsb & BME680_BIT_H1_DATA_MSK);
+                       (tmp_lsb & BME680_BIT_H1_DATA_MASK);
 
        ret = regmap_read(data->regmap, BME680_H2_MSB_REG, &tmp_msb);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_H2_MSB_REG\n");
                return ret;
        }
-
        ret = regmap_read(data->regmap, BME680_H2_LSB_REG, &tmp_lsb);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_H2_LSB_REG\n");
                return ret;
        }
-
        calib->par_h2 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
-                               (tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
+                       (tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
 
        ret = regmap_read(data->regmap, BME680_H3_REG, &tmp);
        if (ret < 0) {
@@ -276,8 +262,8 @@ static int bme680_read_calib(struct bme680_data *data,
        }
        calib->par_gh1 = tmp;
 
-       ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG,
-                              (u8 *) &buf, 2);
+       ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG, (u8 *) &buf,
+                              2);
        if (ret < 0) {
                dev_err(dev, "failed to read BME680_GH2_LSB_REG\n");
                return ret;
@@ -297,7 +283,7 @@ static int bme680_read_calib(struct bme680_data *data,
                dev_err(dev, "failed to read resistance heat range\n");
                return ret;
        }
-       calib->res_heat_range = (tmp & BME680_RHRANGE_MSK) / 16;
+       calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, tmp);
 
        ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_VAL, &tmp);
        if (ret < 0) {
@@ -311,7 +297,7 @@ static int bme680_read_calib(struct bme680_data *data,
                dev_err(dev, "failed to read range software error\n");
                return ret;
        }
-       calib->range_sw_err = (tmp & BME680_RSERROR_MSK) / 16;
+       calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, tmp);
 
        return 0;
 }
@@ -408,10 +394,7 @@ static u32 bme680_compensate_humid(struct bme680_data *data,
        var6 = (var4 * var5) >> 1;
        calc_hum = (((var3 + var6) >> 10) * 1000) >> 12;
 
-       if (calc_hum > 100000) /* Cap at 100%rH */
-               calc_hum = 100000;
-       else if (calc_hum < 0)
-               calc_hum = 0;
+       calc_hum = clamp(calc_hum, 0, 100000); /* clamp between 0-100 %rH */
 
        return calc_hum;
 }
@@ -518,12 +501,20 @@ static int bme680_set_mode(struct bme680_data *data, bool mode)
        return ret;
 }
 
+static u8 bme680_oversampling_to_reg(u8 val)
+{
+       return ilog2(val) + 1;
+}
+
 static int bme680_chip_config(struct bme680_data *data)
 {
        struct device *dev = regmap_get_device(data->regmap);
        int ret;
-       u8 osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK,
-                            data->oversampling_humid + 1);
+       u8 osrs;
+
+       osrs = FIELD_PREP(
+               BME680_OSRS_HUMIDITY_MASK,
+               bme680_oversampling_to_reg(data->oversampling_humid));
        /*
         * Highly recommended to set oversampling of humidity before
         * temperature/pressure oversampling.
@@ -544,12 +535,12 @@ static int bme680_chip_config(struct bme680_data *data)
                return ret;
        }
 
-       osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
-              FIELD_PREP(BME680_OSRS_PRESS_MASK, data->oversampling_press + 1);
-
+       osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK,
+                         bme680_oversampling_to_reg(data->oversampling_temp)) |
+              FIELD_PREP(BME680_OSRS_PRESS_MASK,
+                         bme680_oversampling_to_reg(data->oversampling_press));
        ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
-                               BME680_OSRS_TEMP_MASK |
-                               BME680_OSRS_PRESS_MASK,
+                               BME680_OSRS_TEMP_MASK | BME680_OSRS_PRESS_MASK,
                                osrs);
        if (ret < 0)
                dev_err(dev, "failed to write ctrl_meas register\n");
@@ -577,14 +568,15 @@ static int bme680_gas_config(struct bme680_data *data)
        /* set target heating duration */
        ret = regmap_write(data->regmap, BME680_REG_GAS_WAIT_0, heatr_dur);
        if (ret < 0) {
-               dev_err(dev, "failted to write gas_wait_0 register\n");
+               dev_err(dev, "failed to write gas_wait_0 register\n");
                return ret;
        }
 
-       /* Selecting the runGas and NB conversion settings for the sensor */
+       /* Enable the gas sensor and select heater profile set-point 0 */
        ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1,
                                 BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK,
-                                BME680_RUN_GAS_EN_BIT | BME680_NB_CONV_0_VAL);
+                                FIELD_PREP(BME680_RUN_GAS_MASK, 1) |
+                                FIELD_PREP(BME680_NB_CONV_MASK, 0));
        if (ret < 0)
                dev_err(dev, "failed to write ctrl_gas_1 register\n");
 
@@ -782,13 +774,13 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
                switch (chan->type) {
                case IIO_TEMP:
-                       *val = 1 << data->oversampling_temp;
+                       *val = data->oversampling_temp;
                        return IIO_VAL_INT;
                case IIO_PRESSURE:
-                       *val = 1 << data->oversampling_press;
+                       *val = data->oversampling_press;
                        return IIO_VAL_INT;
                case IIO_HUMIDITYRELATIVE:
-                       *val = 1 << data->oversampling_humid;
+                       *val = data->oversampling_humid;
                        return IIO_VAL_INT;
                default:
                        return -EINVAL;
@@ -798,52 +790,9 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
        }
 }
 
-static int bme680_write_oversampling_ratio_temp(struct bme680_data *data,
-                                               int val)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
-               if (bme680_oversampling_avail[i] == val) {
-                       data->oversampling_temp = ilog2(val);
-
-                       return bme680_chip_config(data);
-               }
-       }
-
-       return -EINVAL;
-}
-
-static int bme680_write_oversampling_ratio_press(struct bme680_data *data,
-                                                int val)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
-               if (bme680_oversampling_avail[i] == val) {
-                       data->oversampling_press = ilog2(val);
-
-                       return bme680_chip_config(data);
-               }
-       }
-
-       return -EINVAL;
-}
-
-static int bme680_write_oversampling_ratio_humid(struct bme680_data *data,
-                                                int val)
+static bool bme680_is_valid_oversampling(int rate)
 {
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
-               if (bme680_oversampling_avail[i] == val) {
-                       data->oversampling_humid = ilog2(val);
-
-                       return bme680_chip_config(data);
-               }
-       }
-
-       return -EINVAL;
+       return (rate > 0 && rate <= 16 && is_power_of_2(rate));
 }
 
 static int bme680_write_raw(struct iio_dev *indio_dev,
@@ -852,18 +801,31 @@ static int bme680_write_raw(struct iio_dev *indio_dev,
 {
        struct bme680_data *data = iio_priv(indio_dev);
 
+       if (val2 != 0)
+               return -EINVAL;
+
        switch (mask) {
        case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+       {
+               if (!bme680_is_valid_oversampling(val))
+                       return -EINVAL;
+
                switch (chan->type) {
                case IIO_TEMP:
-                       return bme680_write_oversampling_ratio_temp(data, val);
+                       data->oversampling_temp = val;
+                       break;
                case IIO_PRESSURE:
-                       return bme680_write_oversampling_ratio_press(data, val);
+                       data->oversampling_press = val;
+                       break;
                case IIO_HUMIDITYRELATIVE:
-                       return bme680_write_oversampling_ratio_humid(data, val);
+                       data->oversampling_humid = val;
+                       break;
                default:
                        return -EINVAL;
                }
+
+               return bme680_chip_config(data);
+       }
        default:
                return -EINVAL;
        }
@@ -925,9 +887,9 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
        indio_dev->modes = INDIO_DIRECT_MODE;
 
        /* default values for the sensor */
-       data->oversampling_humid = ilog2(2); /* 2X oversampling rate */
-       data->oversampling_press = ilog2(4); /* 4X oversampling rate */
-       data->oversampling_temp = ilog2(8);  /* 8X oversampling rate */
+       data->oversampling_humid = 2; /* 2X oversampling rate */
+       data->oversampling_press = 4; /* 4X oversampling rate */
+       data->oversampling_temp = 8;  /* 8X oversampling rate */
        data->heater_temp = 320; /* degree Celsius */
        data->heater_dur = 150;  /* milliseconds */
 
index 80beb64e9e0c66d843fd1acb6d721d6c7c163994..bb2057fd1b6f54e2fd69f679196e313d4cb2166d 100644 (file)
@@ -120,6 +120,16 @@ config AD5624R_SPI
          Say yes here to build support for Analog Devices AD5624R, AD5644R and
          AD5664R converters (DAC). This driver uses the common SPI interface.
 
+config LTC1660
+       tristate "Linear Technology LTC1660/LTC1665 DAC SPI driver"
+       depends on SPI
+       help
+         Say yes here to build support for Linear Technology
+         LTC1660 and LTC1665 Digital to Analog Converters.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ltc1660.
+
 config LTC2632
        tristate "Linear Technology LTC2632-12/10/8 DAC spi driver"
        depends on SPI
index a1b37cf9944165fcaef0db42d85149aaab88a233..2ac93cc4a38937d849c9580ae5fef85cc7a36d53 100644 (file)
@@ -29,6 +29,7 @@ obj-$(CONFIG_CIO_DAC) += cio-dac.o
 obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
 obj-$(CONFIG_DS4424) += ds4424.o
 obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
+obj-$(CONFIG_LTC1660) += ltc1660.o
 obj-$(CONFIG_LTC2632) += ltc2632.o
 obj-$(CONFIG_M62332) += m62332.o
 obj-$(CONFIG_MAX517) += max517.o
index fd26a4272fc5bc98284d1491e25cd86f16d8f80d..c3426708b6b559c543ac916ead8be58858bdc639 100644 (file)
@@ -628,6 +628,6 @@ static void __exit ad5446_exit(void)
 }
 module_exit(ad5446_exit);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC");
 MODULE_LICENSE("GPL v2");
index d9037ea59168ef1664b4e6841082b5b4b98b3e01..0ae23a268017ea4c511a6d6db9719ae50a42f56f 100644 (file)
@@ -369,6 +369,6 @@ static struct spi_driver ad5504_driver = {
 };
 module_spi_driver(ad5504_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC");
 MODULE_LICENSE("GPL v2");
index 2ddbfc3fdbae7430330466c9dc386ae8d3e26603..0e134b13967a5b85d68e023544178cbac434e6d8 100644 (file)
@@ -470,6 +470,6 @@ int ad5686_remove(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(ad5686_remove);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC");
 MODULE_LICENSE("GPL v2");
index bd36333257af8bf334bedbda9012bb4f8c9a6dfb..ef41f12bf2620c7e9e163d4c272e62dfa4d90b78 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/property.h>
 #include <linux/spi/spi.h>
+#include <linux/gpio/consumer.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
@@ -108,6 +109,7 @@ struct ad5758_range {
 struct ad5758_state {
        struct spi_device *spi;
        struct mutex lock;
+       struct gpio_desc *gpio_reset;
        struct ad5758_range out_range;
        unsigned int dc_dc_mode;
        unsigned int dc_dc_ilim;
@@ -474,6 +476,21 @@ static int ad5758_internal_buffers_en(struct ad5758_state *st, bool enable)
                                             AD5758_CAL_MEM_UNREFRESHED_MSK);
 }
 
+static int ad5758_reset(struct ad5758_state *st)
+{
+       if (st->gpio_reset) {
+               gpiod_set_value(st->gpio_reset, 0);
+               usleep_range(100, 1000);
+               gpiod_set_value(st->gpio_reset, 1);
+               usleep_range(100, 1000);
+
+               return 0;
+       } else {
+               /* Perform a software reset */
+               return ad5758_soft_reset(st);
+       }
+}
+
 static int ad5758_reg_access(struct iio_dev *indio_dev,
                             unsigned int reg,
                             unsigned int writeval,
@@ -768,13 +785,18 @@ static int ad5758_init(struct ad5758_state *st)
 {
        int regval, ret;
 
+       st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
+                                                GPIOD_OUT_HIGH);
+       if (IS_ERR(st->gpio_reset))
+               return PTR_ERR(st->gpio_reset);
+
        /* Disable CRC checks */
        ret = ad5758_crc_disable(st);
        if (ret < 0)
                return ret;
 
-       /* Perform a software reset */
-       ret = ad5758_soft_reset(st);
+       /* Perform a reset */
+       ret = ad5758_reset(st);
        if (ret < 0)
                return ret;
 
index 7569bf6868c277cf6141b3ad44674ad6bf472eb3..84ce5e6ecf3f8eb938fec8be09149aed3d12b21c 100644 (file)
@@ -467,6 +467,6 @@ static struct spi_driver ad5791_driver = {
 };
 module_spi_driver(ad5791_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC");
 MODULE_LICENSE("GPL v2");
index aaa2103d7c2b7229709609af7f71c1ad7fa8cc8e..a791d0a09d3b5c47b46c1589018d37b33ff655a1 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * IIO DAC emulation driver using a digital potentiometer
  *
  * Copyright (C) 2016 Axentia Technologies AB
  *
  * Author: Peter Rosin <peda@axentia.se>
- *
- * 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.
  */
 
 /*
diff --git a/drivers/iio/dac/ltc1660.c b/drivers/iio/dac/ltc1660.c
new file mode 100644 (file)
index 0000000..1086683
--- /dev/null
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for Linear Technology LTC1665/LTC1660, 8 channels DAC
+ *
+ * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
+ */
+#include <linux/bitops.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#define LTC1660_REG_WAKE       0x0
+#define LTC1660_REG_DAC_A      0x1
+#define LTC1660_REG_DAC_B      0x2
+#define LTC1660_REG_DAC_C      0x3
+#define LTC1660_REG_DAC_D      0x4
+#define LTC1660_REG_DAC_E      0x5
+#define LTC1660_REG_DAC_F      0x6
+#define LTC1660_REG_DAC_G      0x7
+#define LTC1660_REG_DAC_H      0x8
+#define LTC1660_REG_SLEEP      0xe
+
+#define LTC1660_NUM_CHANNELS   8
+
+static const struct regmap_config ltc1660_regmap_config = {
+       .reg_bits = 4,
+       .val_bits = 12,
+};
+
+enum ltc1660_supported_device_ids {
+       ID_LTC1660,
+       ID_LTC1665,
+};
+
+struct ltc1660_priv {
+       struct spi_device *spi;
+       struct regmap *regmap;
+       struct regulator *vref_reg;
+       unsigned int value[LTC1660_NUM_CHANNELS];
+       unsigned int vref_mv;
+};
+
+static int ltc1660_read_raw(struct iio_dev *indio_dev,
+               struct iio_chan_spec const *chan,
+               int *val,
+               int *val2,
+               long mask)
+{
+       struct ltc1660_priv *priv = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               *val = priv->value[chan->channel];
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = regulator_get_voltage(priv->vref_reg);
+               if (*val < 0) {
+                       dev_err(&priv->spi->dev, "failed to read vref regulator: %d\n",
+                                       *val);
+                       return *val;
+               }
+
+               /* Convert to mV */
+               *val /= 1000;
+               *val2 = chan->scan_type.realbits;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ltc1660_write_raw(struct iio_dev *indio_dev,
+               struct iio_chan_spec const *chan,
+               int val,
+               int val2,
+               long mask)
+{
+       struct ltc1660_priv *priv = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               if (val2 != 0)
+                       return -EINVAL;
+
+               if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
+                       return -EINVAL;
+
+               ret = regmap_write(priv->regmap, chan->channel,
+                                       (val << chan->scan_type.shift));
+               if (!ret)
+                       priv->value[chan->channel] = val;
+
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+#define LTC1660_CHAN(chan, bits) {                     \
+       .type = IIO_VOLTAGE,                            \
+       .indexed = 1,                                   \
+       .output = 1,                                    \
+       .channel = chan,                                \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+       .scan_type = {                                  \
+               .sign = 'u',                            \
+               .realbits = (bits),                     \
+               .storagebits = 16,                      \
+               .shift = 12 - (bits),                   \
+       },                                              \
+}
+
+#define  LTC1660_OCTAL_CHANNELS(bits) {                        \
+               LTC1660_CHAN(LTC1660_REG_DAC_A, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_B, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_C, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_D, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_E, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_F, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_G, bits),  \
+               LTC1660_CHAN(LTC1660_REG_DAC_H, bits),  \
+}
+
+static const struct iio_chan_spec ltc1660_channels[][LTC1660_NUM_CHANNELS] = {
+       [ID_LTC1660] = LTC1660_OCTAL_CHANNELS(10),
+       [ID_LTC1665] = LTC1660_OCTAL_CHANNELS(8),
+};
+
+static const struct iio_info ltc1660_info = {
+       .read_raw = &ltc1660_read_raw,
+       .write_raw = &ltc1660_write_raw,
+};
+
+static int __maybe_unused ltc1660_suspend(struct device *dev)
+{
+       struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(
+                                               to_spi_device(dev)));
+       return regmap_write(priv->regmap, LTC1660_REG_SLEEP, 0x00);
+}
+
+static int __maybe_unused ltc1660_resume(struct device *dev)
+{
+       struct ltc1660_priv *priv = iio_priv(spi_get_drvdata(
+                                               to_spi_device(dev)));
+       return regmap_write(priv->regmap, LTC1660_REG_WAKE, 0x00);
+}
+static SIMPLE_DEV_PM_OPS(ltc1660_pm_ops, ltc1660_suspend, ltc1660_resume);
+
+static int ltc1660_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct ltc1660_priv *priv;
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
+       if (indio_dev == NULL)
+               return -ENOMEM;
+
+       priv = iio_priv(indio_dev);
+       priv->regmap = devm_regmap_init_spi(spi, &ltc1660_regmap_config);
+       if (IS_ERR(priv->regmap)) {
+               dev_err(&spi->dev, "failed to register spi regmap %ld\n",
+                       PTR_ERR(priv->regmap));
+               return PTR_ERR(priv->regmap);
+       }
+
+       priv->vref_reg = devm_regulator_get(&spi->dev, "vref");
+       if (IS_ERR(priv->vref_reg)) {
+               dev_err(&spi->dev, "vref regulator not specified\n");
+               return PTR_ERR(priv->vref_reg);
+       }
+
+       ret = regulator_enable(priv->vref_reg);
+       if (ret) {
+               dev_err(&spi->dev, "failed to enable vref regulator: %d\n",
+                               ret);
+               return ret;
+       }
+
+       priv->spi = spi;
+       spi_set_drvdata(spi, indio_dev);
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->info = &ltc1660_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = ltc1660_channels[id->driver_data];
+       indio_dev->num_channels = LTC1660_NUM_CHANNELS;
+       indio_dev->name = id->name;
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(&spi->dev, "failed to register iio device: %d\n",
+                               ret);
+               goto error_disable_reg;
+       }
+
+       return 0;
+
+error_disable_reg:
+       regulator_disable(priv->vref_reg);
+
+       return ret;
+}
+
+static int ltc1660_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct ltc1660_priv *priv = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       regulator_disable(priv->vref_reg);
+
+       return 0;
+}
+
+static const struct of_device_id ltc1660_dt_ids[] = {
+       { .compatible = "lltc,ltc1660", .data = (void *)ID_LTC1660 },
+       { .compatible = "lltc,ltc1665", .data = (void *)ID_LTC1665 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ltc1660_dt_ids);
+
+static const struct spi_device_id ltc1660_id[] = {
+       {"ltc1660", ID_LTC1660},
+       {"ltc1665", ID_LTC1665},
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(spi, ltc1660_id);
+
+static struct spi_driver ltc1660_driver = {
+       .driver = {
+               .name = "ltc1660",
+               .of_match_table = ltc1660_dt_ids,
+               .pm = &ltc1660_pm_ops,
+       },
+       .probe  = ltc1660_probe,
+       .remove = ltc1660_remove,
+       .id_table = ltc1660_id,
+};
+module_spi_driver(ltc1660_driver);
+
+MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
+MODULE_DESCRIPTION("Linear Technology LTC1660/LTC1665 DAC");
+MODULE_LICENSE("GPL v2");
index 1d853247a20598feda1913990a680bd06e5533c9..451d10e323cff1ff6d3a033e21b4129ad6ffe3c7 100644 (file)
@@ -113,15 +113,14 @@ static int max517_write_raw(struct iio_dev *indio_dev,
        return ret;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int max517_suspend(struct device *dev)
+static int __maybe_unused max517_suspend(struct device *dev)
 {
        u8 outbuf = COMMAND_PD;
 
        return i2c_master_send(to_i2c_client(dev), &outbuf, 1);
 }
 
-static int max517_resume(struct device *dev)
+static int __maybe_unused max517_resume(struct device *dev)
 {
        u8 outbuf = 0;
 
@@ -129,10 +128,6 @@ static int max517_resume(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(max517_pm_ops, max517_suspend, max517_resume);
-#define MAX517_PM_OPS (&max517_pm_ops)
-#else
-#define MAX517_PM_OPS NULL
-#endif
 
 static const struct iio_info max517_info = {
        .read_raw = max517_read_raw,
@@ -229,7 +224,7 @@ MODULE_DEVICE_TABLE(i2c, max517_id);
 static struct i2c_driver max517_driver = {
        .driver = {
                .name   = MAX517_DRV_NAME,
-               .pm             = MAX517_PM_OPS,
+               .pm     = &max517_pm_ops,
        },
        .probe          = max517_probe,
        .remove         = max517_remove,
index d0ecc1fdd8fcd1d5d31108664f8157765e5db6c8..f0cf6903dcd2a92b2886661264418d74eec043b2 100644 (file)
@@ -270,8 +270,7 @@ static int max5821_write_raw(struct iio_dev *indio_dev,
        }
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int max5821_suspend(struct device *dev)
+static int __maybe_unused max5821_suspend(struct device *dev)
 {
        u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
                         MAX5821_EXTENDED_DAC_A |
@@ -281,7 +280,7 @@ static int max5821_suspend(struct device *dev)
        return i2c_master_send(to_i2c_client(dev), outbuf, 2);
 }
 
-static int max5821_resume(struct device *dev)
+static int __maybe_unused max5821_resume(struct device *dev)
 {
        u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE,
                         MAX5821_EXTENDED_DAC_A |
@@ -292,10 +291,6 @@ static int max5821_resume(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume);
-#define MAX5821_PM_OPS (&max5821_pm_ops)
-#else
-#define MAX5821_PM_OPS NULL
-#endif /* CONFIG_PM_SLEEP */
 
 static const struct iio_info max5821_info = {
        .read_raw = max5821_read_raw,
@@ -392,7 +387,7 @@ static struct i2c_driver max5821_driver = {
        .driver = {
                .name   = "max5821",
                .of_match_table = max5821_of_match,
-               .pm     = MAX5821_PM_OPS,
+               .pm     = &max5821_pm_ops,
        },
        .probe          = max5821_probe,
        .remove         = max5821_remove,
index 8b5aad4c32d90effd27cb6a19f3373d5c9060879..6d71fd905e29d69b0a5b1afa99c5451037333153 100644 (file)
@@ -45,7 +45,7 @@ struct mcp4725_data {
        struct regulator *vref_reg;
 };
 
-static int mcp4725_suspend(struct device *dev)
+static int __maybe_unused mcp4725_suspend(struct device *dev)
 {
        struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
                to_i2c_client(dev)));
@@ -58,7 +58,7 @@ static int mcp4725_suspend(struct device *dev)
        return i2c_master_send(data->client, outbuf, 2);
 }
 
-static int mcp4725_resume(struct device *dev)
+static int __maybe_unused mcp4725_resume(struct device *dev)
 {
        struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
                to_i2c_client(dev)));
@@ -71,13 +71,7 @@ static int mcp4725_resume(struct device *dev)
 
        return i2c_master_send(data->client, outbuf, 2);
 }
-
-#ifdef CONFIG_PM_SLEEP
 static SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend, mcp4725_resume);
-#define MCP4725_PM_OPS (&mcp4725_pm_ops)
-#else
-#define MCP4725_PM_OPS NULL
-#endif
 
 static ssize_t mcp4725_store_eeprom(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t len)
@@ -547,7 +541,7 @@ static struct i2c_driver mcp4725_driver = {
        .driver = {
                .name   = MCP4725_DRV_NAME,
                .of_match_table = of_match_ptr(mcp4725_of_match),
-               .pm     = MCP4725_PM_OPS,
+               .pm     = &mcp4725_pm_ops,
        },
        .probe          = mcp4725_probe,
        .remove         = mcp4725_remove,
index bf9aa3fc0534e6786c5f5fe605cfd43b9a383690..b5190d1dae8e33a15e148ff78471fb09dd4b90d1 100644 (file)
@@ -94,17 +94,22 @@ static int mcp4922_write_raw(struct iio_dev *indio_dev,
                long mask)
 {
        struct mcp4922_state *state = iio_priv(indio_dev);
+       int ret;
 
        if (val2 != 0)
                return -EINVAL;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               if (val > GENMASK(chan->scan_type.realbits-1, 0))
+               if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
                        return -EINVAL;
                val <<= chan->scan_type.shift;
-               state->value[chan->channel] = val;
-               return mcp4922_spi_write(state, chan->channel, val);
+
+               ret = mcp4922_spi_write(state, chan->channel, val);
+               if (!ret)
+                       state->value[chan->channel] = val;
+               return ret;
+
        default:
                return -EINVAL;
        }
index e39d1e901353bc06ef0d06fb6c38f1844990d20d..f6dcd8bce2b018a8e97d41099daac48faf0e783a 100644 (file)
@@ -421,6 +421,7 @@ MODULE_DEVICE_TABLE(i2c, dac5571_id);
 static struct i2c_driver dac5571_driver = {
        .driver = {
                   .name = "ti-dac5571",
+                  .of_match_table = of_match_ptr(dac5571_of_id),
        },
        .probe    = dac5571_probe,
        .remove   = dac5571_remove,
index f4a508107f0de9b70180d7d4bf3e7f59e46bb64a..f3f94fbdd20aba7aec96250b1c72b3b575399210 100644 (file)
@@ -1078,6 +1078,6 @@ static struct spi_driver ad9523_driver = {
 };
 module_spi_driver(ad9523_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD9523 CLOCKDIST/PLL");
 MODULE_LICENSE("GPL v2");
index 6d768431d90e926f33e3c524e7af014e2b7ce26d..f4748ff243f74a209fad810d5765ad7da271942f 100644 (file)
@@ -388,7 +388,7 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
        if (!pdata)
                return NULL;
 
-       strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
+       snprintf(&pdata->name[0], SPI_NAME_SIZE - 1, "%pOFn", np);
 
        tmp = 10000;
        of_property_read_u32(np, "adi,channel-spacing", &tmp);
index 15ccadc74891f73dca409acb0806cb4136646da9..3e29562ce374ffec9f213555f1360bed9b03d46a 100644 (file)
@@ -282,9 +282,11 @@ static int max30102_read_measurement(struct max30102_data *data,
        switch (measurements) {
        case 3:
                MAX30102_COPY_DATA(2);
-       case 2: /* fall-through */
+               /* fall through */
+       case 2:
                MAX30102_COPY_DATA(1);
-       case 1: /* fall-through */
+               /* fall through */
+       case 1:
                MAX30102_COPY_DATA(0);
                break;
        default:
index d80ef468508a19763ccbe0a70be5397158440c77..1e428c196a825c22f40318ca5d00cf776ff8359f 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/iio/iio.h>
 #include <linux/acpi.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include "inv_mpu_iio.h"
 
 /*
@@ -926,6 +927,39 @@ error_power_off:
        return result;
 }
 
+static int inv_mpu_core_enable_regulator(struct inv_mpu6050_state *st)
+{
+       int result;
+
+       result = regulator_enable(st->vddio_supply);
+       if (result) {
+               dev_err(regmap_get_device(st->map),
+                       "Failed to enable regulator: %d\n", result);
+       } else {
+               /* Give the device a little bit of time to start up. */
+               usleep_range(35000, 70000);
+       }
+
+       return result;
+}
+
+static int inv_mpu_core_disable_regulator(struct inv_mpu6050_state *st)
+{
+       int result;
+
+       result = regulator_disable(st->vddio_supply);
+       if (result)
+               dev_err(regmap_get_device(st->map),
+                       "Failed to disable regulator: %d\n", result);
+
+       return result;
+}
+
+static void inv_mpu_core_disable_regulator_action(void *_data)
+{
+       inv_mpu_core_disable_regulator(_data);
+}
+
 int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
                int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
 {
@@ -992,6 +1026,28 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
                return -EINVAL;
        }
 
+       st->vddio_supply = devm_regulator_get(dev, "vddio");
+       if (IS_ERR(st->vddio_supply)) {
+               if (PTR_ERR(st->vddio_supply) != -EPROBE_DEFER)
+                       dev_err(dev, "Failed to get vddio regulator %d\n",
+                               (int)PTR_ERR(st->vddio_supply));
+
+               return PTR_ERR(st->vddio_supply);
+       }
+
+       result = inv_mpu_core_enable_regulator(st);
+       if (result)
+               return result;
+
+       result = devm_add_action(dev, inv_mpu_core_disable_regulator_action,
+                                st);
+       if (result) {
+               inv_mpu_core_disable_regulator_action(st);
+               dev_err(dev, "Failed to setup regulator cleanup action %d\n",
+                       result);
+               return result;
+       }
+
        /* power is turned on inside check chip type*/
        result = inv_check_and_setup_chip(st);
        if (result)
@@ -1051,7 +1107,12 @@ static int inv_mpu_resume(struct device *dev)
        int result;
 
        mutex_lock(&st->lock);
+       result = inv_mpu_core_enable_regulator(st);
+       if (result)
+               goto out_unlock;
+
        result = inv_mpu6050_set_power_itg(st, true);
+out_unlock:
        mutex_unlock(&st->lock);
 
        return result;
@@ -1064,6 +1125,7 @@ static int inv_mpu_suspend(struct device *dev)
 
        mutex_lock(&st->lock);
        result = inv_mpu6050_set_power_itg(st, false);
+       inv_mpu_core_disable_regulator(st);
        mutex_unlock(&st->lock);
 
        return result;
index e69a59659dbcf9036c24abe96b8a4ef314a89143..6bcc11fc1b886c7d847525e5f3139bb0c38699b4 100644 (file)
@@ -129,6 +129,7 @@ struct inv_mpu6050_hw {
  *  @chip_period:      chip internal period estimation (~1kHz).
  *  @it_timestamp:     timestamp from previous interrupt.
  *  @data_timestamp:   timestamp for next data sample.
+ *  @vddio_supply      voltage regulator for the chip.
  */
 struct inv_mpu6050_state {
        struct mutex lock;
@@ -149,6 +150,7 @@ struct inv_mpu6050_state {
        s64 chip_period;
        s64 it_timestamp;
        s64 data_timestamp;
+       struct regulator *vddio_supply;
 };
 
 /*register and associated bit definition*/
index ccc817e17eb859cfab79419b1c48c06dc889882b..094fd006b63d36f24abb747418f3d71231117757 100644 (file)
@@ -9,7 +9,7 @@ config IIO_ST_LSM6DSX
        help
          Say yes here to build support for STMicroelectronics LSM6DSx imu
          sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
-         ism330dlc
+         ism330dlc, lsm6dso
 
          To compile this driver as a module, choose M here: the module
          will be called st_lsm6dsx.
index edcd838037cd80799e8253e3bfe953443036c49f..ef73519a0fb6fa4a309bd2d10da1822cd560baeb 100644 (file)
@@ -19,6 +19,7 @@
 #define ST_LSM6DSL_DEV_NAME    "lsm6dsl"
 #define ST_LSM6DSM_DEV_NAME    "lsm6dsm"
 #define ST_ISM330DLC_DEV_NAME  "ism330dlc"
+#define ST_LSM6DSO_DEV_NAME    "lsm6dso"
 
 enum st_lsm6dsx_hw_id {
        ST_LSM6DS3_ID,
@@ -26,14 +27,20 @@ enum st_lsm6dsx_hw_id {
        ST_LSM6DSL_ID,
        ST_LSM6DSM_ID,
        ST_ISM330DLC_ID,
+       ST_LSM6DSO_ID,
        ST_LSM6DSX_MAX_ID,
 };
 
-#define ST_LSM6DSX_BUFF_SIZE           400
+#define ST_LSM6DSX_BUFF_SIZE           512
 #define ST_LSM6DSX_CHAN_SIZE           2
 #define ST_LSM6DSX_SAMPLE_SIZE         6
+#define ST_LSM6DSX_TAG_SIZE            1
+#define ST_LSM6DSX_TAGGED_SAMPLE_SIZE  (ST_LSM6DSX_SAMPLE_SIZE + \
+                                        ST_LSM6DSX_TAG_SIZE)
 #define ST_LSM6DSX_MAX_WORD_LEN                ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \
                                         ST_LSM6DSX_SAMPLE_SIZE)
+#define ST_LSM6DSX_MAX_TAGGED_WORD_LEN ((32 / ST_LSM6DSX_TAGGED_SAMPLE_SIZE) \
+                                        * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)
 #define ST_LSM6DSX_SHIFT_VAL(val, mask)        (((val) << __ffs(mask)) & (mask))
 
 struct st_lsm6dsx_reg {
@@ -41,13 +48,17 @@ struct st_lsm6dsx_reg {
        u8 mask;
 };
 
+struct st_lsm6dsx_hw;
+
 /**
  * struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
+ * @read_fifo: Read FIFO callback.
  * @fifo_th: FIFO threshold register info (addr + mask).
  * @fifo_diff: FIFO diff status register info (addr + mask).
  * @th_wl: FIFO threshold word length.
  */
 struct st_lsm6dsx_fifo_ops {
+       int (*read_fifo)(struct st_lsm6dsx_hw *hw);
        struct {
                u8 addr;
                u16 mask;
@@ -79,6 +90,7 @@ struct st_lsm6dsx_hw_ts_settings {
  * @max_fifo_size: Sensor max fifo length in FIFO words.
  * @id: List of hw id supported by the driver configuration.
  * @decimator: List of decimator register info (addr + mask).
+ * @batch: List of FIFO batching register info (addr + mask).
  * @fifo_ops: Sensor hw FIFO parameters.
  * @ts_settings: Hw timer related settings.
  */
@@ -87,6 +99,7 @@ struct st_lsm6dsx_settings {
        u16 max_fifo_size;
        enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
+       struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
        struct st_lsm6dsx_fifo_ops fifo_ops;
        struct st_lsm6dsx_hw_ts_settings ts_settings;
 };
@@ -175,5 +188,8 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
 int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
 int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
                             enum st_lsm6dsx_fifo_mode fifo_mode);
+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);
 
 #endif /* ST_LSM6DSX_H */
index 7589f2ad1dae7de9fe04b5448b233fdda786db70..61f2c5777295d6a873143acdc1059cf10547ac2a 100644 (file)
  * buffer contains the data of all the enabled FIFO data sets
  * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
  * value of the decimation factor and ODR set for each FIFO data set.
+ *
+ * LSM6DSO: The FIFO buffer can be configured to store data from gyroscope and
+ * accelerometer. Each sample is queued with a tag (1B) indicating data source
+ * (gyroscope, accelerometer, hw timer).
+ *
  * FIFO supported modes:
  *  - BYPASS: FIFO disabled
  *  - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
@@ -46,6 +51,7 @@
 #define ST_LSM6DSX_FIFO_ODR_MASK               GENMASK(6, 3)
 #define ST_LSM6DSX_FIFO_EMPTY_MASK             BIT(12)
 #define ST_LSM6DSX_REG_FIFO_OUTL_ADDR          0x3e
+#define ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR       0x78
 #define ST_LSM6DSX_REG_TS_RESET_ADDR           0x42
 
 #define ST_LSM6DSX_MAX_FIFO_ODR_VAL            0x08
@@ -58,6 +64,12 @@ struct st_lsm6dsx_decimator_entry {
        u8 val;
 };
 
+enum st_lsm6dsx_fifo_tag {
+       ST_LSM6DSX_GYRO_TAG = 0x01,
+       ST_LSM6DSX_ACC_TAG = 0x02,
+       ST_LSM6DSX_TS_TAG = 0x04,
+};
+
 static const
 struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
        {  0, 0x0 },
@@ -177,12 +189,34 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
                                   bool enable)
 {
        struct st_lsm6dsx_hw *hw = sensor->hw;
+       const struct st_lsm6dsx_reg *batch_reg;
        u8 data;
 
-       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));
+       batch_reg = &hw->settings->batch[sensor->id];
+       if (batch_reg->addr) {
+               int val;
+
+               if (enable) {
+                       int err;
+
+                       err = st_lsm6dsx_check_odr(sensor, sensor->odr,
+                                                  &data);
+                       if (err < 0)
+                               return err;
+               } else {
+                       data = 0;
+               }
+               val = ST_LSM6DSX_SHIFT_VAL(data, batch_reg->mask);
+               return regmap_update_bits(hw->regmap, 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));
+       }
 }
 
 int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
@@ -251,21 +285,21 @@ static int st_lsm6dsx_reset_hw_ts(struct st_lsm6dsx_hw *hw)
 }
 
 /*
- * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN in order to avoid
- * a kmalloc for each bus access
+ * Set max bulk read to ST_LSM6DSX_MAX_WORD_LEN/ST_LSM6DSX_MAX_TAGGED_WORD_LEN
+ * in order to avoid a kmalloc for each bus access
  */
-static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
-                                       unsigned int data_len)
+static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 addr,
+                                       u8 *data, unsigned int data_len,
+                                       unsigned int max_word_len)
 {
        unsigned int word_len, read_len = 0;
        int err;
 
        while (read_len < data_len) {
                word_len = min_t(unsigned int, data_len - read_len,
-                                ST_LSM6DSX_MAX_WORD_LEN);
-               err = regmap_bulk_read(hw->regmap,
-                                      ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
-                                      data + read_len, word_len);
+                                max_word_len);
+               err = regmap_bulk_read(hw->regmap, addr, data + read_len,
+                                      word_len);
                if (err < 0)
                        return err;
                read_len += word_len;
@@ -283,7 +317,7 @@ static inline int st_lsm6dsx_read_block(struct st_lsm6dsx_hw *hw, u8 *data,
  *
  * Return: Number of bytes read from the FIFO
  */
-static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
+int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
 {
        u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
        u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
@@ -315,7 +349,9 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
        gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
 
        for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
-               err = st_lsm6dsx_read_block(hw, hw->buff, pattern_len);
+               err = st_lsm6dsx_read_block(hw, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
+                                           hw->buff, pattern_len,
+                                           ST_LSM6DSX_MAX_WORD_LEN);
                if (err < 0) {
                        dev_err(hw->dev,
                                "failed to read pattern from fifo (err=%d)\n",
@@ -401,13 +437,111 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
        return read_len;
 }
 
+/**
+ * st_lsm6dsx_read_tagged_fifo() - LSM6DSO read FIFO routine
+ * @hw: Pointer to instance of struct st_lsm6dsx_hw.
+ *
+ * Read samples from the hw FIFO and push them to IIO buffers.
+ *
+ * Return: Number of bytes read from the FIFO
+ */
+int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw)
+{
+       u16 pattern_len = hw->sip * ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
+       u16 fifo_len, fifo_diff_mask;
+       struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
+       u8 iio_buff[ST_LSM6DSX_IIO_BUFF_SIZE], tag;
+       bool reset_ts = false;
+       int i, err, read_len;
+       __le16 fifo_status;
+       s64 ts = 0;
+
+       err = regmap_bulk_read(hw->regmap,
+                              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);
+               return err;
+       }
+
+       fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
+       fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
+                  ST_LSM6DSX_TAGGED_SAMPLE_SIZE;
+       if (!fifo_len)
+               return 0;
+
+       acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+       gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
+
+       for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
+               err = st_lsm6dsx_read_block(hw,
+                                           ST_LSM6DSX_REG_FIFO_OUT_TAG_ADDR,
+                                           hw->buff, pattern_len,
+                                           ST_LSM6DSX_MAX_TAGGED_WORD_LEN);
+               if (err < 0) {
+                       dev_err(hw->dev,
+                               "failed to read pattern from fifo (err=%d)\n",
+                               err);
+                       return err;
+               }
+
+               for (i = 0; i < pattern_len;
+                    i += ST_LSM6DSX_TAGGED_SAMPLE_SIZE) {
+                       memcpy(iio_buff, &hw->buff[i + ST_LSM6DSX_TAG_SIZE],
+                              ST_LSM6DSX_SAMPLE_SIZE);
+
+                       tag = hw->buff[i] >> 3;
+                       switch (tag) {
+                       case ST_LSM6DSX_TS_TAG:
+                               /*
+                                * hw timestamp is 4B long and it is stored
+                                * in FIFO according to this schema:
+                                * B0 = ts[7:0], B1 = ts[15:8], B2 = ts[23:16],
+                                * B3 = ts[31:24]
+                                */
+                               ts = le32_to_cpu(*((__le32 *)iio_buff));
+                               /*
+                                * check if hw timestamp engine is going to
+                                * reset (the sensor generates an interrupt
+                                * to signal the hw timestamp will reset in
+                                * 1.638s)
+                                */
+                               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;
+                       }
+               }
+       }
+
+       if (unlikely(reset_ts)) {
+               err = st_lsm6dsx_reset_hw_ts(hw);
+               if (err < 0)
+                       return err;
+       }
+       return read_len;
+}
+
 int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
 {
        int err;
 
        mutex_lock(&hw->fifo_lock);
 
-       st_lsm6dsx_read_fifo(hw);
+       hw->settings->fifo_ops.read_fifo(hw);
        err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
 
        mutex_unlock(&hw->fifo_lock);
@@ -479,7 +613,7 @@ static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
        int count;
 
        mutex_lock(&hw->fifo_lock);
-       count = st_lsm6dsx_read_fifo(hw);
+       count = hw->settings->fifo_ops.read_fifo(hw);
        mutex_unlock(&hw->fifo_lock);
 
        return !count ? IRQ_NONE : IRQ_HANDLED;
index aebbe0ddd8d8c3ddf2900cf9487d1736ec123ae2..2ad3c610e4b63777cfc7e83f278d88ca231e0e2f 100644 (file)
  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
  *   - FIFO size: 4KB
  *
+ * - LSM6DSO
+ *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
+ *   - FIFO size: 3KB
+ *
  * Copyright 2016 STMicroelectronics Inc.
  *
  * Lorenzo Bianconi <lorenzo.bianconi@st.com>
@@ -171,6 +177,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                },
                .fifo_ops = {
+                       .read_fifo = st_lsm6dsx_read_fifo,
                        .fifo_th = {
                                .addr = 0x06,
                                .mask = GENMASK(11, 0),
@@ -217,6 +224,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                },
                .fifo_ops = {
+                       .read_fifo = st_lsm6dsx_read_fifo,
                        .fifo_th = {
                                .addr = 0x06,
                                .mask = GENMASK(11, 0),
@@ -265,6 +273,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                },
                .fifo_ops = {
+                       .read_fifo = st_lsm6dsx_read_fifo,
                        .fifo_th = {
                                .addr = 0x06,
                                .mask = GENMASK(10, 0),
@@ -294,6 +303,45 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
                        },
                },
        },
+       {
+               .wai = 0x6c,
+               .max_fifo_size = 512,
+               .id = {
+                       [0] = ST_LSM6DSO_ID,
+               },
+               .batch = {
+                       [ST_LSM6DSX_ID_ACC] = {
+                               .addr = 0x09,
+                               .mask = GENMASK(3, 0),
+                       },
+                       [ST_LSM6DSX_ID_GYRO] = {
+                               .addr = 0x09,
+                               .mask = GENMASK(7, 4),
+                       },
+               },
+               .fifo_ops = {
+                       .read_fifo = st_lsm6dsx_read_tagged_fifo,
+                       .fifo_th = {
+                               .addr = 0x07,
+                               .mask = GENMASK(8, 0),
+                       },
+                       .fifo_diff = {
+                               .addr = 0x3a,
+                               .mask = GENMASK(8, 0),
+                       },
+                       .th_wl = 1,
+               },
+               .ts_settings = {
+                       .timer_en = {
+                               .addr = 0x19,
+                               .mask = BIT(5),
+                       },
+                       .decimator = {
+                               .addr = 0x0a,
+                               .mask = GENMASK(7, 6),
+                       },
+               },
+       },
 };
 
 #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx)             \
@@ -395,8 +443,7 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
        return 0;
 }
 
-static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr,
-                               u8 *val)
+int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
 {
        int i;
 
index 377c4e9997daf891d3e6d74cbd9f3296f0a5d71d..448b7bc1e57818c744b4f791fa0137a04184bed7 100644 (file)
@@ -61,6 +61,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
                .compatible = "st,ism330dlc",
                .data = (void *)ST_ISM330DLC_ID,
        },
+       {
+               .compatible = "st,lsm6dso",
+               .data = (void *)ST_LSM6DSO_ID,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -71,6 +75,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
        { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
        { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
        { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
+       { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
index fec5c6ce7eb7a247fba044fb297ba7a29210f0ec..b1df8a6973e6f4d019abae7b669347220e97d4e1 100644 (file)
@@ -61,6 +61,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
                .compatible = "st,ism330dlc",
                .data = (void *)ST_ISM330DLC_ID,
        },
+       {
+               .compatible = "st,lsm6dso",
+               .data = (void *)ST_LSM6DSO_ID,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -71,6 +75,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
        { ST_LSM6DSL_DEV_NAME, ST_LSM6DSL_ID },
        { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
        { ST_ISM330DLC_DEV_NAME, ST_ISM330DLC_ID },
+       { ST_LSM6DSO_DEV_NAME, ST_LSM6DSO_ID },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
index a814828e69f5c3c47de3c3a95a8131d042dbbec5..c3a481452b67661c29d33430d062749713f993f4 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * ROHM BH1710/BH1715/BH1721/BH1750/BH1751 ambient light sensor driver
  *
  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
  *
- * 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.
- *
  * Data sheets:
  *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1710fvc-e.pdf
  *  http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1715fvc-e.pdf
@@ -281,8 +278,7 @@ static int bh1750_remove(struct i2c_client *client)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int bh1750_suspend(struct device *dev)
+static int __maybe_unused bh1750_suspend(struct device *dev)
 {
        int ret;
        struct bh1750_data *data =
@@ -300,10 +296,6 @@ static int bh1750_suspend(struct device *dev)
 }
 
 static SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
-#define BH1750_PM_OPS (&bh1750_pm_ops)
-#else
-#define BH1750_PM_OPS NULL
-#endif
 
 static const struct i2c_device_id bh1750_id[] = {
        { "bh1710", BH1710 },
@@ -318,7 +310,7 @@ MODULE_DEVICE_TABLE(i2c, bh1750_id);
 static struct i2c_driver bh1750_driver = {
        .driver = {
                .name = "bh1750",
-               .pm = BH1750_PM_OPS,
+               .pm = &bh1750_pm_ops,
        },
        .probe = bh1750_probe,
        .remove = bh1750_remove,
index bcdb0eb9e5371f05a35ca91eb1daaa7337ac12f1..b9b0bd341be8f4deee12f6a744119f93eec69ae7 100644 (file)
@@ -99,7 +99,6 @@ static const int max44000_alspga_shift[] = {0, 2, 4, 7};
  * Handling this internally is also required for buffer support because the
  * channel's scan_type can't be modified dynamically.
  */
-static const int max44000_alstim_shift[] = {0, 2, 4, 6};
 #define MAX44000_ALSTIM_SHIFT(alstim) (2 * (alstim))
 
 /* Available integration times with pretty manual alignment: */
index df5b2a0da96c4a9c311ddd6da57f990f6d1f821f..83cece921843c64594f67d60e41d79cea9b4ac89 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/platform_data/tsl2772.h>
+#include <linux/regulator/consumer.h>
 
 /* Cal defs */
 #define PROX_STAT_CAL                  0
 #define TSL2772_ALS_GAIN_TRIM_MIN      250
 #define TSL2772_ALS_GAIN_TRIM_MAX      4000
 
+#define TSL2772_MAX_PROX_LEDS          2
+
+#define TSL2772_BOOT_MIN_SLEEP_TIME    10000
+#define TSL2772_BOOT_MAX_SLEEP_TIME    28000
+
 /* Device family members */
 enum {
        tsl2571,
@@ -118,7 +124,8 @@ enum {
        tsl2672,
        tmd2672,
        tsl2772,
-       tmd2772
+       tmd2772,
+       apds9930,
 };
 
 enum {
@@ -141,11 +148,21 @@ struct tsl2772_chip_info {
        const struct iio_info *info;
 };
 
+static const int tsl2772_led_currents[][2] = {
+       { 100000, TSL2772_100_mA },
+       {  50000, TSL2772_50_mA },
+       {  25000, TSL2772_25_mA },
+       {  13000, TSL2772_13_mA },
+       {      0, 0 }
+};
+
 struct tsl2772_chip {
        kernel_ulong_t id;
        struct mutex prox_mutex;
        struct mutex als_mutex;
        struct i2c_client *client;
+       struct regulator *vdd_supply;
+       struct regulator *vddio_supply;
        u16 prox_data;
        struct tsl2772_als_info als_cur_info;
        struct tsl2772_settings settings;
@@ -197,6 +214,12 @@ static const struct tsl2772_lux tmd2x72_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
        {     0,      0 },
 };
 
+static const struct tsl2772_lux apds9930_lux_table[TSL2772_DEF_LUX_TABLE_SZ] = {
+       { 52000,  96824 },
+       { 38792,  67132 },
+       {     0,      0 },
+};
+
 static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
        [tsl2571] = tsl2x71_lux_table,
        [tsl2671] = tsl2x71_lux_table,
@@ -208,6 +231,7 @@ static const struct tsl2772_lux *tsl2772_default_lux_table_group[] = {
        [tmd2672] = tmd2x72_lux_table,
        [tsl2772] = tsl2x72_lux_table,
        [tmd2772] = tmd2x72_lux_table,
+       [apds9930] = apds9930_lux_table,
 };
 
 static const struct tsl2772_settings tsl2772_default_settings = {
@@ -258,6 +282,7 @@ static const int tsl2772_int_time_avail[][6] = {
        [tmd2672] = { 0, 2730, 0, 2730, 0, 699000 },
        [tsl2772] = { 0, 2730, 0, 2730, 0, 699000 },
        [tmd2772] = { 0, 2730, 0, 2730, 0, 699000 },
+       [apds9930] = { 0, 2730, 0, 2730, 0, 699000 },
 };
 
 static int tsl2772_int_calibscale_avail[] = { 1, 8, 16, 120 };
@@ -283,7 +308,8 @@ static const u8 device_channel_config[] = {
        [tsl2672] = PRX2,
        [tmd2672] = PRX2,
        [tsl2772] = ALSPRX2,
-       [tmd2772] = ALSPRX2
+       [tmd2772] = ALSPRX2,
+       [apds9930] = ALSPRX2,
 };
 
 static int tsl2772_read_status(struct tsl2772_chip *chip)
@@ -497,6 +523,7 @@ static int tsl2772_get_prox(struct iio_dev *indio_dev)
        case tmd2672:
        case tsl2772:
        case tmd2772:
+       case apds9930:
                if (!(ret & TSL2772_STA_PRX_VALID)) {
                        ret = -EINVAL;
                        goto prox_poll_err;
@@ -515,6 +542,75 @@ prox_poll_err:
        return ret;
 }
 
+static int tsl2772_read_prox_led_current(struct tsl2772_chip *chip)
+{
+       struct device_node *of_node = chip->client->dev.of_node;
+       int ret, tmp, i;
+
+       ret = of_property_read_u32(of_node, "led-max-microamp", &tmp);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; tsl2772_led_currents[i][0] != 0; i++) {
+               if (tmp == tsl2772_led_currents[i][0]) {
+                       chip->settings.prox_power = tsl2772_led_currents[i][1];
+                       return 0;
+               }
+       }
+
+       dev_err(&chip->client->dev, "Invalid value %d for led-max-microamp\n",
+               tmp);
+
+       return -EINVAL;
+
+}
+
+static int tsl2772_read_prox_diodes(struct tsl2772_chip *chip)
+{
+       struct device_node *of_node = chip->client->dev.of_node;
+       int i, ret, num_leds, prox_diode_mask;
+       u32 leds[TSL2772_MAX_PROX_LEDS];
+
+       ret = of_property_count_u32_elems(of_node, "amstaos,proximity-diodes");
+       if (ret < 0)
+               return ret;
+
+       num_leds = ret;
+       if (num_leds > TSL2772_MAX_PROX_LEDS)
+               num_leds = TSL2772_MAX_PROX_LEDS;
+
+       ret = of_property_read_u32_array(of_node, "amstaos,proximity-diodes",
+                                        leds, num_leds);
+       if (ret < 0) {
+               dev_err(&chip->client->dev,
+                       "Invalid value for amstaos,proximity-diodes: %d.\n",
+                       ret);
+               return ret;
+       }
+
+       prox_diode_mask = 0;
+       for (i = 0; i < num_leds; i++) {
+               if (leds[i] == 0)
+                       prox_diode_mask |= TSL2772_DIODE0;
+               else if (leds[i] == 1)
+                       prox_diode_mask |= TSL2772_DIODE1;
+               else {
+                       dev_err(&chip->client->dev,
+                               "Invalid value %d in amstaos,proximity-diodes.\n",
+                               leds[i]);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void tsl2772_parse_dt(struct tsl2772_chip *chip)
+{
+       tsl2772_read_prox_led_current(chip);
+       tsl2772_read_prox_diodes(chip);
+}
+
 /**
  * tsl2772_defaults() - Populates the device nominal operating parameters
  *                      with those provided by a 'platform' data struct or
@@ -541,6 +637,8 @@ static void tsl2772_defaults(struct tsl2772_chip *chip)
                memcpy(chip->tsl2772_device_lux,
                       tsl2772_default_lux_table_group[chip->id],
                       TSL2772_DEFAULT_TABLE_BYTES);
+
+       tsl2772_parse_dt(chip);
 }
 
 /**
@@ -595,6 +693,52 @@ static int tsl2772_als_calibrate(struct iio_dev *indio_dev)
        return ret;
 }
 
+static void tsl2772_disable_regulators_action(void *_data)
+{
+       struct tsl2772_chip *chip = _data;
+
+       regulator_disable(chip->vdd_supply);
+       regulator_disable(chip->vddio_supply);
+}
+
+static int tsl2772_enable_regulator(struct tsl2772_chip *chip,
+                                   struct regulator *regulator)
+{
+       int ret;
+
+       ret = regulator_enable(regulator);
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "Failed to enable regulator: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct regulator *tsl2772_get_regulator(struct tsl2772_chip *chip,
+                                              char *name)
+{
+       struct regulator *regulator;
+       int ret;
+
+       regulator = devm_regulator_get(&chip->client->dev, name);
+       if (IS_ERR(regulator)) {
+               if (PTR_ERR(regulator) != -EPROBE_DEFER)
+                       dev_err(&chip->client->dev,
+                               "Failed to get %s regulator %d\n",
+                               name, (int)PTR_ERR(regulator));
+
+               return regulator;
+       }
+
+       ret = tsl2772_enable_regulator(chip, regulator);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       return regulator;
+}
+
 static int tsl2772_chip_on(struct iio_dev *indio_dev)
 {
        struct tsl2772_chip *chip = iio_priv(indio_dev);
@@ -1260,6 +1404,7 @@ static int tsl2772_device_id_verif(int id, int target)
        case tmd2672:
        case tsl2772:
        case tmd2772:
+       case apds9930:
                return (id & 0xf0) == SWORDFISH_ID;
        }
 
@@ -1652,6 +1797,27 @@ static int tsl2772_probe(struct i2c_client *clientp,
        chip->client = clientp;
        i2c_set_clientdata(clientp, indio_dev);
 
+       chip->vddio_supply = tsl2772_get_regulator(chip, "vddio");
+       if (IS_ERR(chip->vddio_supply))
+               return PTR_ERR(chip->vddio_supply);
+
+       chip->vdd_supply = tsl2772_get_regulator(chip, "vdd");
+       if (IS_ERR(chip->vdd_supply)) {
+               regulator_disable(chip->vddio_supply);
+               return PTR_ERR(chip->vdd_supply);
+       }
+
+       ret = devm_add_action(&clientp->dev, tsl2772_disable_regulators_action,
+                             chip);
+       if (ret < 0) {
+               tsl2772_disable_regulators_action(chip);
+               dev_err(&clientp->dev, "Failed to setup regulator cleanup action %d\n",
+                       ret);
+               return ret;
+       }
+
+       usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
+
        ret = i2c_smbus_read_byte_data(chip->client,
                                       TSL2772_CMD_REG | TSL2772_CHIPID);
        if (ret < 0)
@@ -1725,13 +1891,33 @@ static int tsl2772_probe(struct i2c_client *clientp,
 static int tsl2772_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct tsl2772_chip *chip = iio_priv(indio_dev);
+       int ret;
+
+       ret = tsl2772_chip_off(indio_dev);
+       regulator_disable(chip->vdd_supply);
+       regulator_disable(chip->vddio_supply);
 
-       return tsl2772_chip_off(indio_dev);
+       return ret;
 }
 
 static int tsl2772_resume(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct tsl2772_chip *chip = iio_priv(indio_dev);
+       int ret;
+
+       ret = tsl2772_enable_regulator(chip, chip->vddio_supply);
+       if (ret < 0)
+               return ret;
+
+       ret = tsl2772_enable_regulator(chip, chip->vdd_supply);
+       if (ret < 0) {
+               regulator_disable(chip->vddio_supply);
+               return ret;
+       }
+
+       usleep_range(TSL2772_BOOT_MIN_SLEEP_TIME, TSL2772_BOOT_MAX_SLEEP_TIME);
 
        return tsl2772_chip_on(indio_dev);
 }
@@ -1758,6 +1944,7 @@ static const struct i2c_device_id tsl2772_idtable[] = {
        { "tmd2672", tmd2672 },
        { "tsl2772", tsl2772 },
        { "tmd2772", tmd2772 },
+       { "apds9930", apds9930},
        {}
 };
 
@@ -1774,6 +1961,7 @@ static const struct of_device_id tsl2772_of_match[] = {
        { .compatible = "amstaos,tmd2672" },
        { .compatible = "amstaos,tsl2772" },
        { .compatible = "amstaos,tmd2772" },
+       { .compatible = "avago,apds9930" },
        {}
 };
 MODULE_DEVICE_TABLE(of, tsl2772_of_match);
index e1f44cecdef4c50b984878229f7afb3389c9a7ca..0422ef57914cd0617a1bee41196da466deaff87b 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * IIO multiplexer driver
  *
  * Copyright (C) 2017 Axentia Technologies AB
  *
  * Author: Peter Rosin <peda@axentia.se>
- *
- * 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/err.h>
index ffe2761333a2da1f71437fe255691f8fda12eb94..6d2f13fa56623cffbcc495ca7b5802b3b1ec40f6 100644 (file)
@@ -137,7 +137,6 @@ static int max5481_probe(struct spi_device *spi)
        struct iio_dev *indio_dev;
        struct max5481_data *data;
        const struct spi_device_id *id = spi_get_device_id(spi);
-       const struct of_device_id *match;
        int ret;
 
        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
@@ -149,10 +148,8 @@ static int max5481_probe(struct spi_device *spi)
 
        data->spi = spi;
 
-       match = of_match_device(of_match_ptr(max5481_match), &spi->dev);
-       if (match)
-               data->cfg = of_device_get_match_data(&spi->dev);
-       else
+       data->cfg = of_device_get_match_data(&spi->dev);
+       if (!data->cfg)
                data->cfg = &max5481_cfg[id->driver_data];
 
        indio_dev->name = id->name;
index 320a7c9297772992371d065faaddd41de9de1bbe..62151b2a2b12db798155344995b7e9657fc25c9f 100644 (file)
@@ -147,7 +147,6 @@ static int mcp4018_probe(struct i2c_client *client)
        struct device *dev = &client->dev;
        struct mcp4018_data *data;
        struct iio_dev *indio_dev;
-       const struct of_device_id *match;
 
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_BYTE)) {
@@ -162,10 +161,8 @@ static int mcp4018_probe(struct i2c_client *client)
        i2c_set_clientdata(client, indio_dev);
        data->client = client;
 
-       match = of_match_device(of_match_ptr(mcp4018_of_match), dev);
-       if (match)
-               data->cfg = of_device_get_match_data(dev);
-       else
+       data->cfg = of_device_get_match_data(dev);
+       if (!data->cfg)
                data->cfg = &mcp4018_cfg[i2c_match_id(mcp4018_id, client)->driver_data];
 
        indio_dev->dev.parent = dev;
@@ -190,4 +187,4 @@ module_i2c_driver(mcp4018_driver);
 
 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
 MODULE_DESCRIPTION("MCP4018 digital potentiometer");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index df894af6cccbd59b479390ae2a7b65c51f69eddf..d71a22d71a308110d4ad178a0571ed0bf1b93331 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Industrial I/O driver for Microchip digital potentiometers
  * Copyright (c) 2015  Axentia Technologies AB
  * mcp4652     2       257             5, 10, 50, 100          01011xx
  * mcp4661     2       257             5, 10, 50, 100          0101xxx
  * mcp4662     2       257             5, 10, 50, 100          01011xx
- *
- * 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/module.h>
@@ -360,7 +357,6 @@ static int mcp4531_probe(struct i2c_client *client)
        struct device *dev = &client->dev;
        struct mcp4531_data *data;
        struct iio_dev *indio_dev;
-       const struct of_device_id *match;
 
        if (!i2c_check_functionality(client->adapter,
                                     I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -375,10 +371,8 @@ static int mcp4531_probe(struct i2c_client *client)
        i2c_set_clientdata(client, indio_dev);
        data->client = client;
 
-       match = of_match_device(of_match_ptr(mcp4531_of_match), dev);
-       if (match)
-               data->cfg = of_device_get_match_data(dev);
-       else
+       data->cfg = of_device_get_match_data(dev);
+       if (!data->cfg)
                data->cfg = &mcp4531_cfg[i2c_match_id(mcp4531_id, client)->driver_data];
 
        indio_dev->dev.parent = dev;
@@ -403,4 +397,4 @@ module_i2c_driver(mcp4531_driver);
 
 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
 MODULE_DESCRIPTION("MCP4531 digital potentiometer");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index ead9e9f8589487a60fac2dc90a602f9e8a0a410f..bc06271fa38bc95f8b1f14e2fdb27041e24c6560 100644 (file)
@@ -1,12 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * MS5611 pressure and temperature sensor driver
  *
  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
  *
- * 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 _MS5611_H
index f950cfde5db99ce4e8a7e16367c8fbeadb7b481c..2f598ad91621fd70c715d140da665dad977365d9 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * MS5611 pressure and temperature sensor driver
  *
  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
  *
- * 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.
- *
  * Data sheet:
  *  http://www.meas-spec.com/downloads/MS5611-01BA03.pdf
  *  http://www.meas-spec.com/downloads/MS5607-02BA03.pdf
index 55fb5fc0b6eac1d9adbf54e2e45382048cb135f5..8089c59adce5b09b1b05a6242b694c8069961a89 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * MS5611 pressure and temperature sensor driver (I2C bus)
  *
  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
  *
- * 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.
- *
  * 7-bit I2C slave addresses:
  *
  * 0x77 (CSB pin low)
@@ -117,9 +114,7 @@ static int ms5611_i2c_remove(struct i2c_client *client)
 #if defined(CONFIG_OF)
 static const struct of_device_id ms5611_i2c_matches[] = {
        { .compatible = "meas,ms5611" },
-       { .compatible = "ms5611" },
        { .compatible = "meas,ms5607" },
-       { .compatible = "ms5607" },
        { }
 };
 MODULE_DEVICE_TABLE(of, ms5611_i2c_matches);
index 932e05001e1a91fa1a7a211f75491005f197bc93..b463eaa799ab4df73166a473c195f2cd86edb11a 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * MS5611 pressure and temperature sensor driver (SPI bus)
  *
  * Copyright (c) Tomasz Duszynski <tduszyns@gmail.com>
  *
- * 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>
@@ -119,9 +116,7 @@ static int ms5611_spi_remove(struct spi_device *spi)
 #if defined(CONFIG_OF)
 static const struct of_device_id ms5611_spi_matches[] = {
        { .compatible = "meas,ms5611" },
-       { .compatible = "ms5611" },
        { .compatible = "meas,ms5607" },
-       { .compatible = "ms5607" },
        { }
 };
 MODULE_DEVICE_TABLE(of, ms5611_spi_matches);
index e5e94540f404dd2c0d72efc90abbfd85aa0c5a72..5ae549075b27c50d512cbf5ef75b9630c87ef9c3 100644 (file)
@@ -232,7 +232,6 @@ static u32 isl29501_register_write(struct isl29501_private *isl29501,
                                   u32 value)
 {
        const struct isl29501_register_desc *reg = &isl29501_registers[name];
-       u8 msb, lsb;
        int ret;
 
        if (!reg->msb && value > U8_MAX)
@@ -241,22 +240,15 @@ static u32 isl29501_register_write(struct isl29501_private *isl29501,
        if (value > U16_MAX)
                return -ERANGE;
 
-       if (!reg->msb) {
-               lsb = value & 0xFF;
-       } else {
-               msb = (value >> 8) & 0xFF;
-               lsb = value & 0xFF;
-       }
-
        mutex_lock(&isl29501->lock);
        if (reg->msb) {
                ret = i2c_smbus_write_byte_data(isl29501->client,
-                                               reg->msb, msb);
+                                               reg->msb, value >> 8);
                if (ret < 0)
                        goto err;
        }
 
-       ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, lsb);
+       ret = i2c_smbus_write_byte_data(isl29501->client, reg->lsb, value);
 
 err:
        mutex_unlock(&isl29501->lock);
index 3f0dc9a1a51406c5622a06cfc2b9cd01a96e0c85..45c4897295d6dfc319384622974acd8f3de6dfda 100644 (file)
@@ -222,7 +222,7 @@ static void __exit iio_sysfs_trig_exit(void)
 }
 module_exit(iio_sysfs_trig_exit);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:iio-trig-sysfs");
index df0499fc4802fb4cb7ac8a17950dcac4266e1f1f..acdbc07fd2592c03084a0c6fb6e89aee073f58fd 100644 (file)
@@ -761,6 +761,6 @@ static struct spi_driver ad7192_driver = {
 };
 module_spi_driver(ad7192_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7190, AD7192, AD7193, AD7195 ADC");
 MODULE_LICENSE("GPL v2");
index b736275c10f53532b0d27d445711dec1bda6de67..58420dcb406d9fb85cf54032e8baf14da5baf754 100644 (file)
@@ -987,6 +987,6 @@ static struct spi_driver ad7280_driver = {
 };
 module_spi_driver(ad7280_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7280A");
 MODULE_LICENSE("GPL v2");
index 25b9fcd5e3a4bcedd8b4a5288cf6ff2e3e6605eb..c5fe3003075bc27dacb79c50e4e1c1fc65c73183 100644 (file)
@@ -534,6 +534,6 @@ EXPORT_SYMBOL_GPL(ad7606_pm_ops);
 
 #endif
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
 MODULE_LICENSE("GPL v2");
index a34c2a1d537326d4a5054a2b85a1414eea15c2f1..956e38774767efc5e387e8c138c3c564e556909d 100644 (file)
@@ -105,6 +105,6 @@ static struct platform_driver ad7606_driver = {
 
 module_platform_driver(ad7606_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
 MODULE_LICENSE("GPL v2");
index c9b1f26685f49fb0a2bf24e6de9fb4630d3dc659..ffd9d0626ec27f6a12b8ca79623fd3e71b6e66cc 100644 (file)
@@ -73,6 +73,6 @@ static struct spi_driver ad7606_driver = {
 };
 module_spi_driver(ad7606_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7606 ADC");
 MODULE_LICENSE("GPL v2");
index 16d72072c076cbf08ec40daeccb81aa303960b81..b67412db0318a5a312a4993b31209568156f7f83 100644 (file)
@@ -260,6 +260,6 @@ static struct spi_driver ad7780_driver = {
 };
 module_spi_driver(ad7780_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs");
 MODULE_LICENSE("GPL v2");
index f53612a6461d653ce4858a03acbe8554f555bbd1..0eb28fea876ea024fa535fa5aef955c6275687e6 100644 (file)
@@ -758,6 +758,6 @@ static struct i2c_driver ad7746_driver = {
 };
 module_i2c_driver(ad7746_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD7746/5/7 capacitive sensor driver");
 MODULE_LICENSE("GPL v2");
index c73eff1f8d73d0bd854c74920d38b121163c44e5..a3ce504277244ea1656ff38cc3792c511fc98ded 100644 (file)
@@ -454,6 +454,6 @@ static struct spi_driver ad9832_driver = {
 };
 module_spi_driver(ad9832_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS");
 MODULE_LICENSE("GPL v2");
index 4c6d4043903e6c1f51a4e95b704b5ee033aef787..1e977014fe5f8ec8090a6daa37b378265f9bb42d 100644 (file)
@@ -526,6 +526,6 @@ static struct spi_driver ad9834_driver = {
 };
 module_spi_driver(ad9834_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS");
 MODULE_LICENSE("GPL v2");
index 14df89510396c29b868035388504d69c33b0426f..a2370dd1e1a8fd51f849f4f96a37a94070b48eb1 100644 (file)
@@ -797,6 +797,6 @@ static struct i2c_driver ad5933_driver = {
 };
 module_i2c_driver(ad5933_driver);
 
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 MODULE_DESCRIPTION("Analog Devices AD5933 Impedance Conv. Network Analyzer");
 MODULE_LICENSE("GPL v2");
index 42121fa238fafbf96919b3b93678f949d9e69d22..61d556db154276abef5f103629d15369ed60a3d2 100644 (file)
@@ -1,14 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
- * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * 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.
+ * Copyright (c) 2012-2014,2018 The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DT_BINDINGS_QCOM_SPMI_VADC_H
 #define VADC_LR_MUX10_PU1_PU2_AMUX_USB_ID      0xf9
 #define VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM      0xfc
 
+/* ADC channels for SPMI PMIC5 */
+
+#define ADC5_REF_GND                           0x00
+#define ADC5_1P25VREF                          0x01
+#define ADC5_VREF_VADC                         0x02
+#define ADC5_VREF_VADC5_DIV_3                  0x82
+#define ADC5_VPH_PWR                           0x83
+#define ADC5_VBAT_SNS                          0x84
+#define ADC5_VCOIN                             0x85
+#define ADC5_DIE_TEMP                          0x06
+#define ADC5_USB_IN_I                          0x07
+#define ADC5_USB_IN_V_16                       0x08
+#define ADC5_CHG_TEMP                          0x09
+#define ADC5_BAT_THERM                         0x0a
+#define ADC5_BAT_ID                            0x0b
+#define ADC5_XO_THERM                          0x0c
+#define ADC5_AMUX_THM1                         0x0d
+#define ADC5_AMUX_THM2                         0x0e
+#define ADC5_AMUX_THM3                         0x0f
+#define ADC5_AMUX_THM4                         0x10
+#define ADC5_AMUX_THM5                         0x11
+#define ADC5_GPIO1                             0x12
+#define ADC5_GPIO2                             0x13
+#define ADC5_GPIO3                             0x14
+#define ADC5_GPIO4                             0x15
+#define ADC5_GPIO5                             0x16
+#define ADC5_GPIO6                             0x17
+#define ADC5_GPIO7                             0x18
+#define ADC5_SBUx                              0x99
+#define ADC5_MID_CHG_DIV6                      0x1e
+#define ADC5_OFF                               0xff
+
+/* 30k pull-up1 */
+#define ADC5_BAT_THERM_30K_PU                  0x2a
+#define ADC5_BAT_ID_30K_PU                     0x2b
+#define ADC5_XO_THERM_30K_PU                   0x2c
+#define ADC5_AMUX_THM1_30K_PU                  0x2d
+#define ADC5_AMUX_THM2_30K_PU                  0x2e
+#define ADC5_AMUX_THM3_30K_PU                  0x2f
+#define ADC5_AMUX_THM4_30K_PU                  0x30
+#define ADC5_AMUX_THM5_30K_PU                  0x31
+#define ADC5_GPIO1_30K_PU                      0x32
+#define ADC5_GPIO2_30K_PU                      0x33
+#define ADC5_GPIO3_30K_PU                      0x34
+#define ADC5_GPIO4_30K_PU                      0x35
+#define ADC5_GPIO5_30K_PU                      0x36
+#define ADC5_GPIO6_30K_PU                      0x37
+#define ADC5_GPIO7_30K_PU                      0x38
+#define ADC5_SBUx_30K_PU                       0x39
+
+/* 100k pull-up2 */
+#define ADC5_BAT_THERM_100K_PU                 0x4a
+#define ADC5_BAT_ID_100K_PU                    0x4b
+#define ADC5_XO_THERM_100K_PU                  0x4c
+#define ADC5_AMUX_THM1_100K_PU                 0x4d
+#define ADC5_AMUX_THM2_100K_PU                 0x4e
+#define ADC5_AMUX_THM3_100K_PU                 0x4f
+#define ADC5_AMUX_THM4_100K_PU                 0x50
+#define ADC5_AMUX_THM5_100K_PU                 0x51
+#define ADC5_GPIO1_100K_PU                     0x52
+#define ADC5_GPIO2_100K_PU                     0x53
+#define ADC5_GPIO3_100K_PU                     0x54
+#define ADC5_GPIO4_100K_PU                     0x55
+#define ADC5_GPIO5_100K_PU                     0x56
+#define ADC5_GPIO6_100K_PU                     0x57
+#define ADC5_GPIO7_100K_PU                     0x58
+#define ADC5_SBUx_100K_PU                      0x59
+
+/* 400k pull-up3 */
+#define ADC5_BAT_THERM_400K_PU                 0x6a
+#define ADC5_BAT_ID_400K_PU                    0x6b
+#define ADC5_XO_THERM_400K_PU                  0x6c
+#define ADC5_AMUX_THM1_400K_PU                 0x6d
+#define ADC5_AMUX_THM2_400K_PU                 0x6e
+#define ADC5_AMUX_THM3_400K_PU                 0x6f
+#define ADC5_AMUX_THM4_400K_PU                 0x70
+#define ADC5_AMUX_THM5_400K_PU                 0x71
+#define ADC5_GPIO1_400K_PU                     0x72
+#define ADC5_GPIO2_400K_PU                     0x73
+#define ADC5_GPIO3_400K_PU                     0x74
+#define ADC5_GPIO4_400K_PU                     0x75
+#define ADC5_GPIO5_400K_PU                     0x76
+#define ADC5_GPIO6_400K_PU                     0x77
+#define ADC5_GPIO7_400K_PU                     0x78
+#define ADC5_SBUx_400K_PU                      0x79
+
+/* 1/3 Divider */
+#define ADC5_GPIO1_DIV3                                0x92
+#define ADC5_GPIO2_DIV3                                0x93
+#define ADC5_GPIO3_DIV3                                0x94
+#define ADC5_GPIO4_DIV3                                0x95
+#define ADC5_GPIO5_DIV3                                0x96
+#define ADC5_GPIO6_DIV3                                0x97
+#define ADC5_GPIO7_DIV3                                0x98
+#define ADC5_SBUx_DIV3                         0x99
+
+/* Current and combined current/voltage channels */
+#define ADC5_INT_EXT_ISENSE                    0xa1
+#define ADC5_PARALLEL_ISENSE                   0xa5
+#define ADC5_CUR_REPLICA_VDS                   0xa7
+#define ADC5_CUR_SENS_BATFET_VDS_OFFSET                0xa9
+#define ADC5_CUR_SENS_REPLICA_VDS_OFFSET       0xab
+#define ADC5_EXT_SENS_OFFSET                   0xad
+
+#define ADC5_INT_EXT_ISENSE_VBAT_VDATA         0xb0
+#define ADC5_INT_EXT_ISENSE_VBAT_IDATA         0xb1
+#define ADC5_EXT_ISENSE_VBAT_VDATA             0xb2
+#define ADC5_EXT_ISENSE_VBAT_IDATA             0xb3
+#define ADC5_PARALLEL_ISENSE_VBAT_VDATA                0xb4
+#define ADC5_PARALLEL_ISENSE_VBAT_IDATA                0xb5
+
+#define ADC5_MAX_CHANNEL                       0xc0
+
 #endif /* _DT_BINDINGS_QCOM_SPMI_VADC_H */