]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'iio-for-4.12d' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Apr 2017 15:13:31 +0000 (17:13 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Apr 2017 15:13:31 +0000 (17:13 +0200)
Jonathan writes:

Fourth set of IIO new device support, features and cleanups for the 4.12 cycle

New device support
* max1117, 1118 and 1119
  - new ADC driver
* max9611
  - new ADC driver
* pm8xxx hk/xoadc
  - new driver with some shared features broken out from the SPMI vadc.
* sun4i-gpadc
  - A33 thermal sensor support (with associated rework)
* stm32-dac
  - new driver and bindings
* stm32 trigger
  - enable support of quadrature encoder device and counter modes

Features
* apds9960
  - use the runtime pm for normal suspend
* stm32-adc
  - add opition to sest resolution via devicetree
* xoadc
  - augment DT bindings to deal with some weird mux cases

Cleanups
* ad5933
  - protect direct mode using claim and release helpers
ade7759
  - S_IRUGO and friends to octal in two goes
* adis16203
  - drop unnecessary brackets
* hid-sensor
  - fix unbalanced pm_runtieme_enable error when probing after remove
* lsm6dsx
  - use actual part numbers for device name when known
  - simplify data read pin parsing
* mpu3050
  - avoid double reporting errors

35 files changed:
Documentation/ABI/testing/sysfs-bus-iio-adc-max9611 [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
Documentation/devicetree/bindings/iio/adc/max1118.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/max9611.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/qcom,pm8xxx-xoadc.txt
Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt
Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt [new file with mode: 0644]
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/max1118.c [new file with mode: 0644]
drivers/iio/adc/max9611.c [new file with mode: 0644]
drivers/iio/adc/qcom-pm8xxx-xoadc.c [new file with mode: 0644]
drivers/iio/adc/qcom-spmi-vadc.c
drivers/iio/adc/qcom-vadc-common.c [new file with mode: 0644]
drivers/iio/adc/qcom-vadc-common.h [new file with mode: 0644]
drivers/iio/adc/stm32-adc.c
drivers/iio/adc/sun4i-gpadc-iio.c
drivers/iio/common/hid-sensors/hid-sensor-trigger.c
drivers/iio/dac/Kconfig
drivers/iio/dac/Makefile
drivers/iio/dac/stm32-dac-core.c [new file with mode: 0644]
drivers/iio/dac/stm32-dac-core.h [new file with mode: 0644]
drivers/iio/dac/stm32-dac.c [new file with mode: 0644]
drivers/iio/gyro/mpu3050-i2c.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
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/apds9960.c
drivers/iio/trigger/stm32-timer-trigger.c
drivers/staging/iio/accel/adis16203.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/iio/meter/ade7759.c
include/linux/mfd/stm32-timers.h
include/linux/mfd/sun4i-gpadc.h

diff --git a/Documentation/ABI/testing/sysfs-bus-iio-adc-max9611 b/Documentation/ABI/testing/sysfs-bus-iio-adc-max9611
new file mode 100644 (file)
index 0000000..6d2d2b0
--- /dev/null
@@ -0,0 +1,17 @@
+What:          /sys/bus/iio/devices/iio:deviceX/in_power_shunt_resistor
+Date:          March 2017
+KernelVersion: 4.12
+Contact:       linux-iio@vger.kernel.org
+Description:   The value of the shunt resistor used to compute power drain on
+                common input voltage pin (RS+). In Ohms.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_current_shunt_resistor
+Date:          March 2017
+KernelVersion: 4.12
+Contact:       linux-iio@vger.kernel.org
+Description:   The value of the shunt resistor used to compute current flowing
+                between RS+ and RS- voltage sense inputs. In Ohms.
+
+These attributes describe a single physical component, exposed as two distinct
+attributes as it is used to calculate two different values: power load and
+current flowing between RS+ and RS- inputs.
index 6534a60037ffa6129c7a1f90d7dca62f68b23c54..230020e06677d73a2b8b24c031962e3fbda19c45 100644 (file)
@@ -3,11 +3,15 @@ KernelVersion:        4.11
 Contact:       benjamin.gaignard@st.com
 Description:
                Reading returns the list possible master modes which are:
-               - "reset"     : The UG bit from the TIMx_EGR register is used as trigger output (TRGO).
-               - "enable"    : The Counter Enable signal CNT_EN is used as trigger output.
+               - "reset"     : The UG bit from the TIMx_EGR register is
+                               used as trigger output (TRGO).
+               - "enable"    : The Counter Enable signal CNT_EN is used
+                               as trigger output.
                - "update"    : The update event is selected as trigger output.
-                               For instance a master timer can then be used as a prescaler for a slave timer.
-               - "compare_pulse" : The trigger output send a positive pulse when the CC1IF flag is to be set.
+                               For instance a master timer can then be used
+                               as a prescaler for a slave timer.
+               - "compare_pulse" : The trigger output send a positive pulse
+                                   when the CC1IF flag is to be set.
                - "OC1REF"    : OC1REF signal is used as trigger output.
                - "OC2REF"    : OC2REF signal is used as trigger output.
                - "OC3REF"    : OC3REF signal is used as trigger output.
@@ -27,3 +31,62 @@ Description:
                Reading returns the current sampling frequency.
                Writing an value different of 0 set and start sampling.
                Writing 0 stop sampling.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_count0_preset
+KernelVersion: 4.12
+Contact:       benjamin.gaignard@st.com
+Description:
+               Reading returns the current preset value.
+               Writing sets the preset value.
+               When counting up the counter starts from 0 and fires an
+               event when reach preset value.
+               When counting down the counter start from preset value
+               and fire event when reach 0.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_count_quadrature_mode_available
+KernelVersion: 4.12
+Contact:       benjamin.gaignard@st.com
+Description:
+               Reading returns the list possible quadrature modes.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_count0_quadrature_mode
+KernelVersion: 4.12
+Contact:       benjamin.gaignard@st.com
+Description:
+               Configure the device counter quadrature modes:
+               channel_A:
+                       Encoder A input servers as the count input and B as
+                       the UP/DOWN direction control input.
+
+               channel_B:
+                       Encoder B input serves as the count input and A as
+                       the UP/DOWN direction control input.
+
+               quadrature:
+                       Encoder A and B inputs are mixed to get direction
+                       and count with a scale of 0.25.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_count_enable_mode_available
+KernelVersion: 4.12
+Contact:       benjamin.gaignard@st.com
+Description:
+               Reading returns the list possible enable modes.
+
+What:          /sys/bus/iio/devices/iio:deviceX/in_count0_enable_mode
+KernelVersion: 4.12
+Contact:       benjamin.gaignard@st.com
+Description:
+               Configure the device counter enable modes, in all case
+               counting direction is set by in_count0_count_direction
+               attribute and the counter is clocked by the internal clock.
+               always:
+                       Counter is always ON.
+
+               gated:
+                       Counting is enabled when connected trigger signal
+                       level is high else counting is disabled.
+
+               triggered:
+                       Counting is enabled on rising edge of the connected
+                       trigger, and remains enabled for the duration of this
+                       selected mode.
diff --git a/Documentation/devicetree/bindings/iio/adc/max1118.txt b/Documentation/devicetree/bindings/iio/adc/max1118.txt
new file mode 100644 (file)
index 0000000..cf33d0b
--- /dev/null
@@ -0,0 +1,21 @@
+* MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs
+
+Required properties:
+ - compatible: Should be one of
+       * "maxim,max1117"
+       * "maxim,max1118"
+       * "maxim,max1119"
+ - reg: spi chip select number for the device
+ - (max1118 only) vref-supply: The regulator supply for ADC reference voltage
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+               Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+adc@0 {
+       compatible = "maxim,max1118";
+       reg = <0>;
+       vref-supply = <&vdd_supply>;
+       spi-max-frequency = <1000000>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/max9611.txt b/Documentation/devicetree/bindings/iio/adc/max9611.txt
new file mode 100644 (file)
index 0000000..ab4f431
--- /dev/null
@@ -0,0 +1,27 @@
+* Maxim max9611/max9612 current sense amplifier with 12-bits ADC interface
+
+Maxim max9611/max9612 is an high-side current sense amplifier with integrated
+12-bits ADC communicating over I2c bus.
+The device node for this driver shall be a child of a I2c controller.
+
+Required properties
+  - compatible: Should be "maxim,max9611" or "maxim,max9612"
+  - reg: The 7-bits long I2c address of the device
+  - shunt-resistor-micro-ohms: Value, in micro Ohms, of the current sense shunt
+                               resistor
+
+Example:
+
+&i2c4 {
+       csa: adc@7c {
+               compatible = "maxim,max9611";
+               reg = <0x7c>;
+
+               shunt-resistor-micro-ohms = <5000>;
+       };
+};
+
+This device node describes a current sense amplifier sitting on I2c4 bus
+with address 0x7c (read address is 0xf9, write address is 0xf8).
+A sense resistor of 0,005 Ohm is installed between RS+ and RS- current-sensing
+inputs.
index 53cd146d8096becd5f85a6bdac7f06351a60c331..3ae06127789e30654792851c79b51fe3f53863e0 100644 (file)
@@ -19,32 +19,42 @@ Required properties:
   with PMIC variant but is typically something like 2.2 or 1.8V.
 
 The following required properties are standard for IO channels, see
-iio-bindings.txt for more details:
+iio-bindings.txt for more details, but notice that this particular
+ADC has a special addressing scheme that require two cells for
+identifying each ADC channel:
 
-- #address-cells: should be set to <1>
+- #address-cells: should be set to <2>, the first cell is the
+  prescaler (on PM8058) or premux (on PM8921) with two valid bits
+  so legal values are 0x00, 0x01 or 0x02. The second cell
+  is the main analog mux setting (0x00..0x0f). The combination
+  of prescaler/premux and analog mux uniquely addresses a hardware
+  channel on all systems.
 
 - #size-cells: should be set to <0>
 
-- #io-channel-cells: should be set to <1>
+- #io-channel-cells: should be set to <2>, again the cells are
+  precaler or premux followed by the analog muxing line.
 
 - interrupts: should refer to the parent PMIC interrupt controller
   and reference the proper ADC interrupt.
 
 Required subnodes:
 
-The ADC channels are configured as subnodes of the ADC. Since some of
-them are used for calibrating the ADC, these nodes are compulsory:
+The ADC channels are configured as subnodes of the ADC.
+
+Since some of them are used for calibrating the ADC, these nodes are
+compulsory:
 
 adc-channel@c {
-       reg = <0x0c>;
+       reg = <0x00 0x0c>;
 };
 
 adc-channel@d {
-       reg = <0x0d>;
+       reg = <0x00 0x0d>;
 };
 
 adc-channel@f {
-       reg = <0x0f>;
+       reg = <0x00 0x0f>;
 };
 
 These three nodes are used for absolute and ratiometric calibration
@@ -52,13 +62,13 @@ and only need to have these reg values: they are by hardware definition
 1:1 ratio converters that sample 625, 1250 and 0 milliV and create
 an interpolation calibration for all other ADCs.
 
-Optional subnodes: any channels other than channel 0x0c, 0x0d and
-0x0f are optional.
+Optional subnodes: any channels other than channels [0x00 0x0c],
+[0x00 0x0d] and [0x00 0x0f] are optional.
 
 Required channel node properties:
 
 - reg: should contain the hardware channel number in the range
-  0 .. 0x0f (4 bits). The hardware only supports 16 channels.
+  0 .. 0xff (8 bits).
 
 Optional channel node properties:
 
@@ -94,56 +104,54 @@ Example:
 xoadc: xoadc@197 {
        compatible = "qcom,pm8058-adc";
        reg = <0x197>;
-       interrupt-parent = <&pm8058>;
-       interrupts = <76 1>;
-       #address-cells = <1>;
+       interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>;
+       #address-cells = <2>;
        #size-cells = <0>;
-       #io-channel-cells = <1>;
+       #io-channel-cells = <2>;
 
        vcoin: adc-channel@0 {
-               reg = <0x00>;
+               reg = <0x00 0x00>;
        };
        vbat: adc-channel@1 {
-               reg = <0x01>;
+               reg = <0x00 0x01>;
        };
        dcin: adc-channel@2 {
-               reg = <0x02>;
+               reg = <0x00 0x02>;
        };
        ichg: adc-channel@3 {
-               reg = <0x03>;
+               reg = <0x00 0x03>;
        };
        vph_pwr: adc-channel@4 {
-               reg = <0x04>;
+               reg = <0x00 0x04>;
        };
        usb_vbus: adc-channel@a {
-               reg = <0x0a>;
+               reg = <0x00 0x0a>;
        };
        die_temp: adc-channel@b {
-               reg = <0x0b>;
+               reg = <0x00 0x0b>;
        };
        ref_625mv: adc-channel@c {
-               reg = <0x0c>;
+               reg = <0x00 0x0c>;
        };
        ref_1250mv: adc-channel@d {
-               reg = <0x0d>;
+               reg = <0x00 0x0d>;
        };
        ref_325mv: adc-channel@e {
-               reg = <0x0e>;
+               reg = <0x00 0x0e>;
        };
        ref_muxoff: adc-channel@f {
-               reg = <0x0f>;
+               reg = <0x00 0x0f>;
        };
 };
 
-
 /* IIO client node */
 iio-hwmon {
        compatible = "iio-hwmon";
-       io-channels = <&xoadc 0x01>, /* Battery */
-                   <&xoadc 0x02>, /* DC in (charger) */
-                   <&xoadc 0x04>, /* VPH the main system voltage */
-                   <&xoadc 0x0b>, /* Die temperature */
-                   <&xoadc 0x0c>, /* Reference voltage 1.25V */
-                   <&xoadc 0x0d>, /* Reference voltage 0.625V */
-                   <&xoadc 0x0e>; /* Reference voltage 0.325V */
+       io-channels = <&xoadc 0x00 0x01>, /* Battery */
+                   <&xoadc 0x00 0x02>, /* DC in (charger) */
+                   <&xoadc 0x00 0x04>, /* VPH the main system voltage */
+                   <&xoadc 0x00 0x0b>, /* Die temperature */
+                   <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */
+                   <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */
+                   <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */
 };
index 5dfc88ec24a49ad7a0ae3c950b0ed5adc26d7a18..e35f9f1b320042c6b89714d32d3998db58e2a4e3 100644 (file)
@@ -57,6 +57,9 @@ Optional properties:
 - dmas: Phandle to dma channel for this ADC instance.
   See ../../dma/dma.txt for details.
 - dma-names: Must be "rx" when dmas property is being used.
+- assigned-resolution-bits: Resolution (bits) to use for conversions. Must
+  match device available resolutions (e.g. can be 6, 8, 10 or 12 on stm32f4).
+  Default is maximum resolution if unset.
 
 Example:
        adc: adc@40012000 {
@@ -84,6 +87,7 @@ Example:
                        st,adc-channels = <8>;
                        dmas = <&dma2 0 0 0x400 0x0>;
                        dma-names = "rx";
+                       assigned-resolution-bits = <8>;
                };
                ...
                other adc child nodes follow...
diff --git a/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
new file mode 100644 (file)
index 0000000..bcee71f
--- /dev/null
@@ -0,0 +1,61 @@
+STMicroelectronics STM32 DAC
+
+The STM32 DAC is a 12-bit voltage output digital-to-analog converter. The DAC
+may be configured in 8 or 12-bit mode. It has two output channels, each with
+its own converter.
+It has built-in noise and triangle waveform generator and supports external
+triggers for conversions. The DAC's output buffer allows a high drive output
+current.
+
+Contents of a stm32 dac root node:
+-----------------------------------
+Required properties:
+- compatible: Must be "st,stm32h7-dac-core".
+- reg: Offset and length of the device's register set.
+- clocks: Must contain an entry for pclk (which feeds the peripheral bus
+  interface)
+- clock-names: Must be "pclk".
+- vref-supply: Phandle to the vref+ input analog reference supply.
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- resets: Must contain the phandle to the reset controller.
+- A pinctrl state named "default" for each DAC channel may be defined to set
+  DAC_OUTx pin in mode of operation for analog output on external pin.
+
+Contents of a stm32 dac child node:
+-----------------------------------
+DAC core node should contain at least one subnode, representing a
+DAC instance/channel available on the machine.
+
+Required properties:
+- compatible: Must be "st,stm32-dac".
+- reg: Must be either 1 or 2, to define (single) channel in use
+- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
+  Documentation/devicetree/bindings/iio/iio-bindings.txt
+
+Example:
+       dac: dac@40007400 {
+               compatible = "st,stm32h7-dac-core";
+               reg = <0x40007400 0x400>;
+               clocks = <&clk>;
+               clock-names = "pclk";
+               vref-supply = <&reg_vref>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&dac_out1 &dac_out2>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               dac1: dac@1 {
+                       compatible = "st,stm32-dac";
+                       #io-channels-cells = <1>;
+                       reg = <1>;
+               };
+
+               dac2: dac@2 {
+                       compatible = "st,stm32-dac";
+                       #io-channels-cells = <1>;
+                       reg = <2>;
+               };
+       };
index b7b3a9a80043762ae9305c6f39bd209e50c59656..0b8915298bf1ff8d663b6d66e4c0af7d5ea57d30 100644 (file)
@@ -379,6 +379,18 @@ config MAX11100
          To compile this driver as a module, choose M here: the module will be
          called max11100.
 
+config MAX1118
+       tristate "Maxim max1117/max1118/max1119 ADCs driver"
+       depends on SPI
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       help
+         Say yes here to build support for Maxim max1117/max1118/max1119
+         8-bit, dual-channel ADCs.
+
+         To compile this driver as a module, choose M here: the module will be
+         called max1118.
+
 config MAX1363
        tristate "Maxim max1363 ADC driver"
        depends on I2C
@@ -398,6 +410,16 @@ config MAX1363
          To compile this driver as a module, choose M here: the module will be
          called max1363.
 
+config MAX9611
+       tristate "Maxim max9611/max9612 ADC driver"
+       depends on I2C
+       help
+         Say yes here to build support for Maxim max9611/max9612 current sense
+         amplifier with 12-bits ADC interface.
+
+         To compile this driver as a module, choose M here: the module will be
+         called max9611.
+
 config MCP320X
        tristate "Microchip Technology MCP3x01/02/04/08"
        depends on SPI
@@ -486,6 +508,20 @@ config PALMAS_GPADC
          is used in smartphones and tablets and supports a 16 channel
          general purpose ADC.
 
+config QCOM_VADC_COMMON
+       tristate
+
+config QCOM_PM8XXX_XOADC
+       tristate "Qualcomm SSBI PM8xxx PMIC XOADCs"
+       depends on MFD_PM8XXX
+       select QCOM_VADC_COMMON
+       help
+         ADC driver for the XOADC portions of the Qualcomm PM8xxx PMICs
+         using SSBI transport: PM8018, PM8038, PM8058, PM8921.
+
+         To compile this driver as a module, choose M here: the module
+         will be called qcom-pm8xxx-xoadc.
+
 config QCOM_SPMI_IADC
        tristate "Qualcomm SPMI PMIC current ADC"
        depends on SPMI
@@ -504,6 +540,7 @@ config QCOM_SPMI_VADC
        tristate "Qualcomm SPMI PMIC voltage ADC"
        depends on SPMI
        select REGMAP_SPMI
+       select QCOM_VADC_COMMON
        help
          This is the IIO Voltage ADC driver for Qualcomm QPNP VADC Chip.
 
@@ -594,7 +631,7 @@ config STX104
 config SUN4I_GPADC
        tristate "Support for the Allwinner SoCs GPADC"
        depends on IIO
-       depends on MFD_SUN4I_GPADC
+       depends on MFD_SUN4I_GPADC || MACH_SUN8I
        depends on THERMAL || !THERMAL_OF
        help
          Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
index 3d9174ab26c8afbbef4be05b20e9c5b67b84f260..56e5fabece4ce12d54a3ca9ce8fbb651cf913a29 100644 (file)
@@ -37,7 +37,9 @@ obj-$(CONFIG_LTC2485) += ltc2485.o
 obj-$(CONFIG_LTC2497) += ltc2497.o
 obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX11100) += max11100.o
+obj-$(CONFIG_MAX1118) += max1118.o
 obj-$(CONFIG_MAX1363) += max1363.o
+obj-$(CONFIG_MAX9611) += max9611.o
 obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
@@ -47,7 +49,9 @@ obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.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
+obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
 obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c
new file mode 100644 (file)
index 0000000..2e9648a
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * MAX1117/MAX1118/MAX1119 8-bit, dual-channel ADCs driver
+ *
+ * Copyright (c) 2017 Akinobu Mita <akinobu.mita@gmail.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1117-MAX1119.pdf
+ *
+ * SPI interface connections
+ *
+ * SPI                MAXIM
+ * Master  Direction  MAX1117/8/9
+ * ------  ---------  -----------
+ * nCS        -->     CNVST
+ * SCK        -->     SCLK
+ * MISO       <--     DOUT
+ * ------  ---------  -----------
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/regulator/consumer.h>
+
+enum max1118_id {
+       max1117,
+       max1118,
+       max1119,
+};
+
+struct max1118 {
+       struct spi_device *spi;
+       struct mutex lock;
+       struct regulator *reg;
+
+       u8 data ____cacheline_aligned;
+};
+
+#define MAX1118_CHANNEL(ch)                                            \
+       {                                                               \
+               .type = IIO_VOLTAGE,                                    \
+               .indexed = 1,                                           \
+               .channel = (ch),                                        \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+               .scan_index = ch,                                       \
+               .scan_type = {                                          \
+                       .sign = 'u',                                    \
+                       .realbits = 8,                                  \
+                       .storagebits = 8,                               \
+               },                                                      \
+       }
+
+static const struct iio_chan_spec max1118_channels[] = {
+       MAX1118_CHANNEL(0),
+       MAX1118_CHANNEL(1),
+       IIO_CHAN_SOFT_TIMESTAMP(2),
+};
+
+static int max1118_read(struct spi_device *spi, int channel)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct max1118 *adc = iio_priv(indio_dev);
+       struct spi_transfer xfers[] = {
+               /*
+                * To select CH1 for conversion, CNVST pin must be brought high
+                * and low for a second time.
+                */
+               {
+                       .len = 0,
+                       .delay_usecs = 1,       /* > CNVST Low Time 100 ns */
+                       .cs_change = 1,
+               },
+               /*
+                * The acquisition interval begins with the falling edge of
+                * CNVST.  The total acquisition and conversion process takes
+                * <7.5us.
+                */
+               {
+                       .len = 0,
+                       .delay_usecs = 8,
+               },
+               {
+                       .rx_buf = &adc->data,
+                       .len = 1,
+               },
+       };
+       int ret;
+
+       if (channel == 0)
+               ret = spi_sync_transfer(spi, xfers + 1, 2);
+       else
+               ret = spi_sync_transfer(spi, xfers, 3);
+
+       if (ret)
+               return ret;
+
+       return adc->data;
+}
+
+static int max1118_get_vref_mV(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct max1118 *adc = iio_priv(indio_dev);
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       int vref_uV;
+
+       switch (id->driver_data) {
+       case max1117:
+               return 2048;
+       case max1119:
+               return 4096;
+       case max1118:
+               vref_uV = regulator_get_voltage(adc->reg);
+               if (vref_uV < 0)
+                       return vref_uV;
+               return vref_uV / 1000;
+       }
+
+       return -ENODEV;
+}
+
+static int max1118_read_raw(struct iio_dev *indio_dev,
+                       struct iio_chan_spec const *chan,
+                       int *val, int *val2, long mask)
+{
+       struct max1118 *adc = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&adc->lock);
+               *val = max1118_read(adc->spi, chan->channel);
+               mutex_unlock(&adc->lock);
+               if (*val < 0)
+                       return *val;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = max1118_get_vref_mV(adc->spi);
+               if (*val < 0)
+                       return *val;
+               *val2 = 8;
+
+               return IIO_VAL_FRACTIONAL_LOG2;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_info max1118_info = {
+       .read_raw = max1118_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static irqreturn_t max1118_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct max1118 *adc = iio_priv(indio_dev);
+       u8 data[16] = { }; /* 2x 8-bit ADC data + padding + 8 bytes timestamp */
+       int scan_index;
+       int i = 0;
+
+       mutex_lock(&adc->lock);
+
+       for_each_set_bit(scan_index, indio_dev->active_scan_mask,
+                       indio_dev->masklength) {
+               const struct iio_chan_spec *scan_chan =
+                               &indio_dev->channels[scan_index];
+               int ret = max1118_read(adc->spi, scan_chan->channel);
+
+               if (ret < 0) {
+                       dev_warn(&adc->spi->dev,
+                               "failed to get conversion data\n");
+                       goto out;
+               }
+
+               data[i] = ret;
+               i++;
+       }
+       iio_push_to_buffers_with_timestamp(indio_dev, data,
+                                          iio_get_time_ns(indio_dev));
+out:
+       mutex_unlock(&adc->lock);
+
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int max1118_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct max1118 *adc;
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       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;
+       mutex_init(&adc->lock);
+
+       if (id->driver_data == max1118) {
+               adc->reg = devm_regulator_get(&spi->dev, "vref");
+               if (IS_ERR(adc->reg)) {
+                       dev_err(&spi->dev, "failed to get vref regulator\n");
+                       return PTR_ERR(adc->reg);
+               }
+               ret = regulator_enable(adc->reg);
+               if (ret)
+                       return ret;
+       }
+
+       spi_set_drvdata(spi, indio_dev);
+
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->info = &max1118_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = max1118_channels;
+       indio_dev->num_channels = ARRAY_SIZE(max1118_channels);
+
+       /*
+        * To reinitiate a conversion on CH0, it is necessary to allow for a
+        * conversion to be complete and all of the data to be read out.  Once
+        * a conversion has been completed, the MAX1117/MAX1118/MAX1119 will go
+        * into AutoShutdown mode until the next conversion is initiated.
+        */
+       max1118_read(spi, 0);
+
+       ret = iio_triggered_buffer_setup(indio_dev, NULL,
+                                       max1118_trigger_handler, NULL);
+       if (ret)
+               goto err_reg_disable;
+
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto err_buffer_cleanup;
+
+       return 0;
+
+err_buffer_cleanup:
+       iio_triggered_buffer_cleanup(indio_dev);
+err_reg_disable:
+       if (id->driver_data == max1118)
+               regulator_disable(adc->reg);
+
+       return ret;
+}
+
+static int max1118_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct max1118 *adc = iio_priv(indio_dev);
+       const struct spi_device_id *id = spi_get_device_id(spi);
+
+       iio_device_unregister(indio_dev);
+       iio_triggered_buffer_cleanup(indio_dev);
+       if (id->driver_data == max1118)
+               return regulator_disable(adc->reg);
+
+       return 0;
+}
+
+static const struct spi_device_id max1118_id[] = {
+       { "max1117", max1117 },
+       { "max1118", max1118 },
+       { "max1119", max1119 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, max1118_id);
+
+#ifdef CONFIG_OF
+
+static const struct of_device_id max1118_dt_ids[] = {
+       { .compatible = "maxim,max1117" },
+       { .compatible = "maxim,max1118" },
+       { .compatible = "maxim,max1119" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, max1118_dt_ids);
+
+#endif
+
+static struct spi_driver max1118_spi_driver = {
+       .driver = {
+               .name = "max1118",
+               .of_match_table = of_match_ptr(max1118_dt_ids),
+       },
+       .probe = max1118_probe,
+       .remove = max1118_remove,
+       .id_table = max1118_id,
+};
+module_spi_driver(max1118_spi_driver);
+
+MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
+MODULE_DESCRIPTION("MAXIM MAX1117/MAX1118/MAX1119 ADCs driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
new file mode 100644 (file)
index 0000000..ec82106
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ * iio/adc/max9611.c
+ *
+ * Maxim max9611/max9612 high side current sense amplifier with
+ * 12-bit ADC interface.
+ *
+ * Copyright (C) 2017 Jacopo Mondi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This driver supports input common-mode voltage, current-sense
+ * amplifier with programmable gains and die temperature reading from
+ * Maxim max9611/max9612.
+ *
+ * Op-amp, analog comparator, and watchdog functionalities are not
+ * supported by this driver.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#define DRIVER_NAME                    "max9611"
+
+/* max9611 register addresses */
+#define MAX9611_REG_CSA_DATA           0x00
+#define MAX9611_REG_RS_DATA            0x02
+#define MAX9611_REG_TEMP_DATA          0x08
+#define MAX9611_REG_CTRL1              0x0a
+#define MAX9611_REG_CTRL2              0x0b
+
+/* max9611 REG1 mux configuration options */
+#define MAX9611_MUX_MASK               GENMASK(3, 0)
+#define MAX9611_MUX_SENSE_1x           0x00
+#define MAX9611_MUX_SENSE_4x           0x01
+#define MAX9611_MUX_SENSE_8x           0x02
+#define MAX9611_INPUT_VOLT             0x03
+#define MAX9611_MUX_TEMP               0x06
+
+/* max9611 voltage (both csa and input) helper macros */
+#define MAX9611_VOLTAGE_SHIFT          0x04
+#define MAX9611_VOLTAGE_RAW(_r)                ((_r) >> MAX9611_VOLTAGE_SHIFT)
+
+/*
+ * max9611 current sense amplifier voltage output:
+ * LSB and offset values depends on selected gain (1x, 4x, 8x)
+ *
+ * GAIN                LSB (nV)        OFFSET (LSB steps)
+ * 1x          107500          1
+ * 4x          26880           1
+ * 8x          13440           3
+ *
+ * The complete formula to calculate current sense voltage is:
+ *     (((adc_read >> 4) - offset) / ((1 / LSB) * 10^-3)
+ */
+#define MAX9611_CSA_1X_LSB_nV          107500
+#define MAX9611_CSA_4X_LSB_nV          26880
+#define MAX9611_CSA_8X_LSB_nV          13440
+
+#define MAX9611_CSA_1X_OFFS_RAW                1
+#define MAX9611_CSA_4X_OFFS_RAW                1
+#define MAX9611_CSA_8X_OFFS_RAW                3
+
+/*
+ * max9611 common input mode (CIM): LSB is 14mV, with 14mV offset at 25 C
+ *
+ * The complete formula to calculate input common voltage is:
+ *     (((adc_read >> 4) * 1000) - offset) / (1 / 14 * 1000)
+ */
+#define MAX9611_CIM_LSB_mV             14
+#define MAX9611_CIM_OFFSET_RAW         1
+
+/*
+ * max9611 temperature reading: LSB is 480 milli degrees Celsius
+ *
+ * The complete formula to calculate temperature is:
+ *     ((adc_read >> 7) * 1000) / (1 / 480 * 1000)
+ */
+#define MAX9611_TEMP_MAX_POS           0x7f80
+#define MAX9611_TEMP_MAX_NEG           0xff80
+#define MAX9611_TEMP_MIN_NEG           0xd980
+#define MAX9611_TEMP_MASK              GENMASK(7, 15)
+#define MAX9611_TEMP_SHIFT             0x07
+#define MAX9611_TEMP_RAW(_r)           ((_r) >> MAX9611_TEMP_SHIFT)
+#define MAX9611_TEMP_SCALE_NUM         1000000
+#define MAX9611_TEMP_SCALE_DIV         2083
+
+struct max9611_dev {
+       struct device *dev;
+       struct i2c_client *i2c_client;
+       struct mutex lock;
+       unsigned int shunt_resistor_uohm;
+};
+
+enum max9611_conf_ids {
+       CONF_SENSE_1x,
+       CONF_SENSE_4x,
+       CONF_SENSE_8x,
+       CONF_IN_VOLT,
+       CONF_TEMP,
+};
+
+/**
+ * max9611_mux_conf - associate ADC mux configuration with register address
+ *                   where data shall be read from
+ */
+static const unsigned int max9611_mux_conf[][2] = {
+       /* CONF_SENSE_1x */
+       { MAX9611_MUX_SENSE_1x, MAX9611_REG_CSA_DATA },
+       /* CONF_SENSE_4x */
+       { MAX9611_MUX_SENSE_4x, MAX9611_REG_CSA_DATA },
+       /* CONF_SENSE_8x */
+       { MAX9611_MUX_SENSE_8x, MAX9611_REG_CSA_DATA },
+       /* CONF_IN_VOLT */
+       { MAX9611_INPUT_VOLT, MAX9611_REG_RS_DATA },
+       /* CONF_TEMP */
+       { MAX9611_MUX_TEMP, MAX9611_REG_TEMP_DATA },
+};
+
+enum max9611_csa_gain {
+       CSA_GAIN_1x,
+       CSA_GAIN_4x,
+       CSA_GAIN_8x,
+};
+
+enum max9611_csa_gain_params {
+       CSA_GAIN_LSB_nV,
+       CSA_GAIN_OFFS_RAW,
+};
+
+/**
+ * max9611_csa_gain_conf - associate gain multiplier with LSB and
+ *                        offset values.
+ *
+ * Group together parameters associated with configurable gain
+ * on current sense amplifier path to ADC interface.
+ * Current sense read routine adjusts gain until it gets a meaningful
+ * value; use this structure to retrieve the correct LSB and offset values.
+ */
+static const unsigned int max9611_gain_conf[][2] = {
+       { /* [0] CSA_GAIN_1x */
+               MAX9611_CSA_1X_LSB_nV,
+               MAX9611_CSA_1X_OFFS_RAW,
+       },
+       { /* [1] CSA_GAIN_4x */
+               MAX9611_CSA_4X_LSB_nV,
+               MAX9611_CSA_4X_OFFS_RAW,
+       },
+       { /* [2] CSA_GAIN_8x */
+               MAX9611_CSA_8X_LSB_nV,
+               MAX9611_CSA_8X_OFFS_RAW,
+       },
+};
+
+enum max9611_chan_addrs {
+       MAX9611_CHAN_VOLTAGE_INPUT,
+       MAX9611_CHAN_VOLTAGE_SENSE,
+       MAX9611_CHAN_TEMPERATURE,
+       MAX9611_CHAN_CURRENT_LOAD,
+       MAX9611_CHAN_POWER_LOAD,
+};
+
+static const struct iio_chan_spec max9611_channels[] = {
+       {
+         .type                 = IIO_TEMP,
+         .info_mask_separate   = BIT(IIO_CHAN_INFO_RAW) |
+                                 BIT(IIO_CHAN_INFO_SCALE),
+         .address              = MAX9611_CHAN_TEMPERATURE,
+       },
+       {
+         .type                 = IIO_VOLTAGE,
+         .info_mask_separate   = BIT(IIO_CHAN_INFO_PROCESSED),
+         .address              = MAX9611_CHAN_VOLTAGE_SENSE,
+         .indexed              = 1,
+         .channel              = 0,
+       },
+       {
+         .type                 = IIO_VOLTAGE,
+         .info_mask_separate   = BIT(IIO_CHAN_INFO_RAW)   |
+                                 BIT(IIO_CHAN_INFO_SCALE) |
+                                 BIT(IIO_CHAN_INFO_OFFSET),
+         .address              = MAX9611_CHAN_VOLTAGE_INPUT,
+         .indexed              = 1,
+         .channel              = 1,
+       },
+       {
+         .type                 = IIO_CURRENT,
+         .info_mask_separate   = BIT(IIO_CHAN_INFO_PROCESSED),
+         .address              = MAX9611_CHAN_CURRENT_LOAD,
+       },
+       {
+         .type                 = IIO_POWER,
+         .info_mask_separate   = BIT(IIO_CHAN_INFO_PROCESSED),
+         .address              = MAX9611_CHAN_POWER_LOAD
+       },
+};
+
+/**
+ * max9611_read_single() - read a single value from ADC interface
+ *
+ * Data registers are 16 bit long, spread between two 8 bit registers
+ * with consecutive addresses.
+ * Configure ADC mux first, then read register at address "reg_addr".
+ * The smbus_read_word routine asks for 16 bits and the ADC is kind enough
+ * to return values from "reg_addr" and "reg_addr + 1" consecutively.
+ * Data are transmitted with big-endian ordering: MSB arrives first.
+ *
+ * @max9611: max9611 device
+ * @selector: index for mux and register configuration
+ * @raw_val: the value returned from ADC
+ */
+static int max9611_read_single(struct max9611_dev *max9611,
+                              enum max9611_conf_ids selector,
+                              u16 *raw_val)
+{
+       int ret;
+
+       u8 mux_conf = max9611_mux_conf[selector][0] & MAX9611_MUX_MASK;
+       u8 reg_addr = max9611_mux_conf[selector][1];
+
+       /*
+        * Keep mutex lock held during read-write to avoid mux register
+        * (CTRL1) re-configuration.
+        */
+       mutex_lock(&max9611->lock);
+       ret = i2c_smbus_write_byte_data(max9611->i2c_client,
+                                       MAX9611_REG_CTRL1, mux_conf);
+       if (ret) {
+               dev_err(max9611->dev, "i2c write byte failed: 0x%2x - 0x%2x\n",
+                       MAX9611_REG_CTRL1, mux_conf);
+               mutex_unlock(&max9611->lock);
+               return ret;
+       }
+
+       /*
+        * need a delay here to make register configuration
+        * stabilize. 1 msec at least, from empirical testing.
+        */
+       usleep_range(1000, 2000);
+
+       ret = i2c_smbus_read_word_swapped(max9611->i2c_client, reg_addr);
+       if (ret < 0) {
+               dev_err(max9611->dev, "i2c read word from 0x%2x failed\n",
+                       reg_addr);
+               mutex_unlock(&max9611->lock);
+               return ret;
+       }
+
+       *raw_val = ret;
+       mutex_unlock(&max9611->lock);
+
+       return 0;
+}
+
+/**
+ * max9611_read_csa_voltage() - read current sense amplifier output voltage
+ *
+ * Current sense amplifier output voltage is read through a configurable
+ * 1x, 4x or 8x gain.
+ * Start with plain 1x gain, and adjust gain control properly until a
+ * meaningful value is read from ADC output.
+ *
+ * @max9611: max9611 device
+ * @adc_raw: raw value read from ADC output
+ * @csa_gain: gain configuration option selector
+ */
+static int max9611_read_csa_voltage(struct max9611_dev *max9611,
+                                   u16 *adc_raw,
+                                   enum max9611_csa_gain *csa_gain)
+{
+       enum max9611_conf_ids gain_selectors[] = {
+               CONF_SENSE_1x,
+               CONF_SENSE_4x,
+               CONF_SENSE_8x
+       };
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < ARRAY_SIZE(gain_selectors); ++i) {
+               ret = max9611_read_single(max9611, gain_selectors[i], adc_raw);
+               if (ret)
+                       return ret;
+
+               if (*adc_raw > 0) {
+                       *csa_gain = gain_selectors[i];
+                       return 0;
+               }
+       }
+
+       return -EIO;
+}
+
+static int max9611_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct max9611_dev *dev = iio_priv(indio_dev);
+       enum max9611_csa_gain gain_selector;
+       const unsigned int *csa_gain;
+       u16 adc_data;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+
+               switch (chan->address) {
+               case MAX9611_CHAN_TEMPERATURE:
+                       ret = max9611_read_single(dev, CONF_TEMP,
+                                                 &adc_data);
+                       if (ret)
+                               return -EINVAL;
+
+                       *val = MAX9611_TEMP_RAW(adc_data);
+                       return IIO_VAL_INT;
+
+               case MAX9611_CHAN_VOLTAGE_INPUT:
+                       ret = max9611_read_single(dev, CONF_IN_VOLT,
+                                                 &adc_data);
+                       if (ret)
+                               return -EINVAL;
+
+                       *val = MAX9611_VOLTAGE_RAW(adc_data);
+                       return IIO_VAL_INT;
+               }
+
+               break;
+
+       case IIO_CHAN_INFO_OFFSET:
+               /* MAX9611_CHAN_VOLTAGE_INPUT */
+               *val = MAX9611_CIM_OFFSET_RAW;
+
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+
+               switch (chan->address) {
+               case MAX9611_CHAN_TEMPERATURE:
+                       *val = MAX9611_TEMP_SCALE_NUM;
+                       *val2 = MAX9611_TEMP_SCALE_DIV;
+
+                       return IIO_VAL_FRACTIONAL;
+
+               case MAX9611_CHAN_VOLTAGE_INPUT:
+                       *val = MAX9611_CIM_LSB_mV;
+
+                       return IIO_VAL_INT;
+               }
+
+               break;
+
+       case IIO_CHAN_INFO_PROCESSED:
+
+               switch (chan->address) {
+               case MAX9611_CHAN_VOLTAGE_SENSE:
+                       /*
+                        * processed (mV): (raw - offset) * LSB (nV) / 10^6
+                        *
+                        * Even if max9611 can output raw csa voltage readings,
+                        * use a produced value as scale depends on gain.
+                        */
+                       ret = max9611_read_csa_voltage(dev, &adc_data,
+                                                      &gain_selector);
+                       if (ret)
+                               return -EINVAL;
+
+                       csa_gain = max9611_gain_conf[gain_selector];
+
+                       adc_data -= csa_gain[CSA_GAIN_OFFS_RAW];
+                       *val = MAX9611_VOLTAGE_RAW(adc_data) *
+                              csa_gain[CSA_GAIN_LSB_nV];
+                       *val2 = 1000000;
+
+                       return IIO_VAL_FRACTIONAL;
+
+               case MAX9611_CHAN_CURRENT_LOAD:
+                       /* processed (mA): Vcsa (nV) / Rshunt (uOhm)  */
+                       ret = max9611_read_csa_voltage(dev, &adc_data,
+                                                      &gain_selector);
+                       if (ret)
+                               return -EINVAL;
+
+                       csa_gain = max9611_gain_conf[gain_selector];
+
+                       adc_data -= csa_gain[CSA_GAIN_OFFS_RAW];
+                       *val = MAX9611_VOLTAGE_RAW(adc_data) *
+                              csa_gain[CSA_GAIN_LSB_nV];
+                       *val2 = dev->shunt_resistor_uohm;
+
+                       return IIO_VAL_FRACTIONAL;
+
+               case MAX9611_CHAN_POWER_LOAD:
+                       /*
+                        * processed (mW): Vin (mV) * Vcsa (uV) /
+                        *                 Rshunt (uOhm)
+                        */
+                       ret = max9611_read_single(dev, CONF_IN_VOLT,
+                                                 &adc_data);
+                       if (ret)
+                               return -EINVAL;
+
+                       adc_data -= MAX9611_CIM_OFFSET_RAW;
+                       *val = MAX9611_VOLTAGE_RAW(adc_data) *
+                              MAX9611_CIM_LSB_mV;
+
+                       ret = max9611_read_csa_voltage(dev, &adc_data,
+                                                      &gain_selector);
+                       if (ret)
+                               return -EINVAL;
+
+                       csa_gain = max9611_gain_conf[gain_selector];
+
+                       /* divide by 10^3 here to avoid 32bit overflow */
+                       adc_data -= csa_gain[CSA_GAIN_OFFS_RAW];
+                       *val *= MAX9611_VOLTAGE_RAW(adc_data) *
+                               csa_gain[CSA_GAIN_LSB_nV] / 1000;
+                       *val2 = dev->shunt_resistor_uohm;
+
+                       return IIO_VAL_FRACTIONAL;
+               }
+
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static ssize_t max9611_shunt_resistor_show(struct device *dev,
+                                          struct device_attribute *attr,
+                                          char *buf)
+{
+       struct max9611_dev *max9611 = iio_priv(dev_to_iio_dev(dev));
+       unsigned int i, r;
+
+       i = max9611->shunt_resistor_uohm / 1000;
+       r = max9611->shunt_resistor_uohm % 1000;
+
+       return sprintf(buf, "%u.%03u\n", i, r);
+}
+
+static IIO_DEVICE_ATTR(in_power_shunt_resistor, 0444,
+                      max9611_shunt_resistor_show, NULL, 0);
+static IIO_DEVICE_ATTR(in_current_shunt_resistor, 0444,
+                      max9611_shunt_resistor_show, NULL, 0);
+
+static struct attribute *max9611_attributes[] = {
+       &iio_dev_attr_in_power_shunt_resistor.dev_attr.attr,
+       &iio_dev_attr_in_current_shunt_resistor.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group max9611_attribute_group = {
+       .attrs = max9611_attributes,
+};
+
+static const struct iio_info indio_info = {
+       .driver_module  = THIS_MODULE,
+       .read_raw       = max9611_read_raw,
+       .attrs          = &max9611_attribute_group,
+};
+
+static int max9611_init(struct max9611_dev *max9611)
+{
+       struct i2c_client *client = max9611->i2c_client;
+       u16 regval;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                                    I2C_FUNC_SMBUS_WRITE_BYTE  |
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+               dev_err(max9611->dev,
+                       "I2c adapter does not support smbus write_byte or read_word functionalities: aborting probe.\n");
+               return -EINVAL;
+       }
+
+       /* Make sure die temperature is in range to test communications. */
+       ret = max9611_read_single(max9611, CONF_TEMP, &regval);
+       if (ret)
+               return ret;
+
+       regval = ret & MAX9611_TEMP_MASK;
+
+       if ((regval > MAX9611_TEMP_MAX_POS &&
+            regval < MAX9611_TEMP_MIN_NEG) ||
+            regval > MAX9611_TEMP_MAX_NEG) {
+               dev_err(max9611->dev,
+                       "Invalid value received from ADC 0x%4x: aborting\n",
+                       regval);
+               return -EIO;
+       }
+
+       /* Mux shall be zeroed back before applying other configurations */
+       ret = i2c_smbus_write_byte_data(max9611->i2c_client,
+                                       MAX9611_REG_CTRL1, 0);
+       if (ret) {
+               dev_err(max9611->dev, "i2c write byte failed: 0x%2x - 0x%2x\n",
+                       MAX9611_REG_CTRL1, 0);
+               return ret;
+       }
+
+       ret = i2c_smbus_write_byte_data(max9611->i2c_client,
+                                       MAX9611_REG_CTRL2, 0);
+       if (ret) {
+               dev_err(max9611->dev, "i2c write byte failed: 0x%2x - 0x%2x\n",
+                       MAX9611_REG_CTRL2, 0);
+               return ret;
+       }
+       usleep_range(1000, 2000);
+
+       return 0;
+}
+
+static const struct of_device_id max9611_of_table[] = {
+       {.compatible = "maxim,max9611", .data = "max9611"},
+       {.compatible = "maxim,max9612", .data = "max9612"},
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, max9611_of_table);
+static int max9611_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       const char * const shunt_res_prop = "shunt-resistor-micro-ohms";
+       const struct device_node *of_node = client->dev.of_node;
+       const struct of_device_id *of_id =
+               of_match_device(max9611_of_table, &client->dev);
+       struct max9611_dev *max9611;
+       struct iio_dev *indio_dev;
+       unsigned int of_shunt;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*max9611));
+       if (IS_ERR(indio_dev))
+               return PTR_ERR(indio_dev);
+
+       i2c_set_clientdata(client, indio_dev);
+
+       max9611                 = iio_priv(indio_dev);
+       max9611->dev            = &client->dev;
+       max9611->i2c_client     = client;
+       mutex_init(&max9611->lock);
+
+       ret = of_property_read_u32(of_node, shunt_res_prop, &of_shunt);
+       if (ret) {
+               dev_err(&client->dev,
+                       "Missing %s property for %s node\n",
+                       shunt_res_prop, of_node->full_name);
+               return ret;
+       }
+       max9611->shunt_resistor_uohm = of_shunt;
+
+       ret = max9611_init(max9611);
+       if (ret)
+               return ret;
+
+       indio_dev->dev.parent   = &client->dev;
+       indio_dev->dev.of_node  = client->dev.of_node;
+       indio_dev->name         = of_id->data;
+       indio_dev->modes        = INDIO_DIRECT_MODE;
+       indio_dev->info         = &indio_info;
+       indio_dev->channels     = max9611_channels;
+       indio_dev->num_channels = ARRAY_SIZE(max9611_channels);
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static struct i2c_driver max9611_driver = {
+       .driver = {
+                  .name = DRIVER_NAME,
+                  .owner = THIS_MODULE,
+                  .of_match_table = max9611_of_table,
+       },
+       .probe = max9611_probe,
+};
+module_i2c_driver(max9611_driver);
+
+MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org>");
+MODULE_DESCRIPTION("Maxim max9611/12 current sense amplifier with 12bit ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c
new file mode 100644 (file)
index 0000000..cea8f1f
--- /dev/null
@@ -0,0 +1,1036 @@
+/*
+ * Qualcomm PM8xxx PMIC XOADC driver
+ *
+ * These ADCs are known as HK/XO (house keeping / chrystal oscillator)
+ * "XO" in "XOADC" means Chrystal Oscillator. It's a bunch of
+ * specific-purpose and general purpose ADC converters and channels.
+ *
+ * Copyright (C) 2017 Linaro Ltd.
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+
+#include "qcom-vadc-common.h"
+
+/*
+ * Definitions for the "user processor" registers lifted from the v3.4
+ * Qualcomm tree. Their kernel has two out-of-tree drivers for the ADC:
+ * drivers/misc/pmic8058-xoadc.c
+ * drivers/hwmon/pm8xxx-adc.c
+ * None of them contain any complete register specification, so this is
+ * a best effort of combining the information.
+ */
+
+/* These appear to be "battery monitor" registers */
+#define ADC_ARB_BTM_CNTRL1                     0x17e
+#define ADC_ARB_BTM_CNTRL1_EN_BTM              BIT(0)
+#define ADC_ARB_BTM_CNTRL1_SEL_OP_MODE         BIT(1)
+#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1      BIT(2)
+#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2      BIT(3)
+#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3      BIT(4)
+#define ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4      BIT(5)
+#define ADC_ARB_BTM_CNTRL1_EOC                 BIT(6)
+#define ADC_ARB_BTM_CNTRL1_REQ                 BIT(7)
+
+#define ADC_ARB_BTM_AMUX_CNTRL                 0x17f
+#define ADC_ARB_BTM_ANA_PARAM                  0x180
+#define ADC_ARB_BTM_DIG_PARAM                  0x181
+#define ADC_ARB_BTM_RSV                                0x182
+#define ADC_ARB_BTM_DATA1                      0x183
+#define ADC_ARB_BTM_DATA0                      0x184
+#define ADC_ARB_BTM_BAT_COOL_THR1              0x185
+#define ADC_ARB_BTM_BAT_COOL_THR0              0x186
+#define ADC_ARB_BTM_BAT_WARM_THR1              0x187
+#define ADC_ARB_BTM_BAT_WARM_THR0              0x188
+#define ADC_ARB_BTM_CNTRL2                     0x18c
+
+/* Proper ADC registers */
+
+#define ADC_ARB_USRP_CNTRL                     0x197
+#define ADC_ARB_USRP_CNTRL_EN_ARB              BIT(0)
+#define ADC_ARB_USRP_CNTRL_RSV1                        BIT(1)
+#define ADC_ARB_USRP_CNTRL_RSV2                        BIT(2)
+#define ADC_ARB_USRP_CNTRL_RSV3                        BIT(3)
+#define ADC_ARB_USRP_CNTRL_RSV4                        BIT(4)
+#define ADC_ARB_USRP_CNTRL_RSV5                        BIT(5)
+#define ADC_ARB_USRP_CNTRL_EOC                 BIT(6)
+#define ADC_ARB_USRP_CNTRL_REQ                 BIT(7)
+
+#define ADC_ARB_USRP_AMUX_CNTRL                        0x198
+/*
+ * The channel mask includes the bits selecting channel mux and prescaler
+ * on PM8058, or channel mux and premux on PM8921.
+ */
+#define ADC_ARB_USRP_AMUX_CNTRL_CHAN_MASK      0xfc
+#define ADC_ARB_USRP_AMUX_CNTRL_RSV0           BIT(0)
+#define ADC_ARB_USRP_AMUX_CNTRL_RSV1           BIT(1)
+/* On PM8058 this is prescaling, on PM8921 this is premux */
+#define ADC_ARB_USRP_AMUX_CNTRL_PRESCALEMUX0   BIT(2)
+#define ADC_ARB_USRP_AMUX_CNTRL_PRESCALEMUX1   BIT(3)
+#define ADC_ARB_USRP_AMUX_CNTRL_SEL0           BIT(4)
+#define ADC_ARB_USRP_AMUX_CNTRL_SEL1           BIT(5)
+#define ADC_ARB_USRP_AMUX_CNTRL_SEL2           BIT(6)
+#define ADC_ARB_USRP_AMUX_CNTRL_SEL3           BIT(7)
+#define ADC_AMUX_PREMUX_SHIFT                  2
+#define ADC_AMUX_SEL_SHIFT                     4
+
+/* We know very little about the bits in this register */
+#define ADC_ARB_USRP_ANA_PARAM                 0x199
+#define ADC_ARB_USRP_ANA_PARAM_DIS             0xFE
+#define ADC_ARB_USRP_ANA_PARAM_EN              0xFF
+
+#define ADC_ARB_USRP_DIG_PARAM                 0x19A
+#define ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0      BIT(0)
+#define ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1      BIT(1)
+#define ADC_ARB_USRP_DIG_PARAM_CLK_RATE0       BIT(2)
+#define ADC_ARB_USRP_DIG_PARAM_CLK_RATE1       BIT(3)
+#define ADC_ARB_USRP_DIG_PARAM_EOC             BIT(4)
+/*
+ * On a later ADC the decimation factors are defined as
+ * 00 = 512, 01 = 1024, 10 = 2048, 11 = 4096 so assume this
+ * holds also for this older XOADC.
+ */
+#define ADC_ARB_USRP_DIG_PARAM_DEC_RATE0       BIT(5)
+#define ADC_ARB_USRP_DIG_PARAM_DEC_RATE1       BIT(6)
+#define ADC_ARB_USRP_DIG_PARAM_EN              BIT(7)
+#define ADC_DIG_PARAM_DEC_SHIFT                        5
+
+#define ADC_ARB_USRP_RSV                       0x19B
+#define ADC_ARB_USRP_RSV_RST                   BIT(0)
+#define ADC_ARB_USRP_RSV_DTEST0                        BIT(1)
+#define ADC_ARB_USRP_RSV_DTEST1                        BIT(2)
+#define ADC_ARB_USRP_RSV_OP                    BIT(3)
+#define ADC_ARB_USRP_RSV_IP_SEL0               BIT(4)
+#define ADC_ARB_USRP_RSV_IP_SEL1               BIT(5)
+#define ADC_ARB_USRP_RSV_IP_SEL2               BIT(6)
+#define ADC_ARB_USRP_RSV_TRM                   BIT(7)
+#define ADC_RSV_IP_SEL_SHIFT                   4
+
+#define ADC_ARB_USRP_DATA0                     0x19D
+#define ADC_ARB_USRP_DATA1                     0x19C
+
+/**
+ * Physical channels which MUST exist on all PM variants in order to provide
+ * proper reference points for calibration.
+ *
+ * @PM8XXX_CHANNEL_INTERNAL: 625mV reference channel
+ * @PM8XXX_CHANNEL_125V: 1250mV reference channel
+ * @PM8XXX_CHANNEL_INTERNAL_2: 325mV reference channel
+ * @PM8XXX_CHANNEL_MUXOFF: channel to reduce input load on mux, apparently also
+ * measures XO temperature
+ */
+#define PM8XXX_CHANNEL_INTERNAL                0x0c
+#define PM8XXX_CHANNEL_125V            0x0d
+#define PM8XXX_CHANNEL_INTERNAL_2      0x0e
+#define PM8XXX_CHANNEL_MUXOFF          0x0f
+
+/*
+ * PM8058 AMUX premux scaling, two bits. This is done of the channel before
+ * reaching the AMUX.
+ */
+#define PM8058_AMUX_PRESCALE_0 0x0 /* No scaling on the signal */
+#define PM8058_AMUX_PRESCALE_1 0x1 /* Unity scaling selected by the user */
+#define PM8058_AMUX_PRESCALE_1_DIV3 0x2 /* 1/3 prescaler on the input */
+
+/* Defines reference voltage for the XOADC */
+#define AMUX_RSV0 0x0 /* XO_IN/XOADC_GND, special selection to read XO temp */
+#define AMUX_RSV1 0x1 /* PMIC_IN/XOADC_GND */
+#define AMUX_RSV2 0x2 /* PMIC_IN/BMS_CSP */
+#define AMUX_RSV3 0x3 /* not used */
+#define AMUX_RSV4 0x4 /* XOADC_GND/XOADC_GND */
+#define AMUX_RSV5 0x5 /* XOADC_VREF/XOADC_GND */
+#define XOADC_RSV_MAX 5 /* 3 bits 0..7, 3 and 6,7 are invalid */
+
+/**
+ * struct xoadc_channel - encodes channel properties and defaults
+ * @datasheet_name: the hardwarename of this channel
+ * @pre_scale_mux: prescale (PM8058) or premux (PM8921) for selecting
+ * this channel. Both this and the amux channel is needed to uniquely
+ * identify a channel. Values 0..3.
+ * @amux_channel: value of the ADC_ARB_USRP_AMUX_CNTRL register for this
+ * channel, bits 4..7, selects the amux, values 0..f
+ * @prescale: the channels have hard-coded prescale ratios defined
+ * by the hardware, this tells us what it is
+ * @type: corresponding IIO channel type, usually IIO_VOLTAGE or
+ * IIO_TEMP
+ * @scale_fn_type: the liner interpolation etc to convert the
+ * ADC code to the value that IIO expects, in uV or millicelsius
+ * etc. This scale function can be pretty elaborate if different
+ * thermistors are connected or other hardware characteristics are
+ * deployed.
+ * @amux_ip_rsv: ratiometric scale value used by the analog muxer: this
+ * selects the reference voltage for ratiometric scaling
+ */
+struct xoadc_channel {
+       const char *datasheet_name;
+       u8 pre_scale_mux:2;
+       u8 amux_channel:4;
+       const struct vadc_prescale_ratio prescale;
+       enum iio_chan_type type;
+       enum vadc_scale_fn_type scale_fn_type;
+       u8 amux_ip_rsv:3;
+};
+
+/**
+ * struct xoadc_variant - encodes the XOADC variant characteristics
+ * @name: name of this PMIC variant
+ * @channels: the hardware channels and respective settings and defaults
+ * @broken_ratiometric: if the PMIC has broken ratiometric scaling (this
+ * is a known problem on PM8058)
+ * @prescaling: this variant uses AMUX bits 2 & 3 for prescaling (PM8058)
+ * @second_level_mux: this variant uses AMUX bits 2 & 3 for a second level
+ * mux
+ */
+struct xoadc_variant {
+       const char name[16];
+       const struct xoadc_channel *channels;
+       bool broken_ratiometric;
+       bool prescaling;
+       bool second_level_mux;
+};
+
+/*
+ * XOADC_CHAN macro parameters:
+ * _dname: the name of the channel
+ * _presmux: prescaler (PM8058) or premux (PM8921) setting for this channel
+ * _amux: the value in bits 2..7 of the ADC_ARB_USRP_AMUX_CNTRL register
+ * for this channel. On some PMICs some of the bits select a prescaler, and
+ * on some PMICs some of the bits select various complex multiplex settings.
+ * _type: IIO channel type
+ * _prenum: prescaler numerator (dividend)
+ * _preden: prescaler denominator (divisor)
+ * _scale: scaling function type, this selects how the raw valued is mangled
+ * to output the actual processed measurement
+ * _amip: analog mux input parent when using ratiometric measurements
+ */
+#define XOADC_CHAN(_dname, _presmux, _amux, _type, _prenum, _preden, _scale, _amip) \
+       {                                                               \
+               .datasheet_name = __stringify(_dname),                  \
+               .pre_scale_mux = _presmux,                              \
+               .amux_channel = _amux,                                  \
+               .prescale = { .num = _prenum, .den = _preden },         \
+               .type = _type,                                          \
+               .scale_fn_type = _scale,                                \
+               .amux_ip_rsv = _amip,                                   \
+       }
+
+/*
+ * Taken from arch/arm/mach-msm/board-9615.c in the vendor tree:
+ * TODO: incomplete, needs testing.
+ */
+static const struct xoadc_channel pm8018_xoadc_channels[] = {
+       XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VPH_PWR, 0x00, 0x02, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1),
+       /* Used for battery ID or battery temperature */
+       XOADC_CHAN(AMUX8, 0x00, 0x08, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV2),
+       XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0),
+       { }, /* Sentinel */
+};
+
+/*
+ * Taken from arch/arm/mach-msm/board-8930-pmic.c in the vendor tree:
+ * TODO: needs testing.
+ */
+static const struct xoadc_channel pm8038_xoadc_channels[] = {
+       XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DCIN, 0x00, 0x02, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ICHG, 0x00, 0x03, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VPH_PWR, 0x00, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX5, 0x00, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX6, 0x00, 0x06, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX7, 0x00, 0x07, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       /* AMUX8 used for battery temperature in most cases */
+       XOADC_CHAN(AMUX8, 0x00, 0x08, IIO_TEMP, 1, 1, SCALE_THERM_100K_PULLUP, AMUX_RSV2),
+       XOADC_CHAN(AMUX9, 0x00, 0x09, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(USB_VBUS, 0x00, 0x0a, IIO_VOLTAGE, 1, 4, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1),
+       XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(INTERNAL_2, 0x00, 0x0e, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0),
+       { }, /* Sentinel */
+};
+
+/*
+ * This was created by cross-referencing the vendor tree
+ * arch/arm/mach-msm/board-msm8x60.c msm_adc_channels_data[]
+ * with the "channel types" (first field) to find the right
+ * configuration for these channels on an MSM8x60 i.e. PM8058
+ * setup.
+ */
+static const struct xoadc_channel pm8058_xoadc_channels[] = {
+       XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DCIN, 0x00, 0x02, IIO_VOLTAGE, 1, 10, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ICHG, 0x00, 0x03, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VPH_PWR, 0x00, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       /*
+        * AMUX channels 5 thru 9 are referred to as MPP5 thru MPP9 in
+        * some code and documentation. But they are really just 5
+        * channels just like any other. They are connected to a switching
+        * matrix where they can be routed to any of the MPPs, not just
+        * 1-to-1 onto MPP5 thru 9, so naming them MPP5 thru MPP9 is
+        * very confusing.
+        */
+       XOADC_CHAN(AMUX5, 0x00, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX6, 0x00, 0x06, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX7, 0x00, 0x07, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX8, 0x00, 0x08, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX9, 0x00, 0x09, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(USB_VBUS, 0x00, 0x0a, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1),
+       XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(INTERNAL_2, 0x00, 0x0e, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0),
+       /* There are also "unity" and divided by 3 channels (prescaler) but noone is using them */
+       { }, /* Sentinel */
+};
+
+/*
+ * The PM8921 has some pre-muxing on its channels, this comes from the vendor tree
+ * include/linux/mfd/pm8xxx/pm8xxx-adc.h
+ * board-flo-pmic.c (Nexus 7) and board-8064-pmic.c
+ */
+static const struct xoadc_channel pm8921_xoadc_channels[] = {
+       XOADC_CHAN(VCOIN, 0x00, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(VBAT, 0x00, 0x01, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DCIN, 0x00, 0x02, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1),
+       /* channel "ICHG" is reserved and not used on PM8921 */
+       XOADC_CHAN(VPH_PWR, 0x00, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(IBAT, 0x00, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       /* CHAN 6 & 7 (MPP1 & MPP2) are reserved for MPP channels on PM8921 */
+       XOADC_CHAN(BATT_THERM, 0x00, 0x08, IIO_TEMP, 1, 1, SCALE_THERM_100K_PULLUP, AMUX_RSV1),
+       XOADC_CHAN(BATT_ID, 0x00, 0x09, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(USB_VBUS, 0x00, 0x0a, IIO_VOLTAGE, 1, 4, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DIE_TEMP, 0x00, 0x0b, IIO_TEMP, 1, 1, SCALE_PMIC_THERM, AMUX_RSV1),
+       XOADC_CHAN(INTERNAL, 0x00, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(125V, 0x00, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       /* FIXME: look into the scaling of this temperature */
+       XOADC_CHAN(CHG_TEMP, 0x00, 0x0e, IIO_TEMP, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(MUXOFF, 0x00, 0x0f, IIO_TEMP, 1, 1, SCALE_XOTHERM, AMUX_RSV0),
+       /* The following channels have premux bit 0 set to 1 (all end in 4) */
+       XOADC_CHAN(ATEST_8, 0x01, 0x00, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       /* Set scaling to 1/2 based on the name for these two */
+       XOADC_CHAN(USB_SNS_DIV20, 0x01, 0x01, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DCIN_SNS_DIV20, 0x01, 0x02, IIO_VOLTAGE, 1, 2, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX3, 0x01, 0x03, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX4, 0x01, 0x04, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX5, 0x01, 0x05, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX6, 0x01, 0x06, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX7, 0x01, 0x07, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX8, 0x01, 0x08, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       /* Internal test signals, I think */
+       XOADC_CHAN(ATEST_1, 0x01, 0x09, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_2, 0x01, 0x0a, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_3, 0x01, 0x0b, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_4, 0x01, 0x0c, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_5, 0x01, 0x0d, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_6, 0x01, 0x0e, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_7, 0x01, 0x0f, IIO_VOLTAGE, 1, 1, SCALE_DEFAULT, AMUX_RSV1),
+       /* The following channels have premux bit 1 set to 1 (all end in 8) */
+       /* I guess even ATEST8 will be divided by 3 here */
+       XOADC_CHAN(ATEST_8, 0x02, 0x00, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       /* I guess div 2 div 3 becomes div 6 */
+       XOADC_CHAN(USB_SNS_DIV20_DIV3, 0x02, 0x01, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(DCIN_SNS_DIV20_DIV3, 0x02, 0x02, IIO_VOLTAGE, 1, 6, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX3_DIV3, 0x02, 0x03, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX4_DIV3, 0x02, 0x04, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX5_DIV3, 0x02, 0x05, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX6_DIV3, 0x02, 0x06, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX7_DIV3, 0x02, 0x07, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(AMUX8_DIV3, 0x02, 0x08, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_1_DIV3, 0x02, 0x09, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_2_DIV3, 0x02, 0x0a, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_3_DIV3, 0x02, 0x0b, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_4_DIV3, 0x02, 0x0c, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_5_DIV3, 0x02, 0x0d, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_6_DIV3, 0x02, 0x0e, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       XOADC_CHAN(ATEST_7_DIV3, 0x02, 0x0f, IIO_VOLTAGE, 1, 3, SCALE_DEFAULT, AMUX_RSV1),
+       { }, /* Sentinel */
+};
+
+/**
+ * struct pm8xxx_chan_info - ADC channel information
+ * @name: name of this channel
+ * @hwchan: pointer to hardware channel information (muxing & scaling settings)
+ * @calibration: whether to use absolute or ratiometric calibration
+ * @scale_fn_type: scaling function type
+ * @decimation: 0,1,2,3
+ * @amux_ip_rsv: ratiometric scale value if using ratiometric
+ * calibration: 0, 1, 2, 4, 5.
+ */
+struct pm8xxx_chan_info {
+       const char *name;
+       const struct xoadc_channel *hwchan;
+       enum vadc_calibration calibration;
+       u8 decimation:2;
+       u8 amux_ip_rsv:3;
+};
+
+/**
+ * struct pm8xxx_xoadc - state container for the XOADC
+ * @dev: pointer to device
+ * @map: regmap to access registers
+ * @vref: reference voltage regulator
+ * characteristics of the channels, and sensible default settings
+ * @nchans: number of channels, configured by the device tree
+ * @chans: the channel information per-channel, configured by the device tree
+ * @iio_chans: IIO channel specifiers
+ * @graph: linear calibration parameters for absolute and
+ * ratiometric measurements
+ * @complete: completion to indicate end of conversion
+ * @lock: lock to restrict access to the hardware to one client at the time
+ */
+struct pm8xxx_xoadc {
+       struct device *dev;
+       struct regmap *map;
+       const struct xoadc_variant *variant;
+       struct regulator *vref;
+       unsigned int nchans;
+       struct pm8xxx_chan_info *chans;
+       struct iio_chan_spec *iio_chans;
+       struct vadc_linear_graph graph[2];
+       struct completion complete;
+       struct mutex lock;
+};
+
+static irqreturn_t pm8xxx_eoc_irq(int irq, void *d)
+{
+       struct iio_dev *indio_dev = d;
+       struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
+
+       complete(&adc->complete);
+
+       return IRQ_HANDLED;
+}
+
+static struct pm8xxx_chan_info *
+pm8xxx_get_channel(struct pm8xxx_xoadc *adc, u8 chan)
+{
+       struct pm8xxx_chan_info *ch;
+       int i;
+
+       for (i = 0; i < adc->nchans; i++) {
+               ch = &adc->chans[i];
+               if (ch->hwchan->amux_channel == chan)
+                       break;
+       }
+       if (i == adc->nchans)
+               return NULL;
+
+       return ch;
+}
+
+static int pm8xxx_read_channel_rsv(struct pm8xxx_xoadc *adc,
+                                  const struct pm8xxx_chan_info *ch,
+                                  u8 rsv, u16 *adc_code,
+                                  bool force_ratiometric)
+{
+       int ret;
+       unsigned int val;
+       u8 rsvmask, rsvval;
+       u8 lsb, msb;
+
+       dev_dbg(adc->dev, "read channel \"%s\", amux %d, prescale/mux: %d, rsv %d\n",
+               ch->name, ch->hwchan->amux_channel, ch->hwchan->pre_scale_mux, rsv);
+
+       mutex_lock(&adc->lock);
+
+       /* Mux in this channel */
+       val = ch->hwchan->amux_channel << ADC_AMUX_SEL_SHIFT;
+       val |= ch->hwchan->pre_scale_mux << ADC_AMUX_PREMUX_SHIFT;
+       ret = regmap_write(adc->map, ADC_ARB_USRP_AMUX_CNTRL, val);
+       if (ret)
+               goto unlock;
+
+       /* Set up ratiometric scale value, mask off all bits except these */
+       rsvmask = (ADC_ARB_USRP_RSV_RST | ADC_ARB_USRP_RSV_DTEST0 |
+                  ADC_ARB_USRP_RSV_DTEST1 | ADC_ARB_USRP_RSV_OP);
+       if (adc->variant->broken_ratiometric && !force_ratiometric) {
+               /*
+                * Apparently the PM8058 has some kind of bug which is
+                * reflected in the vendor tree drivers/misc/pmix8058-xoadc.c
+                * which just hardcodes the RSV selector to SEL1 (0x20) for
+                * most cases and SEL0 (0x10) for the MUXOFF channel only.
+                * If we force ratiometric (currently only done when attempting
+                * to do ratiometric calibration) this doesn't seem to work
+                * very well and I suspect ratiometric conversion is simply
+                * broken or not supported on the PM8058.
+                *
+                * Maybe IO_SEL2 doesn't exist on PM8058 and bits 4 & 5 select
+                * the mode alone.
+                *
+                * Some PM8058 register documentation would be nice to get
+                * this right.
+                */
+               if (ch->hwchan->amux_channel == PM8XXX_CHANNEL_MUXOFF)
+                       rsvval = ADC_ARB_USRP_RSV_IP_SEL0;
+               else
+                       rsvval = ADC_ARB_USRP_RSV_IP_SEL1;
+       } else {
+               if (rsv == 0xff)
+                       rsvval = (ch->amux_ip_rsv << ADC_RSV_IP_SEL_SHIFT) |
+                               ADC_ARB_USRP_RSV_TRM;
+               else
+                       rsvval = (rsv << ADC_RSV_IP_SEL_SHIFT) |
+                               ADC_ARB_USRP_RSV_TRM;
+       }
+
+       ret = regmap_update_bits(adc->map,
+                                ADC_ARB_USRP_RSV,
+                                ~rsvmask,
+                                rsvval);
+       if (ret)
+               goto unlock;
+
+       ret = regmap_write(adc->map, ADC_ARB_USRP_ANA_PARAM,
+                          ADC_ARB_USRP_ANA_PARAM_DIS);
+       if (ret)
+               goto unlock;
+
+       /* Decimation factor */
+       ret = regmap_write(adc->map, ADC_ARB_USRP_DIG_PARAM,
+                          ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 |
+                          ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 |
+                          ch->decimation << ADC_DIG_PARAM_DEC_SHIFT);
+       if (ret)
+               goto unlock;
+
+       ret = regmap_write(adc->map, ADC_ARB_USRP_ANA_PARAM,
+                          ADC_ARB_USRP_ANA_PARAM_EN);
+       if (ret)
+               goto unlock;
+
+       /* Enable the arbiter, the Qualcomm code does it twice like this */
+       ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL,
+                          ADC_ARB_USRP_CNTRL_EN_ARB);
+       if (ret)
+               goto unlock;
+       ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL,
+                          ADC_ARB_USRP_CNTRL_EN_ARB);
+       if (ret)
+               goto unlock;
+
+
+       /* Fire a request! */
+       reinit_completion(&adc->complete);
+       ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL,
+                          ADC_ARB_USRP_CNTRL_EN_ARB |
+                          ADC_ARB_USRP_CNTRL_REQ);
+       if (ret)
+               goto unlock;
+
+       /* Next the interrupt occurs */
+       ret = wait_for_completion_timeout(&adc->complete,
+                                         VADC_CONV_TIME_MAX_US);
+       if (!ret) {
+               dev_err(adc->dev, "conversion timed out\n");
+               ret = -ETIMEDOUT;
+               goto unlock;
+       }
+
+       ret = regmap_read(adc->map, ADC_ARB_USRP_DATA0, &val);
+       if (ret)
+               goto unlock;
+       lsb = val;
+       ret = regmap_read(adc->map, ADC_ARB_USRP_DATA1, &val);
+       if (ret)
+               goto unlock;
+       msb = val;
+       *adc_code = (msb << 8) | lsb;
+
+       /* Turn off the ADC by setting the arbiter to 0 twice */
+       ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 0);
+       if (ret)
+               goto unlock;
+       ret = regmap_write(adc->map, ADC_ARB_USRP_CNTRL, 0);
+       if (ret)
+               goto unlock;
+
+unlock:
+       mutex_unlock(&adc->lock);
+       return ret;
+}
+
+static int pm8xxx_read_channel(struct pm8xxx_xoadc *adc,
+                              const struct pm8xxx_chan_info *ch,
+                              u16 *adc_code)
+{
+       /*
+        * Normally we just use the ratiometric scale value (RSV) predefined
+        * for the channel, but during calibration we need to modify this
+        * so this wrapper is a helper hiding the more complex version.
+        */
+       return pm8xxx_read_channel_rsv(adc, ch, 0xff, adc_code, false);
+}
+
+static int pm8xxx_calibrate_device(struct pm8xxx_xoadc *adc)
+{
+       const struct pm8xxx_chan_info *ch;
+       u16 read_1250v;
+       u16 read_0625v;
+       u16 read_nomux_rsv5;
+       u16 read_nomux_rsv4;
+       int ret;
+
+       adc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV;
+       adc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE;
+
+       /* Common reference channel calibration */
+       ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_125V);
+       if (!ch)
+               return -ENODEV;
+       ret = pm8xxx_read_channel(adc, ch, &read_1250v);
+       if (ret) {
+               dev_err(adc->dev, "could not read 1.25V reference channel\n");
+               return -ENODEV;
+       }
+       ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_INTERNAL);
+       if (!ch)
+               return -ENODEV;
+       ret = pm8xxx_read_channel(adc, ch, &read_0625v);
+       if (ret) {
+               dev_err(adc->dev, "could not read 0.625V reference channel\n");
+               return -ENODEV;
+       }
+       if (read_1250v == read_0625v) {
+               dev_err(adc->dev, "read same ADC code for 1.25V and 0.625V\n");
+               return -ENODEV;
+       }
+
+       adc->graph[VADC_CALIB_ABSOLUTE].dy = read_1250v - read_0625v;
+       adc->graph[VADC_CALIB_ABSOLUTE].gnd = read_0625v;
+
+       dev_info(adc->dev, "absolute calibration dx = %d uV, dy = %d units\n",
+                VADC_ABSOLUTE_RANGE_UV, adc->graph[VADC_CALIB_ABSOLUTE].dy);
+
+       /* Ratiometric calibration */
+       ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_MUXOFF);
+       if (!ch)
+               return -ENODEV;
+       ret = pm8xxx_read_channel_rsv(adc, ch, AMUX_RSV5,
+                                     &read_nomux_rsv5, true);
+       if (ret) {
+               dev_err(adc->dev, "could not read MUXOFF reference channel\n");
+               return -ENODEV;
+       }
+       ret = pm8xxx_read_channel_rsv(adc, ch, AMUX_RSV4,
+                                     &read_nomux_rsv4, true);
+       if (ret) {
+               dev_err(adc->dev, "could not read MUXOFF reference channel\n");
+               return -ENODEV;
+       }
+       adc->graph[VADC_CALIB_RATIOMETRIC].dy =
+               read_nomux_rsv5 - read_nomux_rsv4;
+       adc->graph[VADC_CALIB_RATIOMETRIC].gnd = read_nomux_rsv4;
+
+       dev_info(adc->dev, "ratiometric calibration dx = %d, dy = %d units\n",
+                VADC_RATIOMETRIC_RANGE,
+                adc->graph[VADC_CALIB_RATIOMETRIC].dy);
+
+       return 0;
+}
+
+static int pm8xxx_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
+       const struct pm8xxx_chan_info *ch;
+       u16 adc_code;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               ch = pm8xxx_get_channel(adc, chan->address);
+               if (!ch) {
+                       dev_err(adc->dev, "no such channel %lu\n",
+                               chan->address);
+                       return -EINVAL;
+               }
+               ret = pm8xxx_read_channel(adc, ch, &adc_code);
+               if (ret)
+                       return ret;
+
+               ret = qcom_vadc_scale(ch->hwchan->scale_fn_type,
+                                     &adc->graph[ch->calibration],
+                                     &ch->hwchan->prescale,
+                                     (ch->calibration == VADC_CALIB_ABSOLUTE),
+                                     adc_code, val);
+               if (ret)
+                       return ret;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_RAW:
+               ch = pm8xxx_get_channel(adc, chan->address);
+               if (!ch) {
+                       dev_err(adc->dev, "no such channel %lu\n",
+                               chan->address);
+                       return -EINVAL;
+               }
+               ret = pm8xxx_read_channel(adc, ch, &adc_code);
+               if (ret)
+                       return ret;
+
+               *val = (int)adc_code;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
+                          const struct of_phandle_args *iiospec)
+{
+       struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
+       u8 pre_scale_mux;
+       u8 amux_channel;
+       unsigned int i;
+
+       /*
+        * First cell is prescaler or premux, second cell is analog
+        * 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,
+                       iiospec->args_count);
+               return -EINVAL;
+       }
+       pre_scale_mux = (u8)iiospec->args[0];
+       amux_channel = (u8)iiospec->args[1];
+       dev_dbg(&indio_dev->dev, "pre scale/mux: %02x, amux: %02x\n",
+               pre_scale_mux, amux_channel);
+
+       /* We need to match exactly on the prescale/premux and channel */
+       for (i = 0; i < adc->nchans; i++)
+               if (adc->chans[i].hwchan->pre_scale_mux == pre_scale_mux &&
+                   adc->chans[i].hwchan->amux_channel == amux_channel)
+                       return i;
+
+       return -EINVAL;
+}
+
+static const struct iio_info pm8xxx_xoadc_info = {
+       .driver_module = THIS_MODULE,
+       .of_xlate = pm8xxx_of_xlate,
+       .read_raw = pm8xxx_read_raw,
+};
+
+static int pm8xxx_xoadc_parse_channel(struct device *dev,
+                                     struct device_node *np,
+                                     const struct xoadc_channel *hw_channels,
+                                     struct iio_chan_spec *iio_chan,
+                                     struct pm8xxx_chan_info *ch)
+{
+       const char *name = np->name;
+       const struct xoadc_channel *hwchan;
+       u32 pre_scale_mux, amux_channel;
+       u32 rsv, dec;
+       int ret;
+       int chid;
+
+       ret = of_property_read_u32_index(np, "reg", 0, &pre_scale_mux);
+       if (ret) {
+               dev_err(dev, "invalid pre scale/mux number %s\n", name);
+               return ret;
+       }
+       ret = of_property_read_u32_index(np, "reg", 1, &amux_channel);
+       if (ret) {
+               dev_err(dev, "invalid amux channel number %s\n", name);
+               return ret;
+       }
+
+       /* Find the right channel setting */
+       chid = 0;
+       hwchan = &hw_channels[0];
+       while (hwchan && hwchan->datasheet_name) {
+               if (hwchan->pre_scale_mux == pre_scale_mux &&
+                   hwchan->amux_channel == amux_channel)
+                       break;
+               hwchan++;
+               chid++;
+       }
+       /* The sentinel does not have a name assigned */
+       if (!hwchan->datasheet_name) {
+               dev_err(dev, "could not locate channel %02x/%02x\n",
+                       pre_scale_mux, amux_channel);
+               return -EINVAL;
+       }
+       ch->name = name;
+       ch->hwchan = hwchan;
+       /* Everyone seems to use absolute calibration except in special cases */
+       ch->calibration = VADC_CALIB_ABSOLUTE;
+       /* Everyone seems to use default ("type 2") decimation */
+       ch->decimation = VADC_DEF_DECIMATION;
+
+       if (!of_property_read_u32(np, "qcom,ratiometric", &rsv)) {
+               ch->calibration = VADC_CALIB_RATIOMETRIC;
+               if (rsv > XOADC_RSV_MAX) {
+                       dev_err(dev, "%s too large RSV value %d\n", name, rsv);
+                       return -EINVAL;
+               }
+               if (rsv == AMUX_RSV3) {
+                       dev_err(dev, "%s invalid RSV value %d\n", name, rsv);
+                       return -EINVAL;
+               }
+       }
+
+       /* Optional decimation, if omitted we use the default */
+       ret = of_property_read_u32(np, "qcom,decimation", &dec);
+       if (!ret) {
+               ret = qcom_vadc_decimation_from_dt(dec);
+               if (ret < 0) {
+                       dev_err(dev, "%s invalid decimation %d\n",
+                               name, dec);
+                       return ret;
+               }
+               ch->decimation = ret;
+       }
+
+       iio_chan->channel = chid;
+       iio_chan->address = hwchan->amux_channel;
+       iio_chan->datasheet_name = hwchan->datasheet_name;
+       iio_chan->type = hwchan->type;
+       /* All channels are raw or processed */
+       iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+               BIT(IIO_CHAN_INFO_PROCESSED);
+       iio_chan->indexed = 1;
+
+       dev_dbg(dev, "channel [PRESCALE/MUX: %02x AMUX: %02x] \"%s\" "
+               "ref voltage: %d, decimation %d "
+               "prescale %d/%d, scale function %d\n",
+               hwchan->pre_scale_mux, hwchan->amux_channel, ch->name,
+               ch->amux_ip_rsv, ch->decimation, hwchan->prescale.num,
+               hwchan->prescale.den, hwchan->scale_fn_type);
+
+       return 0;
+}
+
+static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc,
+                                      struct device_node *np)
+{
+       struct device_node *child;
+       struct pm8xxx_chan_info *ch;
+       int ret;
+       int i;
+
+       adc->nchans = of_get_available_child_count(np);
+       if (!adc->nchans) {
+               dev_err(adc->dev, "no channel children\n");
+               return -ENODEV;
+       }
+       dev_dbg(adc->dev, "found %d ADC channels\n", adc->nchans);
+
+       adc->iio_chans = devm_kcalloc(adc->dev, adc->nchans,
+                                     sizeof(*adc->iio_chans), GFP_KERNEL);
+       if (!adc->iio_chans)
+               return -ENOMEM;
+
+       adc->chans = devm_kcalloc(adc->dev, adc->nchans,
+                                 sizeof(*adc->chans), GFP_KERNEL);
+       if (!adc->chans)
+               return -ENOMEM;
+
+       i = 0;
+       for_each_available_child_of_node(np, child) {
+               ch = &adc->chans[i];
+               ret = pm8xxx_xoadc_parse_channel(adc->dev, child,
+                                                adc->variant->channels,
+                                                &adc->iio_chans[i],
+                                                ch);
+               if (ret) {
+                       of_node_put(child);
+                       return ret;
+               }
+               i++;
+       }
+
+       /* Check for required channels */
+       ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_125V);
+       if (!ch) {
+               dev_err(adc->dev, "missing 1.25V reference channel\n");
+               return -ENODEV;
+       }
+       ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_INTERNAL);
+       if (!ch) {
+               dev_err(adc->dev, "missing 0.625V reference channel\n");
+               return -ENODEV;
+       }
+       ch = pm8xxx_get_channel(adc, PM8XXX_CHANNEL_MUXOFF);
+       if (!ch) {
+               dev_err(adc->dev, "missing MUXOFF reference channel\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int pm8xxx_xoadc_probe(struct platform_device *pdev)
+{
+       const struct xoadc_variant *variant;
+       struct pm8xxx_xoadc *adc;
+       struct iio_dev *indio_dev;
+       struct device_node *np = pdev->dev.of_node;
+       struct regmap *map;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       variant = of_device_get_match_data(dev);
+       if (!variant)
+               return -ENODEV;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
+       if (!indio_dev)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, indio_dev);
+
+       adc = iio_priv(indio_dev);
+       adc->dev = dev;
+       adc->variant = variant;
+       init_completion(&adc->complete);
+       mutex_init(&adc->lock);
+
+       ret = pm8xxx_xoadc_parse_channels(adc, np);
+       if (ret)
+               return ret;
+
+       map = dev_get_regmap(dev->parent, NULL);
+       if (!map) {
+               dev_err(dev, "parent regmap unavailable.\n");
+               return -ENXIO;
+       }
+       adc->map = map;
+
+       /* Bring up regulator */
+       adc->vref = devm_regulator_get(dev, "xoadc-ref");
+       if (IS_ERR(adc->vref)) {
+               dev_err(dev, "failed to get XOADC VREF regulator\n");
+               return PTR_ERR(adc->vref);
+       }
+       ret = regulator_enable(adc->vref);
+       if (ret) {
+               dev_err(dev, "failed to enable XOADC VREF regulator\n");
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
+                       pm8xxx_eoc_irq, NULL, 0, variant->name, indio_dev);
+       if (ret) {
+               dev_err(dev, "unable to request IRQ\n");
+               goto out_disable_vref;
+       }
+
+       indio_dev->dev.parent = dev;
+       indio_dev->dev.of_node = np;
+       indio_dev->name = variant->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &pm8xxx_xoadc_info;
+       indio_dev->channels = adc->iio_chans;
+       indio_dev->num_channels = adc->nchans;
+
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto out_disable_vref;
+
+       ret = pm8xxx_calibrate_device(adc);
+       if (ret)
+               goto out_unreg_device;
+
+       dev_info(dev, "%s XOADC driver enabled\n", variant->name);
+
+       return 0;
+
+out_unreg_device:
+       iio_device_unregister(indio_dev);
+out_disable_vref:
+       regulator_disable(adc->vref);
+
+       return ret;
+}
+
+static int pm8xxx_xoadc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       regulator_disable(adc->vref);
+
+       return 0;
+}
+
+static const struct xoadc_variant pm8018_variant = {
+       .name = "PM8018-XOADC",
+       .channels = pm8018_xoadc_channels,
+};
+
+static const struct xoadc_variant pm8038_variant = {
+       .name = "PM8038-XOADC",
+       .channels = pm8038_xoadc_channels,
+};
+
+static const struct xoadc_variant pm8058_variant = {
+       .name = "PM8058-XOADC",
+       .channels = pm8058_xoadc_channels,
+       .broken_ratiometric = true,
+       .prescaling = true,
+};
+
+static const struct xoadc_variant pm8921_variant = {
+       .name = "PM8921-XOADC",
+       .channels = pm8921_xoadc_channels,
+       .second_level_mux = true,
+};
+
+static const struct of_device_id pm8xxx_xoadc_id_table[] = {
+       {
+               .compatible = "qcom,pm8018-adc",
+               .data = &pm8018_variant,
+       },
+       {
+               .compatible = "qcom,pm8038-adc",
+               .data = &pm8038_variant,
+       },
+       {
+               .compatible = "qcom,pm8058-adc",
+               .data = &pm8058_variant,
+       },
+       {
+               .compatible = "qcom,pm8921-adc",
+               .data = &pm8921_variant,
+       },
+       { },
+};
+MODULE_DEVICE_TABLE(of, pm8xxx_xoadc_id_table);
+
+static struct platform_driver pm8xxx_xoadc_driver = {
+       .driver         = {
+               .name   = "pm8xxx-adc",
+               .of_match_table = pm8xxx_xoadc_id_table,
+       },
+       .probe          = pm8xxx_xoadc_probe,
+       .remove         = pm8xxx_xoadc_remove,
+};
+module_platform_driver(pm8xxx_xoadc_driver);
+
+MODULE_DESCRIPTION("PM8xxx XOADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:pm8xxx-xoadc");
index 0a19761d656c66ab8ae87d871556f1f4f13f4884..9e600bfd17652531f50bd7019854f53749e9b822 100644 (file)
@@ -28,6 +28,8 @@
 
 #include <dt-bindings/iio/qcom,spmi-vadc.h>
 
+#include "qcom-vadc-common.h"
+
 /* VADC register and bit definitions */
 #define VADC_REVISION2                         0x1
 #define VADC_REVISION2_SUPPORTED_VADC          1
 
 #define VADC_DATA                              0x60    /* 16 bits */
 
-#define VADC_CONV_TIME_MIN_US                  2000
-#define VADC_CONV_TIME_MAX_US                  2100
-
-/* Min ADC code represents 0V */
-#define VADC_MIN_ADC_CODE                      0x6000
-/* Max ADC code represents full-scale range of 1.8V */
-#define VADC_MAX_ADC_CODE                      0xa800
-
-#define VADC_ABSOLUTE_RANGE_UV                 625000
-#define VADC_RATIOMETRIC_RANGE                 1800
-
-#define VADC_DEF_PRESCALING                    0 /* 1:1 */
-#define VADC_DEF_DECIMATION                    0 /* 512 */
-#define VADC_DEF_HW_SETTLE_TIME                        0 /* 0 us */
-#define VADC_DEF_AVG_SAMPLES                   0 /* 1 sample */
-#define VADC_DEF_CALIB_TYPE                    VADC_CALIB_ABSOLUTE
-
-#define VADC_DECIMATION_MIN                    512
-#define VADC_DECIMATION_MAX                    4096
-
-#define VADC_HW_SETTLE_DELAY_MAX               10000
-#define VADC_AVG_SAMPLES_MAX                   512
-
-#define KELVINMIL_CELSIUSMIL                   273150
-
-#define PMI_CHG_SCALE_1                                -138890
-#define PMI_CHG_SCALE_2                                391750000000LL
-
 #define VADC_CHAN_MIN                  VADC_USBIN
 #define VADC_CHAN_MAX                  VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM
 
-/**
- * struct vadc_map_pt - Map the graph representation for ADC channel
- * @x: Represent the ADC digitized code.
- * @y: Represent the physical data which can be temperature, voltage,
- *     resistance.
- */
-struct vadc_map_pt {
-       s32 x;
-       s32 y;
-};
-
-/*
- * VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
- * VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
- * calibration.
- */
-enum vadc_calibration {
-       VADC_CALIB_ABSOLUTE = 0,
-       VADC_CALIB_RATIOMETRIC
-};
-
-/**
- * struct vadc_linear_graph - Represent ADC characteristics.
- * @dy: numerator slope to calculate the gain.
- * @dx: denominator slope to calculate the gain.
- * @gnd: A/D word of the ground reference used for the channel.
- *
- * Each ADC device has different offset and gain parameters which are
- * computed to calibrate the device.
- */
-struct vadc_linear_graph {
-       s32 dy;
-       s32 dx;
-       s32 gnd;
-};
-
-/**
- * struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
- * @num: the inverse numerator of the gain applied to the input channel.
- * @den: the inverse denominator of the gain applied to the input channel.
- */
-struct vadc_prescale_ratio {
-       u32 num;
-       u32 den;
-};
-
 /**
  * struct vadc_channel_prop - VADC channel property.
  * @channel: channel number, refer to the channel list.
@@ -162,9 +90,8 @@ struct vadc_prescale_ratio {
  *     start of conversion.
  * @avg_samples: ability to provide single result from the ADC
  *     that is an average of multiple measurements.
- * @scale_fn: Represents the scaling function to convert voltage
+ * @scale_fn_type: Represents the scaling function to convert voltage
  *     physical units desired by the client for the channel.
- *     Referenced from enum vadc_scale_fn_type.
  */
 struct vadc_channel_prop {
        unsigned int channel;
@@ -173,7 +100,7 @@ struct vadc_channel_prop {
        unsigned int prescale;
        unsigned int hw_settle_time;
        unsigned int avg_samples;
-       unsigned int scale_fn;
+       enum vadc_scale_fn_type scale_fn_type;
 };
 
 /**
@@ -204,35 +131,6 @@ struct vadc_priv {
        struct mutex             lock;
 };
 
-/**
- * struct vadc_scale_fn - Scaling function prototype
- * @scale: Function pointer to one of the scaling functions
- *     which takes the adc properties, channel properties,
- *     and returns the physical result.
- */
-struct vadc_scale_fn {
-       int (*scale)(struct vadc_priv *, const struct vadc_channel_prop *,
-                    u16, int *);
-};
-
-/**
- * enum vadc_scale_fn_type - Scaling function to convert ADC code to
- *                             physical scaled units for the channel.
- * SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
- * SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
- *                              Uses a mapping table with 100K pullup.
- * 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
- */
-enum vadc_scale_fn_type {
-       SCALE_DEFAULT = 0,
-       SCALE_THERM_100K_PULLUP,
-       SCALE_PMIC_THERM,
-       SCALE_XOTHERM,
-       SCALE_PMI_CHG_TEMP,
-};
-
 static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
        {.num =  1, .den =  1},
        {.num =  1, .den =  3},
@@ -244,44 +142,6 @@ static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
        {.num =  1, .den = 10}
 };
 
-/* Voltage to temperature */
-static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
-       {1758,  -40},
-       {1742,  -35},
-       {1719,  -30},
-       {1691,  -25},
-       {1654,  -20},
-       {1608,  -15},
-       {1551,  -10},
-       {1483,  -5},
-       {1404,  0},
-       {1315,  5},
-       {1218,  10},
-       {1114,  15},
-       {1007,  20},
-       {900,   25},
-       {795,   30},
-       {696,   35},
-       {605,   40},
-       {522,   45},
-       {448,   50},
-       {383,   55},
-       {327,   60},
-       {278,   65},
-       {237,   70},
-       {202,   75},
-       {172,   80},
-       {146,   85},
-       {125,   90},
-       {107,   95},
-       {92,    100},
-       {79,    105},
-       {68,    110},
-       {59,    115},
-       {51,    120},
-       {44,    125}
-};
-
 static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
 {
        return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1);
@@ -553,159 +413,6 @@ err:
        return ret;
 }
 
-static int vadc_map_voltage_temp(const struct vadc_map_pt *pts,
-                                u32 tablesize, s32 input, s64 *output)
-{
-       bool descending = 1;
-       u32 i = 0;
-
-       if (!pts)
-               return -EINVAL;
-
-       /* Check if table is descending or ascending */
-       if (tablesize > 1) {
-               if (pts[0].x < pts[1].x)
-                       descending = 0;
-       }
-
-       while (i < tablesize) {
-               if ((descending) && (pts[i].x < input)) {
-                       /* table entry is less than measured*/
-                        /* value and table is descending, stop */
-                       break;
-               } else if ((!descending) &&
-                               (pts[i].x > input)) {
-                       /* table entry is greater than measured*/
-                       /*value and table is ascending, stop */
-                       break;
-               }
-               i++;
-       }
-
-       if (i == 0) {
-               *output = pts[0].y;
-       } else if (i == tablesize) {
-               *output = pts[tablesize - 1].y;
-       } else {
-               /* result is between search_index and search_index-1 */
-               /* interpolate linearly */
-               *output = (((s32)((pts[i].y - pts[i - 1].y) *
-                       (input - pts[i - 1].x)) /
-                       (pts[i].x - pts[i - 1].x)) +
-                       pts[i - 1].y);
-       }
-
-       return 0;
-}
-
-static void vadc_scale_calib(struct vadc_priv *vadc, u16 adc_code,
-                            const struct vadc_channel_prop *prop,
-                            s64 *scale_voltage)
-{
-       *scale_voltage = (adc_code -
-               vadc->graph[prop->calibration].gnd);
-       *scale_voltage *= vadc->graph[prop->calibration].dx;
-       *scale_voltage = div64_s64(*scale_voltage,
-               vadc->graph[prop->calibration].dy);
-       if (prop->calibration == VADC_CALIB_ABSOLUTE)
-               *scale_voltage +=
-               vadc->graph[prop->calibration].dx;
-
-       if (*scale_voltage < 0)
-               *scale_voltage = 0;
-}
-
-static int vadc_scale_volt(struct vadc_priv *vadc,
-                          const struct vadc_channel_prop *prop, u16 adc_code,
-                          int *result_uv)
-{
-       const struct vadc_prescale_ratio *prescale;
-       s64 voltage = 0, result = 0;
-
-       vadc_scale_calib(vadc, adc_code, prop, &voltage);
-
-       prescale = &vadc_prescale_ratios[prop->prescale];
-       voltage = voltage * prescale->den;
-       result = div64_s64(voltage, prescale->num);
-       *result_uv = result;
-
-       return 0;
-}
-
-static int vadc_scale_therm(struct vadc_priv *vadc,
-                           const struct vadc_channel_prop *prop, u16 adc_code,
-                           int *result_mdec)
-{
-       s64 voltage = 0, result = 0;
-
-       vadc_scale_calib(vadc, adc_code, prop, &voltage);
-
-       if (prop->calibration == VADC_CALIB_ABSOLUTE)
-               voltage = div64_s64(voltage, 1000);
-
-       vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
-                             ARRAY_SIZE(adcmap_100k_104ef_104fb),
-                             voltage, &result);
-       result *= 1000;
-       *result_mdec = result;
-
-       return 0;
-}
-
-static int vadc_scale_die_temp(struct vadc_priv *vadc,
-                              const struct vadc_channel_prop *prop,
-                              u16 adc_code, int *result_mdec)
-{
-       const struct vadc_prescale_ratio *prescale;
-       s64 voltage = 0;
-       u64 temp; /* Temporary variable for do_div */
-
-       vadc_scale_calib(vadc, adc_code, prop, &voltage);
-
-       if (voltage > 0) {
-               prescale = &vadc_prescale_ratios[prop->prescale];
-               temp = voltage * prescale->den;
-               do_div(temp, prescale->num * 2);
-               voltage = temp;
-       } else {
-               voltage = 0;
-       }
-
-       voltage -= KELVINMIL_CELSIUSMIL;
-       *result_mdec = voltage;
-
-       return 0;
-}
-
-static int vadc_scale_chg_temp(struct vadc_priv *vadc,
-                              const struct vadc_channel_prop *prop,
-                              u16 adc_code, int *result_mdec)
-{
-       const struct vadc_prescale_ratio *prescale;
-       s64 voltage = 0, result = 0;
-
-       vadc_scale_calib(vadc, adc_code, prop, &voltage);
-
-       prescale = &vadc_prescale_ratios[prop->prescale];
-       voltage = voltage * prescale->den;
-       voltage = div64_s64(voltage, prescale->num);
-       voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
-       voltage = (voltage + PMI_CHG_SCALE_2);
-       result =  div64_s64(voltage, 1000000);
-       *result_mdec = result;
-
-       return 0;
-}
-
-static int vadc_decimation_from_dt(u32 value)
-{
-       if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
-           value > VADC_DECIMATION_MAX)
-               return -EINVAL;
-
-       return __ffs64(value / VADC_DECIMATION_MIN);
-}
-
 static int vadc_prescaling_from_dt(u32 num, u32 den)
 {
        unsigned int pre;
@@ -742,14 +449,6 @@ static int vadc_avg_samples_from_dt(u32 value)
        return __ffs64(value);
 }
 
-static struct vadc_scale_fn scale_fn[] = {
-       [SCALE_DEFAULT] = {vadc_scale_volt},
-       [SCALE_THERM_100K_PULLUP] = {vadc_scale_therm},
-       [SCALE_PMIC_THERM] = {vadc_scale_die_temp},
-       [SCALE_XOTHERM] = {vadc_scale_therm},
-       [SCALE_PMI_CHG_TEMP] = {vadc_scale_chg_temp},
-};
-
 static int vadc_read_raw(struct iio_dev *indio_dev,
                         struct iio_chan_spec const *chan, int *val, int *val2,
                         long mask)
@@ -766,7 +465,13 @@ static int vadc_read_raw(struct iio_dev *indio_dev,
                if (ret)
                        break;
 
-               scale_fn[prop->scale_fn].scale(vadc, prop, adc_code, val);
+               ret = qcom_vadc_scale(prop->scale_fn_type,
+                               &vadc->graph[prop->calibration],
+                               &vadc_prescale_ratios[prop->prescale],
+                               (prop->calibration == VADC_CALIB_ABSOLUTE),
+                               adc_code, val);
+               if (ret)
+                       break;
 
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_RAW:
@@ -809,7 +514,7 @@ struct vadc_channels {
        unsigned int prescale_index;
        enum iio_chan_type type;
        long info_mask;
-       unsigned int scale_fn;
+       enum vadc_scale_fn_type scale_fn_type;
 };
 
 #define VADC_CHAN(_dname, _type, _mask, _pre, _scale)                  \
@@ -818,7 +523,7 @@ struct vadc_channels {
                .prescale_index = _pre,                                 \
                .type = _type,                                          \
                .info_mask = _mask,                                     \
-               .scale_fn = _scale                                      \
+               .scale_fn_type = _scale                                 \
        },                                                              \
 
 #define VADC_NO_CHAN(_dname, _type, _mask, _pre)                       \
@@ -976,7 +681,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
 
        ret = of_property_read_u32(node, "qcom,decimation", &value);
        if (!ret) {
-               ret = vadc_decimation_from_dt(value);
+               ret = qcom_vadc_decimation_from_dt(value);
                if (ret < 0) {
                        dev_err(dev, "%02x invalid decimation %d\n",
                                chan, value);
@@ -1068,7 +773,7 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
                        return ret;
                }
 
-               prop.scale_fn = vadc_chans[prop.channel].scale_fn;
+               prop.scale_fn_type = vadc_chans[prop.channel].scale_fn_type;
                vadc->chan_props[index] = prop;
 
                vadc_chan = &vadc_chans[prop.channel];
diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c
new file mode 100644 (file)
index 0000000..102fc51
--- /dev/null
@@ -0,0 +1,230 @@
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/math64.h>
+#include <linux/log2.h>
+#include <linux/err.h>
+
+#include "qcom-vadc-common.h"
+
+/* Voltage to temperature */
+static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
+       {1758,  -40},
+       {1742,  -35},
+       {1719,  -30},
+       {1691,  -25},
+       {1654,  -20},
+       {1608,  -15},
+       {1551,  -10},
+       {1483,  -5},
+       {1404,  0},
+       {1315,  5},
+       {1218,  10},
+       {1114,  15},
+       {1007,  20},
+       {900,   25},
+       {795,   30},
+       {696,   35},
+       {605,   40},
+       {522,   45},
+       {448,   50},
+       {383,   55},
+       {327,   60},
+       {278,   65},
+       {237,   70},
+       {202,   75},
+       {172,   80},
+       {146,   85},
+       {125,   90},
+       {107,   95},
+       {92,    100},
+       {79,    105},
+       {68,    110},
+       {59,    115},
+       {51,    120},
+       {44,    125}
+};
+
+static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
+                                     u32 tablesize, s32 input, s64 *output)
+{
+       bool descending = 1;
+       u32 i = 0;
+
+       if (!pts)
+               return -EINVAL;
+
+       /* Check if table is descending or ascending */
+       if (tablesize > 1) {
+               if (pts[0].x < pts[1].x)
+                       descending = 0;
+       }
+
+       while (i < tablesize) {
+               if ((descending) && (pts[i].x < input)) {
+                       /* table entry is less than measured*/
+                        /* value and table is descending, stop */
+                       break;
+               } else if ((!descending) &&
+                               (pts[i].x > input)) {
+                       /* table entry is greater than measured*/
+                       /*value and table is ascending, stop */
+                       break;
+               }
+               i++;
+       }
+
+       if (i == 0) {
+               *output = pts[0].y;
+       } else if (i == tablesize) {
+               *output = pts[tablesize - 1].y;
+       } else {
+               /* result is between search_index and search_index-1 */
+               /* interpolate linearly */
+               *output = (((s32)((pts[i].y - pts[i - 1].y) *
+                       (input - pts[i - 1].x)) /
+                       (pts[i].x - pts[i - 1].x)) +
+                       pts[i - 1].y);
+       }
+
+       return 0;
+}
+
+static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
+                                 u16 adc_code,
+                                 bool absolute,
+                                 s64 *scale_voltage)
+{
+       *scale_voltage = (adc_code - calib_graph->gnd);
+       *scale_voltage *= calib_graph->dx;
+       *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
+       if (absolute)
+               *scale_voltage += calib_graph->dx;
+
+       if (*scale_voltage < 0)
+               *scale_voltage = 0;
+}
+
+static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
+                               const struct vadc_prescale_ratio *prescale,
+                               bool absolute, u16 adc_code,
+                               int *result_uv)
+{
+       s64 voltage = 0, result = 0;
+
+       qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
+
+       voltage = voltage * prescale->den;
+       result = div64_s64(voltage, prescale->num);
+       *result_uv = result;
+
+       return 0;
+}
+
+static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
+                                const struct vadc_prescale_ratio *prescale,
+                                bool absolute, u16 adc_code,
+                                int *result_mdec)
+{
+       s64 voltage = 0, result = 0;
+       int ret;
+
+       qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
+
+       if (absolute)
+               voltage = div64_s64(voltage, 1000);
+
+       ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
+                                        ARRAY_SIZE(adcmap_100k_104ef_104fb),
+                                        voltage, &result);
+       if (ret)
+               return ret;
+
+       result *= 1000;
+       *result_mdec = result;
+
+       return 0;
+}
+
+static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
+                                   const struct vadc_prescale_ratio *prescale,
+                                   bool absolute,
+                                   u16 adc_code, int *result_mdec)
+{
+       s64 voltage = 0;
+       u64 temp; /* Temporary variable for do_div */
+
+       qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
+
+       if (voltage > 0) {
+               temp = voltage * prescale->den;
+               do_div(temp, prescale->num * 2);
+               voltage = temp;
+       } else {
+               voltage = 0;
+       }
+
+       voltage -= KELVINMIL_CELSIUSMIL;
+       *result_mdec = voltage;
+
+       return 0;
+}
+
+static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
+                                   const struct vadc_prescale_ratio *prescale,
+                                   bool absolute,
+                                   u16 adc_code, int *result_mdec)
+{
+       s64 voltage = 0, result = 0;
+
+       qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
+
+       voltage = voltage * prescale->den;
+       voltage = div64_s64(voltage, prescale->num);
+       voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
+       voltage = (voltage + PMI_CHG_SCALE_2);
+       result =  div64_s64(voltage, 1000000);
+       *result_mdec = result;
+
+       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,
+                   bool absolute,
+                   u16 adc_code, int *result)
+{
+       switch (scaletype) {
+       case SCALE_DEFAULT:
+               return qcom_vadc_scale_volt(calib_graph, prescale,
+                                           absolute, adc_code,
+                                           result);
+       case SCALE_THERM_100K_PULLUP:
+       case SCALE_XOTHERM:
+               return qcom_vadc_scale_therm(calib_graph, prescale,
+                                            absolute, adc_code,
+                                            result);
+       case SCALE_PMIC_THERM:
+               return qcom_vadc_scale_die_temp(calib_graph, prescale,
+                                               absolute, adc_code,
+                                               result);
+       case SCALE_PMI_CHG_TEMP:
+               return qcom_vadc_scale_chg_temp(calib_graph, prescale,
+                                               absolute, adc_code,
+                                               result);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL(qcom_vadc_scale);
+
+int qcom_vadc_decimation_from_dt(u32 value)
+{
+       if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
+           value > VADC_DECIMATION_MAX)
+               return -EINVAL;
+
+       return __ffs64(value / VADC_DECIMATION_MIN);
+}
+EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h
new file mode 100644 (file)
index 0000000..63c872a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Code shared between the different Qualcomm PMIC voltage ADCs
+ */
+
+#ifndef QCOM_VADC_COMMON_H
+#define QCOM_VADC_COMMON_H
+
+#define VADC_CONV_TIME_MIN_US                  2000
+#define VADC_CONV_TIME_MAX_US                  2100
+
+/* Min ADC code represents 0V */
+#define VADC_MIN_ADC_CODE                      0x6000
+/* Max ADC code represents full-scale range of 1.8V */
+#define VADC_MAX_ADC_CODE                      0xa800
+
+#define VADC_ABSOLUTE_RANGE_UV                 625000
+#define VADC_RATIOMETRIC_RANGE                 1800
+
+#define VADC_DEF_PRESCALING                    0 /* 1:1 */
+#define VADC_DEF_DECIMATION                    0 /* 512 */
+#define VADC_DEF_HW_SETTLE_TIME                        0 /* 0 us */
+#define VADC_DEF_AVG_SAMPLES                   0 /* 1 sample */
+#define VADC_DEF_CALIB_TYPE                    VADC_CALIB_ABSOLUTE
+
+#define VADC_DECIMATION_MIN                    512
+#define VADC_DECIMATION_MAX                    4096
+
+#define VADC_HW_SETTLE_DELAY_MAX               10000
+#define VADC_AVG_SAMPLES_MAX                   512
+
+#define KELVINMIL_CELSIUSMIL                   273150
+
+#define PMI_CHG_SCALE_1                                -138890
+#define PMI_CHG_SCALE_2                                391750000000LL
+
+/**
+ * struct vadc_map_pt - Map the graph representation for ADC channel
+ * @x: Represent the ADC digitized code.
+ * @y: Represent the physical data which can be temperature, voltage,
+ *     resistance.
+ */
+struct vadc_map_pt {
+       s32 x;
+       s32 y;
+};
+
+/*
+ * VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
+ * VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
+ * calibration.
+ */
+enum vadc_calibration {
+       VADC_CALIB_ABSOLUTE = 0,
+       VADC_CALIB_RATIOMETRIC
+};
+
+/**
+ * struct vadc_linear_graph - Represent ADC characteristics.
+ * @dy: numerator slope to calculate the gain.
+ * @dx: denominator slope to calculate the gain.
+ * @gnd: A/D word of the ground reference used for the channel.
+ *
+ * Each ADC device has different offset and gain parameters which are
+ * computed to calibrate the device.
+ */
+struct vadc_linear_graph {
+       s32 dy;
+       s32 dx;
+       s32 gnd;
+};
+
+/**
+ * struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
+ * @num: the inverse numerator of the gain applied to the input channel.
+ * @den: the inverse denominator of the gain applied to the input channel.
+ */
+struct vadc_prescale_ratio {
+       u32 num;
+       u32 den;
+};
+
+/**
+ * enum vadc_scale_fn_type - Scaling function to convert ADC code to
+ *                             physical scaled units for the channel.
+ * SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
+ * SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
+ *                              Uses a mapping table with 100K pullup.
+ * 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
+ */
+enum vadc_scale_fn_type {
+       SCALE_DEFAULT = 0,
+       SCALE_THERM_100K_PULLUP,
+       SCALE_PMIC_THERM,
+       SCALE_XOTHERM,
+       SCALE_PMI_CHG_TEMP,
+};
+
+int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
+                   const struct vadc_linear_graph *calib_graph,
+                   const struct vadc_prescale_ratio *prescale,
+                   bool absolute,
+                   u16 adc_code, int *result_mdec);
+
+int qcom_vadc_decimation_from_dt(u32 value);
+
+#endif /* QCOM_VADC_COMMON_H */
index 9b49a6addc2a15e09ab3906af3418a35b045d24a..c28e7ff80e1142c329a77d1308dde2ec4e67c5ce 100644 (file)
@@ -60,6 +60,8 @@
 #define STM32F4_EOC                    BIT(1)
 
 /* STM32F4_ADC_CR1 - bit fields */
+#define STM32F4_RES_SHIFT              24
+#define STM32F4_RES_MASK               GENMASK(25, 24)
 #define STM32F4_SCAN                   BIT(8)
 #define STM32F4_EOCIE                  BIT(5)
 
@@ -141,6 +143,7 @@ struct stm32_adc_regs {
  * @lock:              spinlock
  * @bufi:              data buffer index
  * @num_conv:          expected number of scan conversions
+ * @res:               data resolution (e.g. RES bitfield value)
  * @trigger_polarity:  external trigger polarity (e.g. exten)
  * @dma_chan:          dma channel
  * @rx_buf:            dma rx buffer cpu address
@@ -157,6 +160,7 @@ struct stm32_adc {
        spinlock_t              lock;           /* interrupt lock */
        unsigned int            bufi;
        unsigned int            num_conv;
+       u32                     res;
        u32                     trigger_polarity;
        struct dma_chan         *dma_chan;
        u8                      *rx_buf;
@@ -196,6 +200,11 @@ static const struct stm32_adc_chan_spec stm32f4_adc123_channels[] = {
        { IIO_VOLTAGE, 15, "in15" },
 };
 
+static const unsigned int stm32f4_adc_resolutions[] = {
+       /* sorted values so the index matches RES[1:0] in STM32F4_ADC_CR1 */
+       12, 10, 8, 6,
+};
+
 /**
  * stm32f4_sq - describe regular sequence registers
  * - L: sequence len (register & bit field)
@@ -302,6 +311,14 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc)
        stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_EOCIE);
 }
 
+static void stm32_adc_set_res(struct stm32_adc *adc)
+{
+       u32 val = stm32_adc_readl(adc, STM32F4_ADC_CR1);
+
+       val = (val & ~STM32F4_RES_MASK) | (adc->res << STM32F4_RES_SHIFT);
+       stm32_adc_writel(adc, STM32F4_ADC_CR1, val);
+}
+
 /**
  * stm32_adc_start_conv() - Start conversions for regular channels.
  * @adc: stm32 adc instance
@@ -870,11 +887,37 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
        {},
 };
 
+static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
+{
+       struct device_node *node = indio_dev->dev.of_node;
+       struct stm32_adc *adc = iio_priv(indio_dev);
+       unsigned int i;
+       u32 res;
+
+       if (of_property_read_u32(node, "assigned-resolution-bits", &res))
+               res = stm32f4_adc_resolutions[0];
+
+       for (i = 0; i < ARRAY_SIZE(stm32f4_adc_resolutions); i++)
+               if (res == stm32f4_adc_resolutions[i])
+                       break;
+       if (i >= ARRAY_SIZE(stm32f4_adc_resolutions)) {
+               dev_err(&indio_dev->dev, "Bad resolution: %u bits\n", res);
+               return -EINVAL;
+       }
+
+       dev_dbg(&indio_dev->dev, "Using %u bits resolution\n", res);
+       adc->res = i;
+
+       return 0;
+}
+
 static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
                                    struct iio_chan_spec *chan,
                                    const struct stm32_adc_chan_spec *channel,
                                    int scan_index)
 {
+       struct stm32_adc *adc = iio_priv(indio_dev);
+
        chan->type = channel->type;
        chan->channel = channel->channel;
        chan->datasheet_name = channel->name;
@@ -883,7 +926,7 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
        chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
        chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
        chan->scan_type.sign = 'u';
-       chan->scan_type.realbits = 12;
+       chan->scan_type.realbits = stm32f4_adc_resolutions[adc->res];
        chan->scan_type.storagebits = 16;
        chan->ext_info = stm32_adc_ext_info;
 }
@@ -1022,6 +1065,11 @@ static int stm32_adc_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = stm32_adc_of_get_resolution(indio_dev);
+       if (ret < 0)
+               goto err_clk_disable;
+       stm32_adc_set_res(adc);
+
        ret = stm32_adc_chan_of_init(indio_dev);
        if (ret < 0)
                goto err_clk_disable;
index e5318251015094670101404f612799d13fab7cc2..b2352730908805f8a29822a6a00413452a3464cb 100644 (file)
@@ -85,6 +85,12 @@ static const struct gpadc_data sun6i_gpadc_data = {
        .adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
 };
 
+static const struct gpadc_data sun8i_a33_gpadc_data = {
+       .temp_offset = -1662,
+       .temp_scale = 162,
+       .tp_mode_en = SUN8I_GPADC_CTRL1_CHOP_TEMP_EN,
+};
+
 struct sun4i_gpadc_iio {
        struct iio_dev                  *indio_dev;
        struct completion               completion;
@@ -96,6 +102,7 @@ struct sun4i_gpadc_iio {
        unsigned int                    temp_data_irq;
        atomic_t                        ignore_temp_data_irq;
        const struct gpadc_data         *data;
+       bool                            no_irq;
        /* prevents concurrent reads of temperature and ADC */
        struct mutex                    mutex;
 };
@@ -138,6 +145,23 @@ static const struct iio_chan_spec sun4i_gpadc_channels_no_temp[] = {
        SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
 };
 
+static const struct iio_chan_spec sun8i_a33_gpadc_channels[] = {
+       {
+               .type = IIO_TEMP,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE) |
+                                     BIT(IIO_CHAN_INFO_OFFSET),
+               .datasheet_name = "temp_adc",
+       },
+};
+
+static const struct regmap_config sun4i_gpadc_regmap_config = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+       .fast_io = true,
+};
+
 static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
                                 unsigned int irq)
 {
@@ -247,6 +271,17 @@ static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
 {
        struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
 
+       if (info->no_irq) {
+               pm_runtime_get_sync(indio_dev->dev.parent);
+
+               regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, val);
+
+               pm_runtime_mark_last_busy(indio_dev->dev.parent);
+               pm_runtime_put_autosuspend(indio_dev->dev.parent);
+
+               return 0;
+       }
+
        return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
 }
 
@@ -454,31 +489,69 @@ static int sun4i_irq_init(struct platform_device *pdev, const char *name,
        return 0;
 }
 
-static int sun4i_gpadc_probe(struct platform_device *pdev)
+static const struct of_device_id sun4i_gpadc_of_id[] = {
+       {
+               .compatible = "allwinner,sun8i-a33-ths",
+               .data = &sun8i_a33_gpadc_data,
+       },
+       { /* sentinel */ }
+};
+
+static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
+                               struct iio_dev *indio_dev)
 {
-       struct sun4i_gpadc_iio *info;
-       struct iio_dev *indio_dev;
+       struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
+       const struct of_device_id *of_dev;
+       struct thermal_zone_device *tzd;
+       struct resource *mem;
+       void __iomem *base;
        int ret;
-       struct sun4i_gpadc_dev *sun4i_gpadc_dev;
 
-       sun4i_gpadc_dev = dev_get_drvdata(pdev->dev.parent);
+       of_dev = of_match_device(sun4i_gpadc_of_id, &pdev->dev);
+       if (!of_dev)
+               return -ENODEV;
+
+       info->no_irq = true;
+       info->data = (struct gpadc_data *)of_dev->data;
+       indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels);
+       indio_dev->channels = sun8i_a33_gpadc_channels;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       info->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                            &sun4i_gpadc_regmap_config);
+       if (IS_ERR(info->regmap)) {
+               ret = PTR_ERR(info->regmap);
+               dev_err(&pdev->dev, "failed to init regmap: %d\n", ret);
+               return ret;
+       }
 
-       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
-       if (!indio_dev)
-               return -ENOMEM;
+       if (!IS_ENABLED(CONFIG_THERMAL_OF))
+               return 0;
 
-       info = iio_priv(indio_dev);
-       platform_set_drvdata(pdev, indio_dev);
+       tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, info,
+                                                  &sun4i_ts_tz_ops);
+       if (IS_ERR(tzd))
+               dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
+                       PTR_ERR(tzd));
 
-       mutex_init(&info->mutex);
+       return PTR_ERR_OR_ZERO(tzd);
+}
+
+static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
+                                struct iio_dev *indio_dev)
+{
+       struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
+       struct sun4i_gpadc_dev *sun4i_gpadc_dev =
+               dev_get_drvdata(pdev->dev.parent);
+       int ret;
+
+       info->no_irq = false;
        info->regmap = sun4i_gpadc_dev->regmap;
-       info->indio_dev = indio_dev;
-       init_completion(&info->completion);
-       indio_dev->name = dev_name(&pdev->dev);
-       indio_dev->dev.parent = &pdev->dev;
-       indio_dev->dev.of_node = pdev->dev.of_node;
-       indio_dev->info = &sun4i_gpadc_iio_info;
-       indio_dev->modes = INDIO_DIRECT_MODE;
+
        indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels);
        indio_dev->channels = sun4i_gpadc_channels;
 
@@ -519,8 +592,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "could not register thermal sensor: %ld\n",
                                PTR_ERR(tzd));
-                       ret = PTR_ERR(tzd);
-                       goto err;
+                       return PTR_ERR(tzd);
                }
        } else {
                indio_dev->num_channels =
@@ -528,36 +600,69 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
                indio_dev->channels = sun4i_gpadc_channels_no_temp;
        }
 
-       pm_runtime_set_autosuspend_delay(&pdev->dev,
-                                        SUN4I_GPADC_AUTOSUSPEND_DELAY);
-       pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_set_suspended(&pdev->dev);
-       pm_runtime_enable(&pdev->dev);
-
        if (IS_ENABLED(CONFIG_THERMAL_OF)) {
                ret = sun4i_irq_init(pdev, "TEMP_DATA_PENDING",
                                     sun4i_gpadc_temp_data_irq_handler,
                                     "temp_data", &info->temp_data_irq,
                                     &info->ignore_temp_data_irq);
                if (ret < 0)
-                       goto err;
+                       return ret;
        }
 
        ret = sun4i_irq_init(pdev, "FIFO_DATA_PENDING",
                             sun4i_gpadc_fifo_data_irq_handler, "fifo_data",
                             &info->fifo_data_irq, &info->ignore_fifo_data_irq);
        if (ret < 0)
-               goto err;
+               return ret;
 
        if (IS_ENABLED(CONFIG_THERMAL_OF)) {
                ret = iio_map_array_register(indio_dev, sun4i_gpadc_hwmon_maps);
                if (ret < 0) {
                        dev_err(&pdev->dev,
                                "failed to register iio map array\n");
-                       goto err;
+                       return ret;
                }
        }
 
+       return 0;
+}
+
+static int sun4i_gpadc_probe(struct platform_device *pdev)
+{
+       struct sun4i_gpadc_iio *info;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       info = iio_priv(indio_dev);
+       platform_set_drvdata(pdev, indio_dev);
+
+       mutex_init(&info->mutex);
+       info->indio_dev = indio_dev;
+       init_completion(&info->completion);
+       indio_dev->name = dev_name(&pdev->dev);
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->dev.of_node = pdev->dev.of_node;
+       indio_dev->info = &sun4i_gpadc_iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       if (pdev->dev.of_node)
+               ret = sun4i_gpadc_probe_dt(pdev, indio_dev);
+       else
+               ret = sun4i_gpadc_probe_mfd(pdev, indio_dev);
+
+       if (ret)
+               return ret;
+
+       pm_runtime_set_autosuspend_delay(&pdev->dev,
+                                        SUN4I_GPADC_AUTOSUSPEND_DELAY);
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_suspended(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
        ret = devm_iio_device_register(&pdev->dev, indio_dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "could not register the device\n");
@@ -567,10 +672,9 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
        return 0;
 
 err_map:
-       if (IS_ENABLED(CONFIG_THERMAL_OF))
+       if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
                iio_map_array_unregister(indio_dev);
 
-err:
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
@@ -580,10 +684,11 @@ err:
 static int sun4i_gpadc_remove(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
 
        pm_runtime_put(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       if (IS_ENABLED(CONFIG_THERMAL_OF))
+       if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF))
                iio_map_array_unregister(indio_dev);
 
        return 0;
@@ -599,6 +704,7 @@ static const struct platform_device_id sun4i_gpadc_id[] = {
 static struct platform_driver sun4i_gpadc_driver = {
        .driver = {
                .name = "sun4i-gpadc-iio",
+               .of_match_table = sun4i_gpadc_of_id,
                .pm = &sun4i_gpadc_pm_ops,
        },
        .id_table = sun4i_gpadc_id,
index ecf592d69043ae82e2e85184096471bfebef95e2..8cadc4880359ac81b8f8cc42655130001b0712c4 100644 (file)
@@ -138,6 +138,10 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
 
 void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
 {
+       pm_runtime_disable(&attrb->pdev->dev);
+       pm_runtime_set_suspended(&attrb->pdev->dev);
+       pm_runtime_put_noidle(&attrb->pdev->dev);
+
        cancel_work_sync(&attrb->work);
        iio_trigger_unregister(attrb->trigger);
        iio_trigger_free(attrb->trigger);
index 08f2f90374099cc862d4f34999c37d1877733d19..df5abc46cd3f509d16926aa865bfb83a156681c3 100644 (file)
@@ -284,6 +284,21 @@ config MCP4922
          To compile this driver as a module, choose M here: the module
          will be called mcp4922.
 
+config STM32_DAC
+       tristate "STMicroelectronics STM32 DAC"
+       depends on (ARCH_STM32 && OF) || COMPILE_TEST
+       depends on REGULATOR
+       select STM32_DAC_CORE
+       help
+         Say yes here to build support for STMicroelectronics STM32 Digital
+         to Analog Converter (DAC).
+
+         This driver can also be built as a module.  If so, the module
+         will be called stm32-dac.
+
+config STM32_DAC_CORE
+       tristate
+
 config VF610_DAC
        tristate "Vybrid vf610 DAC driver"
        depends on OF
index 6e4d99557309dac9f8ed4b68cf0921782f45d950..603587cc2f079242aa166180d01c5c9c64b6fd48 100644 (file)
@@ -30,4 +30,6 @@ obj-$(CONFIG_MAX517) += max517.o
 obj-$(CONFIG_MAX5821) += max5821.o
 obj-$(CONFIG_MCP4725) += mcp4725.o
 obj-$(CONFIG_MCP4922) += mcp4922.o
+obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
+obj-$(CONFIG_STM32_DAC) += stm32-dac.o
 obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
new file mode 100644 (file)
index 0000000..75e4878
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * This file is part of STM32 DAC driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
+ *
+ * License type: GPLv2
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#include "stm32-dac-core.h"
+
+/**
+ * struct stm32_dac_priv - stm32 DAC core private data
+ * @pclk:              peripheral clock common for all DACs
+ * @rst:               peripheral reset control
+ * @vref:              regulator reference
+ * @common:            Common data for all DAC instances
+ */
+struct stm32_dac_priv {
+       struct clk *pclk;
+       struct reset_control *rst;
+       struct regulator *vref;
+       struct stm32_dac_common common;
+};
+
+static struct stm32_dac_priv *to_stm32_dac_priv(struct stm32_dac_common *com)
+{
+       return container_of(com, struct stm32_dac_priv, common);
+}
+
+static const struct regmap_config stm32_dac_regmap_cfg = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = sizeof(u32),
+       .max_register = 0x3fc,
+};
+
+static int stm32_dac_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct stm32_dac_priv *priv;
+       struct regmap *regmap;
+       struct resource *res;
+       void __iomem *mmio;
+       int ret;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mmio = devm_ioremap_resource(dev, res);
+       if (IS_ERR(mmio))
+               return PTR_ERR(mmio);
+
+       regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+       priv->common.regmap = regmap;
+
+       priv->vref = devm_regulator_get(dev, "vref");
+       if (IS_ERR(priv->vref)) {
+               ret = PTR_ERR(priv->vref);
+               dev_err(dev, "vref get failed, %d\n", ret);
+               return ret;
+       }
+
+       ret = regulator_enable(priv->vref);
+       if (ret < 0) {
+               dev_err(dev, "vref enable failed\n");
+               return ret;
+       }
+
+       ret = regulator_get_voltage(priv->vref);
+       if (ret < 0) {
+               dev_err(dev, "vref get voltage failed, %d\n", ret);
+               goto err_vref;
+       }
+       priv->common.vref_mv = ret / 1000;
+       dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
+
+       priv->pclk = devm_clk_get(dev, "pclk");
+       if (IS_ERR(priv->pclk)) {
+               ret = PTR_ERR(priv->pclk);
+               dev_err(dev, "pclk get failed\n");
+               goto err_vref;
+       }
+
+       ret = clk_prepare_enable(priv->pclk);
+       if (ret < 0) {
+               dev_err(dev, "pclk enable failed\n");
+               goto err_vref;
+       }
+
+       priv->rst = devm_reset_control_get(dev, NULL);
+       if (!IS_ERR(priv->rst)) {
+               reset_control_assert(priv->rst);
+               udelay(2);
+               reset_control_deassert(priv->rst);
+       }
+
+       /* When clock speed is higher than 80MHz, set HFSEL */
+       priv->common.hfsel = (clk_get_rate(priv->pclk) > 80000000UL);
+       ret = regmap_update_bits(regmap, STM32_DAC_CR, STM32H7_DAC_CR_HFSEL,
+                                priv->common.hfsel ? STM32H7_DAC_CR_HFSEL : 0);
+       if (ret)
+               goto err_pclk;
+
+       platform_set_drvdata(pdev, &priv->common);
+
+       ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
+       if (ret < 0) {
+               dev_err(dev, "failed to populate DT children\n");
+               goto err_pclk;
+       }
+
+       return 0;
+
+err_pclk:
+       clk_disable_unprepare(priv->pclk);
+err_vref:
+       regulator_disable(priv->vref);
+
+       return ret;
+}
+
+static int stm32_dac_remove(struct platform_device *pdev)
+{
+       struct stm32_dac_common *common = platform_get_drvdata(pdev);
+       struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
+
+       of_platform_depopulate(&pdev->dev);
+       clk_disable_unprepare(priv->pclk);
+       regulator_disable(priv->vref);
+
+       return 0;
+}
+
+static const struct of_device_id stm32_dac_of_match[] = {
+       { .compatible = "st,stm32h7-dac-core", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
+
+static struct platform_driver stm32_dac_driver = {
+       .probe = stm32_dac_probe,
+       .remove = stm32_dac_remove,
+       .driver = {
+               .name = "stm32-dac-core",
+               .of_match_table = stm32_dac_of_match,
+       },
+};
+module_platform_driver(stm32_dac_driver);
+
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DAC core driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:stm32-dac-core");
diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h
new file mode 100644 (file)
index 0000000..daf0993
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * This file is part of STM32 DAC driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
+ *
+ * License type: GPLv2
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STM32_DAC_CORE_H
+#define __STM32_DAC_CORE_H
+
+#include <linux/regmap.h>
+
+/* STM32 DAC registers */
+#define STM32_DAC_CR           0x00
+#define STM32_DAC_DHR12R1      0x08
+#define STM32_DAC_DHR12R2      0x14
+#define STM32_DAC_DOR1         0x2C
+#define STM32_DAC_DOR2         0x30
+
+/* STM32_DAC_CR bit fields */
+#define STM32_DAC_CR_EN1               BIT(0)
+#define STM32H7_DAC_CR_HFSEL           BIT(15)
+#define STM32_DAC_CR_EN2               BIT(16)
+
+/**
+ * struct stm32_dac_common - stm32 DAC driver common data (for all instances)
+ * @regmap: DAC registers shared via regmap
+ * @vref_mv: reference voltage (mv)
+ * @hfsel: high speed bus clock selected
+ */
+struct stm32_dac_common {
+       struct regmap                   *regmap;
+       int                             vref_mv;
+       bool                            hfsel;
+};
+
+#endif
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
new file mode 100644 (file)
index 0000000..50f8ec0
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * This file is part of STM32 DAC driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Authors: Amelie Delaunay <amelie.delaunay@st.com>
+ *         Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License type: GPLv2
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "stm32-dac-core.h"
+
+#define STM32_DAC_CHANNEL_1            1
+#define STM32_DAC_CHANNEL_2            2
+#define STM32_DAC_IS_CHAN_1(ch)                ((ch) & STM32_DAC_CHANNEL_1)
+
+/**
+ * struct stm32_dac - private data of DAC driver
+ * @common:            reference to DAC common data
+ */
+struct stm32_dac {
+       struct stm32_dac_common *common;
+};
+
+static int stm32_dac_is_enabled(struct iio_dev *indio_dev, int channel)
+{
+       struct stm32_dac *dac = iio_priv(indio_dev);
+       u32 en, val;
+       int ret;
+
+       ret = regmap_read(dac->common->regmap, STM32_DAC_CR, &val);
+       if (ret < 0)
+               return ret;
+       if (STM32_DAC_IS_CHAN_1(channel))
+               en = FIELD_GET(STM32_DAC_CR_EN1, val);
+       else
+               en = FIELD_GET(STM32_DAC_CR_EN2, val);
+
+       return !!en;
+}
+
+static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
+                                     bool enable)
+{
+       struct stm32_dac *dac = iio_priv(indio_dev);
+       u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
+       u32 en = enable ? msk : 0;
+       int ret;
+
+       ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en);
+       if (ret < 0) {
+               dev_err(&indio_dev->dev, "%s failed\n", en ?
+                       "Enable" : "Disable");
+               return ret;
+       }
+
+       /*
+        * When HFSEL is set, it is not allowed to write the DHRx register
+        * during 8 clock cycles after the ENx bit is set. It is not allowed
+        * to make software/hardware trigger during this period either.
+        */
+       if (en && dac->common->hfsel)
+               udelay(1);
+
+       return 0;
+}
+
+static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
+{
+       int ret;
+
+       if (STM32_DAC_IS_CHAN_1(channel))
+               ret = regmap_read(dac->common->regmap, STM32_DAC_DOR1, val);
+       else
+               ret = regmap_read(dac->common->regmap, STM32_DAC_DOR2, val);
+
+       return ret ? ret : IIO_VAL_INT;
+}
+
+static int stm32_dac_set_value(struct stm32_dac *dac, int channel, int val)
+{
+       int ret;
+
+       if (STM32_DAC_IS_CHAN_1(channel))
+               ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R1, val);
+       else
+               ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R2, val);
+
+       return ret;
+}
+
+static int stm32_dac_read_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int *val, int *val2, long mask)
+{
+       struct stm32_dac *dac = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               return stm32_dac_get_value(dac, chan->channel, val);
+       case IIO_CHAN_INFO_SCALE:
+               *val = dac->common->vref_mv;
+               *val2 = chan->scan_type.realbits;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int stm32_dac_write_raw(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              int val, int val2, long mask)
+{
+       struct stm32_dac *dac = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               return stm32_dac_set_value(dac, chan->channel, val);
+       default:
+               return -EINVAL;
+       }
+}
+
+static int stm32_dac_debugfs_reg_access(struct iio_dev *indio_dev,
+                                       unsigned reg, unsigned writeval,
+                                       unsigned *readval)
+{
+       struct stm32_dac *dac = iio_priv(indio_dev);
+
+       if (!readval)
+               return regmap_write(dac->common->regmap, reg, writeval);
+       else
+               return regmap_read(dac->common->regmap, reg, readval);
+}
+
+static const struct iio_info stm32_dac_iio_info = {
+       .read_raw = stm32_dac_read_raw,
+       .write_raw = stm32_dac_write_raw,
+       .debugfs_reg_access = stm32_dac_debugfs_reg_access,
+       .driver_module = THIS_MODULE,
+};
+
+static const char * const stm32_dac_powerdown_modes[] = {
+       "three_state",
+};
+
+static int stm32_dac_get_powerdown_mode(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan)
+{
+       return 0;
+}
+
+static int stm32_dac_set_powerdown_mode(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan,
+                                       unsigned int type)
+{
+       return 0;
+}
+
+static ssize_t stm32_dac_read_powerdown(struct iio_dev *indio_dev,
+                                       uintptr_t private,
+                                       const struct iio_chan_spec *chan,
+                                       char *buf)
+{
+       int ret = stm32_dac_is_enabled(indio_dev, chan->channel);
+
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", ret ? 0 : 1);
+}
+
+static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev,
+                                        uintptr_t private,
+                                        const struct iio_chan_spec *chan,
+                                        const char *buf, size_t len)
+{
+       bool powerdown;
+       int ret;
+
+       ret = strtobool(buf, &powerdown);
+       if (ret)
+               return ret;
+
+       ret = stm32_dac_set_enable_state(indio_dev, chan->channel, !powerdown);
+       if (ret)
+               return ret;
+
+       return len;
+}
+
+static const struct iio_enum stm32_dac_powerdown_mode_en = {
+       .items = stm32_dac_powerdown_modes,
+       .num_items = ARRAY_SIZE(stm32_dac_powerdown_modes),
+       .get = stm32_dac_get_powerdown_mode,
+       .set = stm32_dac_set_powerdown_mode,
+};
+
+static const struct iio_chan_spec_ext_info stm32_dac_ext_info[] = {
+       {
+               .name = "powerdown",
+               .read = stm32_dac_read_powerdown,
+               .write = stm32_dac_write_powerdown,
+               .shared = IIO_SEPARATE,
+       },
+       IIO_ENUM("powerdown_mode", IIO_SEPARATE, &stm32_dac_powerdown_mode_en),
+       IIO_ENUM_AVAILABLE("powerdown_mode", &stm32_dac_powerdown_mode_en),
+       {},
+};
+
+#define STM32_DAC_CHANNEL(chan, name) {                        \
+       .type = IIO_VOLTAGE,                            \
+       .indexed = 1,                                   \
+       .output = 1,                                    \
+       .channel = chan,                                \
+       .info_mask_separate =                           \
+               BIT(IIO_CHAN_INFO_RAW) |                \
+               BIT(IIO_CHAN_INFO_SCALE),               \
+       /* scan_index is always 0 as num_channels is 1 */ \
+       .scan_type = {                                  \
+               .sign = 'u',                            \
+               .realbits = 12,                         \
+               .storagebits = 16,                      \
+       },                                              \
+       .datasheet_name = name,                         \
+       .ext_info = stm32_dac_ext_info                  \
+}
+
+static const struct iio_chan_spec stm32_dac_channels[] = {
+       STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_1, "out1"),
+       STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_2, "out2"),
+};
+
+static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
+{
+       struct device_node *np = indio_dev->dev.of_node;
+       unsigned int i;
+       u32 channel;
+       int ret;
+
+       ret = of_property_read_u32(np, "reg", &channel);
+       if (ret) {
+               dev_err(&indio_dev->dev, "Failed to read reg property\n");
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(stm32_dac_channels); i++) {
+               if (stm32_dac_channels[i].channel == channel)
+                       break;
+       }
+       if (i >= ARRAY_SIZE(stm32_dac_channels)) {
+               dev_err(&indio_dev->dev, "Invalid st,dac-channel\n");
+               return -EINVAL;
+       }
+
+       indio_dev->channels = &stm32_dac_channels[i];
+       /*
+        * Expose only one channel here, as they can be used independently,
+        * with separate trigger. Then separate IIO devices are instantiated
+        * to manage this.
+        */
+       indio_dev->num_channels = 1;
+
+       return 0;
+};
+
+static int stm32_dac_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct iio_dev *indio_dev;
+       struct stm32_dac *dac;
+       int ret;
+
+       if (!np)
+               return -ENODEV;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
+       if (!indio_dev)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, indio_dev);
+
+       dac = iio_priv(indio_dev);
+       dac->common = dev_get_drvdata(pdev->dev.parent);
+       indio_dev->name = dev_name(&pdev->dev);
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->dev.of_node = pdev->dev.of_node;
+       indio_dev->info = &stm32_dac_iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = stm32_dac_chan_of_init(indio_dev);
+       if (ret < 0)
+               return ret;
+
+       return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static const struct of_device_id stm32_dac_of_match[] = {
+       { .compatible = "st,stm32-dac", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
+
+static struct platform_driver stm32_dac_driver = {
+       .probe = stm32_dac_probe,
+       .driver = {
+               .name = "stm32-dac",
+               .of_match_table = stm32_dac_of_match,
+       },
+};
+module_platform_driver(stm32_dac_driver);
+
+MODULE_ALIAS("platform:stm32-dac");
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DAC driver");
+MODULE_LICENSE("GPL v2");
index 06007200bf49ba676ab5aadfb51932f8d8b713a4..93f08b304a6345afda26ec6dbacfa09a2fb8aa3d 100644 (file)
@@ -70,9 +70,8 @@ static int mpu3050_i2c_probe(struct i2c_client *client,
                dev_err(&client->dev, "failed to allocate I2C mux\n");
        else {
                mpu3050->i2cmux->priv = mpu3050;
-               ret = i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0);
-               if (ret)
-                       dev_err(&client->dev, "failed to add I2C mux\n");
+               /* Ignore failure, not critical */
+               i2c_mux_add_adapter(mpu3050->i2cmux, 0, 0, 0);
        }
 
        return 0;
index 6a9849e6b30ad97e11e8cec12c8c9eb09f4bbf8e..4839db7b9690ca60c365acb9a79ade5bbb2c242f 100644 (file)
@@ -71,6 +71,7 @@ enum st_lsm6dsx_fifo_mode {
 
 /**
  * struct st_lsm6dsx_sensor - ST IMU sensor instance
+ * @name: Sensor name.
  * @id: Sensor identifier.
  * @hw: Pointer to instance of struct st_lsm6dsx_hw.
  * @gain: Configured sensor sensitivity.
@@ -83,6 +84,7 @@ enum st_lsm6dsx_fifo_mode {
  * @ts: Latest timestamp from the interrupt handler.
  */
 struct st_lsm6dsx_sensor {
+       char name[32];
        enum st_lsm6dsx_sensor_id id;
        struct st_lsm6dsx_hw *hw;
 
@@ -133,7 +135,7 @@ struct st_lsm6dsx_hw {
 #endif /* CONFIG_SPI_MASTER */
 };
 
-int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
                     const struct st_lsm6dsx_transfer_function *tf_ops);
 int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
 int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
index f80a3d4ff977bd5d26f695897fc21a3889fabd13..462a27b70453348c1a2599cbbfc25bbb3f3e0e76 100644 (file)
@@ -559,19 +559,11 @@ static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
 static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
 {
        struct device_node *np = hw->dev->of_node;
-       int err;
 
        if (!np)
                return -EINVAL;
 
-       err = of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
-       if (err == -ENODATA) {
-               /* if the property has not been specified use default value */
-               *drdy_pin = 1;
-               err = 0;
-       }
-
-       return err;
+       return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
 }
 
 static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
@@ -642,7 +634,8 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
 }
 
 static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
-                                              enum st_lsm6dsx_sensor_id id)
+                                              enum st_lsm6dsx_sensor_id id,
+                                              const char *name)
 {
        struct st_lsm6dsx_sensor *sensor;
        struct iio_dev *iio_dev;
@@ -666,27 +659,30 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
        case ST_LSM6DSX_ID_ACC:
                iio_dev->channels = st_lsm6dsx_acc_channels;
                iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
-               iio_dev->name = "lsm6dsx_accel";
                iio_dev->info = &st_lsm6dsx_acc_info;
 
                sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK;
+               scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
+                         name);
                break;
        case ST_LSM6DSX_ID_GYRO:
                iio_dev->channels = st_lsm6dsx_gyro_channels;
                iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
-               iio_dev->name = "lsm6dsx_gyro";
                iio_dev->info = &st_lsm6dsx_gyro_info;
 
                sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK;
+               scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
+                         name);
                break;
        default:
                return NULL;
        }
+       iio_dev->name = sensor->name;
 
        return iio_dev;
 }
 
-int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
                     const struct st_lsm6dsx_transfer_function *tf_ops)
 {
        struct st_lsm6dsx_hw *hw;
@@ -710,7 +706,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
                return err;
 
        for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
-               hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i);
+               hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
                if (!hw->iio_devs[i])
                        return -ENOMEM;
        }
index 2e4ed26fcbbd29bfbd9edce2ff6f123848f023ca..09a51cfb9b5e4bc75d98e3110e197e47b730efdf 100644 (file)
@@ -61,7 +61,7 @@ static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
        return st_lsm6dsx_probe(&client->dev, client->irq,
-                               (int)id->driver_data,
+                               (int)id->driver_data, id->name,
                                &st_lsm6dsx_transfer_fn);
 }
 
index 1bf4a582e6cfaccc1efa1b103c5cb820d0b828c9..f765a5058488ccbdf12b8f76eb0d814c0304eba9 100644 (file)
@@ -78,7 +78,7 @@ static int st_lsm6dsx_spi_probe(struct spi_device *spi)
        const struct spi_device_id *id = spi_get_device_id(spi);
 
        return st_lsm6dsx_probe(&spi->dev, spi->irq,
-                               (int)id->driver_data,
+                               (int)id->driver_data, id->name,
                                &st_lsm6dsx_transfer_fn);
 }
 
index c7af36de29a7446476aa2375602cf31198d5d8d7..518a47e9377b031130d3e562e818c3a463a1c18f 100644 (file)
@@ -1112,6 +1112,8 @@ static int apds9960_runtime_resume(struct device *dev)
 #endif
 
 static const struct dev_pm_ops apds9960_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
        SET_RUNTIME_PM_OPS(apds9960_runtime_suspend,
                           apds9960_runtime_resume, NULL)
 };
index 994b96d1975064a651bf57528b7081fa5fd50d2a..0f1a2cf334bf29fee830aab71c4768c81623e7a5 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/platform_device.h>
 
 #define MAX_TRIGGERS 6
+#define MAX_VALIDS 5
 
 /* List the triggers created by each timer */
 static const void *triggers_table[][MAX_TRIGGERS] = {
@@ -32,12 +33,29 @@ static const void *triggers_table[][MAX_TRIGGERS] = {
        { TIM12_TRGO, TIM12_CH1, TIM12_CH2,},
 };
 
+/* List the triggers accepted by each timer */
+static const void *valids_table[][MAX_VALIDS] = {
+       { TIM5_TRGO, TIM2_TRGO, TIM3_TRGO, TIM4_TRGO,},
+       { TIM1_TRGO, TIM8_TRGO, TIM3_TRGO, TIM4_TRGO,},
+       { TIM1_TRGO, TIM2_TRGO, TIM5_TRGO, TIM4_TRGO,},
+       { TIM1_TRGO, TIM2_TRGO, TIM3_TRGO, TIM8_TRGO,},
+       { TIM2_TRGO, TIM3_TRGO, TIM4_TRGO, TIM8_TRGO,},
+       { }, /* timer 6 */
+       { }, /* timer 7 */
+       { TIM1_TRGO, TIM2_TRGO, TIM4_TRGO, TIM5_TRGO,},
+       { TIM2_TRGO, TIM3_TRGO,},
+       { }, /* timer 10 */
+       { }, /* timer 11 */
+       { TIM4_TRGO, TIM5_TRGO,},
+};
+
 struct stm32_timer_trigger {
        struct device *dev;
        struct regmap *regmap;
        struct clk *clk;
        u32 max_arr;
        const void *triggers;
+       const void *valids;
 };
 
 static int stm32_timer_start(struct stm32_timer_trigger *priv,
@@ -180,8 +198,7 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev,
                                         struct device_attribute *attr,
                                         char *buf)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
        u32 cr2;
 
        regmap_read(priv->regmap, TIM_CR2, &cr2);
@@ -194,8 +211,7 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
                                          struct device_attribute *attr,
                                          const char *buf, size_t len)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
        int i;
 
        for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) {
@@ -275,6 +291,286 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
        return 0;
 }
 
+static int stm32_counter_read_raw(struct iio_dev *indio_dev,
+                                 struct iio_chan_spec const *chan,
+                                 int *val, int *val2, long mask)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+       {
+               u32 cnt;
+
+               regmap_read(priv->regmap, TIM_CNT, &cnt);
+               *val = cnt;
+
+               return IIO_VAL_INT;
+       }
+       case IIO_CHAN_INFO_SCALE:
+       {
+               u32 smcr;
+
+               regmap_read(priv->regmap, TIM_SMCR, &smcr);
+               smcr &= TIM_SMCR_SMS;
+
+               *val = 1;
+               *val2 = 0;
+
+               /* in quadrature case scale = 0.25 */
+               if (smcr == 3)
+                       *val2 = 2;
+
+               return IIO_VAL_FRACTIONAL_LOG2;
+       }
+       }
+
+       return -EINVAL;
+}
+
+static int stm32_counter_write_raw(struct iio_dev *indio_dev,
+                                  struct iio_chan_spec const *chan,
+                                  int val, int val2, long mask)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               regmap_write(priv->regmap, TIM_CNT, val);
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               /* fixed scale */
+               return -EINVAL;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_info stm32_trigger_info = {
+       .driver_module = THIS_MODULE,
+       .read_raw = stm32_counter_read_raw,
+       .write_raw = stm32_counter_write_raw
+};
+
+static const char *const stm32_enable_modes[] = {
+       "always",
+       "gated",
+       "triggered",
+};
+
+static int stm32_enable_mode2sms(int mode)
+{
+       switch (mode) {
+       case 0:
+               return 0;
+       case 1:
+               return 5;
+       case 2:
+               return 6;
+       }
+
+       return -EINVAL;
+}
+
+static int stm32_set_enable_mode(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan,
+                                unsigned int mode)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       int sms = stm32_enable_mode2sms(mode);
+
+       if (sms < 0)
+               return sms;
+
+       regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, sms);
+
+       return 0;
+}
+
+static int stm32_sms2enable_mode(int mode)
+{
+       switch (mode) {
+       case 0:
+               return 0;
+       case 5:
+               return 1;
+       case 6:
+               return 2;
+       }
+
+       return -EINVAL;
+}
+
+static int stm32_get_enable_mode(struct iio_dev *indio_dev,
+                                const struct iio_chan_spec *chan)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       u32 smcr;
+
+       regmap_read(priv->regmap, TIM_SMCR, &smcr);
+       smcr &= TIM_SMCR_SMS;
+
+       return stm32_sms2enable_mode(smcr);
+}
+
+static const struct iio_enum stm32_enable_mode_enum = {
+       .items = stm32_enable_modes,
+       .num_items = ARRAY_SIZE(stm32_enable_modes),
+       .set = stm32_set_enable_mode,
+       .get = stm32_get_enable_mode
+};
+
+static const char *const stm32_quadrature_modes[] = {
+       "channel_A",
+       "channel_B",
+       "quadrature",
+};
+
+static int stm32_set_quadrature_mode(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    unsigned int mode)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+
+       regmap_update_bits(priv->regmap, TIM_SMCR, TIM_SMCR_SMS, mode + 1);
+
+       return 0;
+}
+
+static int stm32_get_quadrature_mode(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       u32 smcr;
+
+       regmap_read(priv->regmap, TIM_SMCR, &smcr);
+       smcr &= TIM_SMCR_SMS;
+
+       return smcr - 1;
+}
+
+static const struct iio_enum stm32_quadrature_mode_enum = {
+       .items = stm32_quadrature_modes,
+       .num_items = ARRAY_SIZE(stm32_quadrature_modes),
+       .set = stm32_set_quadrature_mode,
+       .get = stm32_get_quadrature_mode
+};
+
+static const char *const stm32_count_direction_states[] = {
+       "up",
+       "down"
+};
+
+static int stm32_set_count_direction(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    unsigned int mode)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+
+       regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_DIR, mode);
+
+       return 0;
+}
+
+static int stm32_get_count_direction(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       u32 cr1;
+
+       regmap_read(priv->regmap, TIM_CR1, &cr1);
+
+       return (cr1 & TIM_CR1_DIR);
+}
+
+static const struct iio_enum stm32_count_direction_enum = {
+       .items = stm32_count_direction_states,
+       .num_items = ARRAY_SIZE(stm32_count_direction_states),
+       .set = stm32_set_count_direction,
+       .get = stm32_get_count_direction
+};
+
+static ssize_t stm32_count_get_preset(struct iio_dev *indio_dev,
+                                     uintptr_t private,
+                                     const struct iio_chan_spec *chan,
+                                     char *buf)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       u32 arr;
+
+       regmap_read(priv->regmap, TIM_ARR, &arr);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", arr);
+}
+
+static ssize_t stm32_count_set_preset(struct iio_dev *indio_dev,
+                                     uintptr_t private,
+                                     const struct iio_chan_spec *chan,
+                                     const char *buf, size_t len)
+{
+       struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+       unsigned int preset;
+       int ret;
+
+       ret = kstrtouint(buf, 0, &preset);
+       if (ret)
+               return ret;
+
+       regmap_write(priv->regmap, TIM_ARR, preset);
+       regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+       return len;
+}
+
+static const struct iio_chan_spec_ext_info stm32_trigger_count_info[] = {
+       {
+               .name = "preset",
+               .shared = IIO_SEPARATE,
+               .read = stm32_count_get_preset,
+               .write = stm32_count_set_preset
+       },
+       IIO_ENUM("count_direction", IIO_SEPARATE, &stm32_count_direction_enum),
+       IIO_ENUM_AVAILABLE("count_direction", &stm32_count_direction_enum),
+       IIO_ENUM("quadrature_mode", IIO_SEPARATE, &stm32_quadrature_mode_enum),
+       IIO_ENUM_AVAILABLE("quadrature_mode", &stm32_quadrature_mode_enum),
+       IIO_ENUM("enable_mode", IIO_SEPARATE, &stm32_enable_mode_enum),
+       IIO_ENUM_AVAILABLE("enable_mode", &stm32_enable_mode_enum),
+       {}
+};
+
+static const struct iio_chan_spec stm32_trigger_channel = {
+       .type = IIO_COUNT,
+       .channel = 0,
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+       .ext_info = stm32_trigger_count_info,
+       .indexed = 1
+};
+
+static struct stm32_timer_trigger *stm32_setup_counter_device(struct device *dev)
+{
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(dev,
+                                         sizeof(struct stm32_timer_trigger));
+       if (!indio_dev)
+               return NULL;
+
+       indio_dev->name = dev_name(dev);
+       indio_dev->dev.parent = dev;
+       indio_dev->info = &stm32_trigger_info;
+       indio_dev->num_channels = 1;
+       indio_dev->channels = &stm32_trigger_channel;
+       indio_dev->dev.of_node = dev->of_node;
+
+       ret = devm_iio_device_register(dev, indio_dev);
+       if (ret)
+               return NULL;
+
+       return iio_priv(indio_dev);
+}
+
 /**
  * is_stm32_timer_trigger
  * @trig: trigger to be checked
@@ -299,10 +595,15 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
        if (of_property_read_u32(dev->of_node, "reg", &index))
                return -EINVAL;
 
-       if (index >= ARRAY_SIZE(triggers_table))
+       if (index >= ARRAY_SIZE(triggers_table) ||
+           index >= ARRAY_SIZE(valids_table))
                return -EINVAL;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       /* Create an IIO device only if we have triggers to be validated */
+       if (*valids_table[index])
+               priv = stm32_setup_counter_device(dev);
+       else
+               priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 
        if (!priv)
                return -ENOMEM;
@@ -312,6 +613,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
        priv->clk = ddata->clk;
        priv->max_arr = ddata->max_arr;
        priv->triggers = triggers_table[index];
+       priv->valids = valids_table[index];
 
        ret = stm32_setup_iio_triggers(priv);
        if (ret)
index faa2869b54319c27cabcd1e658630e9613ed550a..4e3fa7592d3f2a41d194b0b3d481f7fe66bcc4ea 100644 (file)
@@ -205,9 +205,8 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
                bits = 14;
                addr = adis16203_addresses[chan->scan_index];
                ret = adis_read_reg_16(st, addr, &val16);
-               if (ret) {
+               if (ret)
                        return ret;
-               }
                val16 &= (1 << bits) - 1;
                val16 = (s16)(val16 << (16 - bits)) >> (16 - bits);
                *val = val16;
index 297665d3fe11e0ee5b927a4839235873966dfe40..3d539eeb0e26a3ef0867c2d419a57171332c1775 100644 (file)
@@ -98,6 +98,7 @@ struct ad5933_state {
        struct i2c_client               *client;
        struct regulator                *reg;
        struct delayed_work             work;
+       struct mutex                    lock; /* Protect sensor state */
        unsigned long                   mclk_hz;
        unsigned char                   ctrl_hb;
        unsigned char                   ctrl_lb;
@@ -306,9 +307,11 @@ static ssize_t ad5933_show_frequency(struct device *dev,
                u8 d8[4];
        } dat;
 
-       mutex_lock(&indio_dev->mlock);
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
        ret = ad5933_i2c_read(st->client, this_attr->address, 3, &dat.d8[1]);
-       mutex_unlock(&indio_dev->mlock);
+       iio_device_release_direct_mode(indio_dev);
        if (ret < 0)
                return ret;
 
@@ -338,9 +341,11 @@ static ssize_t ad5933_store_frequency(struct device *dev,
        if (val > AD5933_MAX_OUTPUT_FREQ_Hz)
                return -EINVAL;
 
-       mutex_lock(&indio_dev->mlock);
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
        ret = ad5933_set_freq(st, this_attr->address, val);
-       mutex_unlock(&indio_dev->mlock);
+       iio_device_release_direct_mode(indio_dev);
 
        return ret ? ret : len;
 }
@@ -364,7 +369,7 @@ static ssize_t ad5933_show(struct device *dev,
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        int ret = 0, len = 0;
 
-       mutex_lock(&indio_dev->mlock);
+       mutex_lock(&st->lock);
        switch ((u32)this_attr->address) {
        case AD5933_OUT_RANGE:
                len = sprintf(buf, "%u\n",
@@ -393,7 +398,7 @@ static ssize_t ad5933_show(struct device *dev,
                ret = -EINVAL;
        }
 
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&st->lock);
        return ret ? ret : len;
 }
 
@@ -415,7 +420,10 @@ static ssize_t ad5933_store(struct device *dev,
                        return ret;
        }
 
-       mutex_lock(&indio_dev->mlock);
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret)
+               return ret;
+       mutex_lock(&st->lock);
        switch ((u32)this_attr->address) {
        case AD5933_OUT_RANGE:
                ret = -EINVAL;
@@ -465,7 +473,8 @@ static ssize_t ad5933_store(struct device *dev,
                ret = -EINVAL;
        }
 
-       mutex_unlock(&indio_dev->mlock);
+       mutex_unlock(&st->lock);
+       iio_device_release_direct_mode(indio_dev);
        return ret ? ret : len;
 }
 
@@ -532,11 +541,9 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
 
        switch (m) {
        case IIO_CHAN_INFO_RAW:
-               mutex_lock(&indio_dev->mlock);
-               if (iio_buffer_enabled(indio_dev)) {
-                       ret = -EBUSY;
-                       goto out;
-               }
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
                ret = ad5933_cmd(st, AD5933_CTRL_MEASURE_TEMP);
                if (ret < 0)
                        goto out;
@@ -549,7 +556,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
                                      2, (u8 *)&dat);
                if (ret < 0)
                        goto out;
-               mutex_unlock(&indio_dev->mlock);
+               iio_device_release_direct_mode(indio_dev);
                *val = sign_extend32(be16_to_cpu(dat), 13);
 
                return IIO_VAL_INT;
@@ -561,7 +568,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
 
        return -EINVAL;
 out:
-       mutex_unlock(&indio_dev->mlock);
+       iio_device_release_direct_mode(indio_dev);
        return ret;
 }
 
@@ -657,18 +664,17 @@ static void ad5933_work(struct work_struct *work)
        unsigned char status;
        int ret;
 
-       mutex_lock(&indio_dev->mlock);
        if (st->state == AD5933_CTRL_INIT_START_FREQ) {
                /* start sweep */
                ad5933_cmd(st, AD5933_CTRL_START_SWEEP);
                st->state = AD5933_CTRL_START_SWEEP;
                schedule_delayed_work(&st->work, st->poll_time_jiffies);
-               goto out;
+               return;
        }
 
        ret = ad5933_i2c_read(st->client, AD5933_REG_STATUS, 1, &status);
        if (ret)
-               goto out;
+               return;
 
        if (status & AD5933_STAT_DATA_VALID) {
                int scan_count = bitmap_weight(indio_dev->active_scan_mask,
@@ -678,7 +684,7 @@ static void ad5933_work(struct work_struct *work)
                                AD5933_REG_REAL_DATA : AD5933_REG_IMAG_DATA,
                                scan_count * 2, (u8 *)buf);
                if (ret)
-                       goto out;
+                       return;
 
                if (scan_count == 2) {
                        val[0] = be16_to_cpu(buf[0]);
@@ -690,7 +696,7 @@ static void ad5933_work(struct work_struct *work)
        } else {
                /* no data available - try again later */
                schedule_delayed_work(&st->work, st->poll_time_jiffies);
-               goto out;
+               return;
        }
 
        if (status & AD5933_STAT_SWEEP_DONE) {
@@ -703,8 +709,6 @@ static void ad5933_work(struct work_struct *work)
                ad5933_cmd(st, AD5933_CTRL_INC_FREQ);
                schedule_delayed_work(&st->work, st->poll_time_jiffies);
        }
-out:
-       mutex_unlock(&indio_dev->mlock);
 }
 
 static int ad5933_probe(struct i2c_client *client,
@@ -723,6 +727,8 @@ static int ad5933_probe(struct i2c_client *client,
        i2c_set_clientdata(client, indio_dev);
        st->client = client;
 
+       mutex_init(&st->lock);
+
        if (!pdata)
                pdata = &ad5933_default_pdata;
 
index 0b65f1847510372d4abc3c38a137918102da1da0..1691760339da0f021db0d36e3c0d1e7dcef03323 100644 (file)
@@ -279,49 +279,49 @@ static int ade7759_reset(struct device *dev)
 }
 
 static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY);
-static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFDEN(0644,
                ade7759_read_16bit,
                ade7759_write_16bit,
                ADE7759_CFDEN);
-static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFNUM(0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_CFNUM);
 static IIO_DEV_ATTR_CHKSUM(ade7759_read_8bit, ADE7759_CHKSUM);
-static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_PHCAL(0644,
                ade7759_read_16bit,
                ade7759_write_16bit,
                ADE7759_PHCAL);
-static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APOS(0644,
                ade7759_read_16bit,
                ade7759_write_16bit,
                ADE7759_APOS);
-static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAGCYC(0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_SAGCYC);
-static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAGLVL(0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_SAGLVL);
-static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_LINECYC(0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_LINECYC);
 static IIO_DEV_ATTR_LENERGY(ade7759_read_40bit, ADE7759_LENERGY);
-static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_PGA_GAIN(0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_GAIN);
-static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(0644,
                ade7759_read_16bit,
                ade7759_write_16bit,
                ADE7759_APGAIN);
-static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CH_OFF(1, 0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_CH1OS);
-static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CH_OFF(2, 0644,
                ade7759_read_8bit,
                ade7759_write_8bit,
                ADE7759_CH2OS);
@@ -458,7 +458,7 @@ static IIO_DEV_ATTR_TEMP_RAW(ade7759_read_8bit);
 static IIO_CONST_ATTR(in_temp_offset, "70 C");
 static IIO_CONST_ATTR(in_temp_scale, "1 C");
 
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAMP_FREQ(0644,
                ade7759_read_frequency,
                ade7759_write_frequency);
 
index d0300045f04ab84efabd0a78e1af19d22b0e773f..4a0abbc10ef6c2f4cd5c6ce0dbf7902024f55e05 100644 (file)
@@ -21,6 +21,7 @@
 #define TIM_CCMR1      0x18    /* Capt/Comp 1 Mode Reg    */
 #define TIM_CCMR2      0x1C    /* Capt/Comp 2 Mode Reg    */
 #define TIM_CCER       0x20    /* Capt/Comp Enable Reg    */
+#define TIM_CNT                0x24    /* Counter                 */
 #define TIM_PSC                0x28    /* Prescaler               */
 #define TIM_ARR                0x2c    /* Auto-Reload Register    */
 #define TIM_CCR1       0x34    /* Capt/Comp Register 1    */
@@ -30,6 +31,7 @@
 #define TIM_BDTR       0x44    /* Break and Dead-Time Reg */
 
 #define TIM_CR1_CEN    BIT(0)  /* Counter Enable          */
+#define TIM_CR1_DIR    BIT(4)  /* Counter Direction       */
 #define TIM_CR1_ARPE   BIT(7)  /* Auto-reload Preload Ena */
 #define TIM_CR2_MMS    (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
 #define TIM_SMCR_SMS   (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
index 509e736d27fba8cf66e389e7f280133a73b2a02d..139872c2e0fe0ffe9517d8f13db65efcd5bc42ff 100644 (file)
 #define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x)           (GENMASK(3, 0) & BIT(x))
 #define SUN6I_GPADC_CTRL1_ADC_CHAN_MASK                        GENMASK(3, 0)
 
+/* TP_CTRL1 bits for sun8i SoCs */
+#define SUN8I_GPADC_CTRL1_CHOP_TEMP_EN                 BIT(8)
+#define SUN8I_GPADC_CTRL1_GPADC_CALI_EN                        BIT(7)
+
 #define SUN4I_GPADC_CTRL2                              0x08
 
 #define SUN4I_GPADC_CTRL2_TP_SENSITIVE_ADJUST(x)       ((GENMASK(3, 0) & (x)) << 28)