Merge tag 'iio-for-4.14a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Jul 2017 04:29:49 +0000 (21:29 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 28 Jul 2017 04:29:49 +0000 (21:29 -0700)
Jonathan writes:

First round of IIO new device support, features and cleanups for the 4.14 cycle.

4 completely new drivers in this set and plenty of other stuff.

One ABI change due to a silly mistake a long time back. Hopefully no
one will notice.  It effects the numerical order of consumer device
channels which was the reverse of the obvious.  It's going the slow
way to allow us some margin to spot if we have broken userspace or
not (seems unlikely)

New Device Support
* ccs811
  - new driver for the Volatile Organic Compounds (VOC) sensor.
* dln2 adc
  - new driver for the ADC on this flexible usb board.
* EP93xx
  - new driver for this Cirrus logic SoC ADC.
* ltc2471
  - new ADC driver support the ltc2471 and ltc2473
* st_accel
  - add trivial table entries to support H3LIS331DL, LIS331DL, LIS3LV02DL.
* st_gyro
  - add L3GD20H support (again) having fixed the various things that were
    broken in the first try.  Includes devicetree binding.
* stm32 dac
  - add support for the DACs in the STM32F4 series

Features
* Documentation
  - add missing power attribute documentation to the ABI docs.
* at91-sama5d2
  - add hardware trigger and buffered capture support with bindings.
  - suspend and resume functionality.
* bmc150
  - support for the BOSC0200 ACPI device id seen on some tablets.
* hdc100x
  - devicetree bindings
  - document supported devices
  - match table and device ids.
* hts221
  - support active low interrupts (with bindings)
  - open drain mode with bindings.
* htu21
  - OF match table and bindings.
* lsm6dsx
  - open drain mode with bindings
* ltc2497
  - add support for board file based consumer mapping.
* ms5367
  - OF match table and bindings.
* mt7622
  - binding document and OF match table.
  - suspend and resume support.
* rpr0521
  - triggered buffer support.
* tsys01
  - OF match table and bindings.

Cleanups and minor fixes
* core
  - fix ordering of IIO channels to entry numbers when using
    iio_map_array_register rather than reversing them.
  - use the new %pOF format specifier rather than full name for the
    device tree nodes.
ad7280a
  - fix potential issue with macro argument reuse.
* ad7766
  - drop a pointless NULL value check as it's done in the gpiod code.
* adis16400
  - unsigned -> unsigned int.
* at91 adc
  - make some init data static to reduce code size.
* at91-sama5d2 ADC
  - make some init data static to reduce code size.
* da311
  - make some init data static to reduce code size.
* hid-sensor-rotation
  - drop an unnecessary static.
* hts221
  - refactor the write_with_mask code.
  - move the BDU configuration to probe time as there is no reason for it
    to change.
  - avoid overwriting reserved data during power-down.  This is a fix, but
    the infrastructure need was too invasive to send it to mainline except
    in a merge window.  It's not a regression as it was always wrong.
  - avoid reconfigure the sampling frequency multiple times by just
    doing it in the write_raw function directly.
  - refactor the power_on/off calls into a set_enable.
  - move the dry-enable logic into trig_set_state as that is the only
    place it was used.
* ina219
  - fix polling of ina226 conversion ready flag.
* imx7d
  - add vendor name in kconfig for consistency with similar parts.
* mcp3422
  - Change initial channel to 0 as it feels more logical.
  - Check for some errors in probe.
* meson-saradc
  - add a check of of_match_device return value.
* mpu3050
  - allow open drain for any interrupt type.
* rockchip adc
  - add check on of_match_device return value.
* sca3000
  - drop a trailing whitespace.
* stm32 adc
  - make array stm32h7_adc_ckmodes_spec static.
* stm32 dac
  - fix an error message.
* stm32 timers
  - fix clock name in docs to match reality after changes.
* st_accel
  - explicit OF table (spi).
  - add missing entries to OF table (i2c).
  - rename of_device_id table to drop the part name.
  - adding missing lis3l02dq entry to bindings.
  - rename H3LIS331DL_DRIVER_NAME to line up with similar entries in driver.
* st_gyro
  - explicit OF table (spi).
* st_magn
  - explicit OF table (spi).
  - enable multiread for lis3mdl.
* st_pressure
  - explicit OF table (spi).
* st_sensors common.
  - move st_sensors_of_i2c_probe and rename to make it available for spi
  drivers.
* tsc3472
  - don't write an extra byte when writing the ATIME register.
  - add a link to the datasheet.
* tsl2x7x - continued staging cleanups
  - add of_match_table.
  - drop redundant power_state sysfs attribute.
  - drop wrapper tsl2x7x_i2c_read.
  - clean up i2c calls made in tsl2x7x_als_calibrate.
  - refactor the read and write _event_value callbacks to handle additional
    elements.
  - use usleep_range instead of mdelay.
  - check return value from tsl2x7x_invoke_change.
* zpa2326
  - add some newline to the end of logging macros.

74 files changed:
Documentation/ABI/testing/sysfs-bus-iio
Documentation/devicetree/bindings/iio/adc/at91-sama5d2_adc.txt
Documentation/devicetree/bindings/iio/adc/mt6577_auxadc.txt
Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
Documentation/devicetree/bindings/iio/humidity/hdc100x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/humidity/hts221.txt
Documentation/devicetree/bindings/iio/humidity/htu21.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
Documentation/devicetree/bindings/iio/pressure/ms5637.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/st-sensors.txt
Documentation/devicetree/bindings/iio/temperature/tsys01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
Documentation/iio/ep93xx_adc.txt [new file with mode: 0644]
drivers/iio/accel/bmc150-accel-i2c.c
drivers/iio/accel/da311.c
drivers/iio/accel/sca3000.c
drivers/iio/accel/st_accel.h
drivers/iio/accel/st_accel_core.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/st_accel_spi.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad7766.c
drivers/iio/adc/at91-sama5d2_adc.c
drivers/iio/adc/at91_adc.c
drivers/iio/adc/dln2-adc.c [new file with mode: 0644]
drivers/iio/adc/ep93xx_adc.c [new file with mode: 0644]
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/ltc2471.c [new file with mode: 0644]
drivers/iio/adc/ltc2497.c
drivers/iio/adc/max9611.c
drivers/iio/adc/mcp3422.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/mt6577_auxadc.c
drivers/iio/adc/rockchip_saradc.c
drivers/iio/adc/stm32-adc-core.c
drivers/iio/adc/ti-ads1015.c
drivers/iio/chemical/Kconfig
drivers/iio/chemical/Makefile
drivers/iio/chemical/ccs811.c [new file with mode: 0644]
drivers/iio/common/st_sensors/st_sensors_core.c
drivers/iio/common/st_sensors/st_sensors_i2c.c
drivers/iio/dac/stm32-dac-core.c
drivers/iio/dac/stm32-dac.c
drivers/iio/gyro/mpu3050-core.c
drivers/iio/gyro/st_gyro.h
drivers/iio/gyro/st_gyro_core.c
drivers/iio/gyro/st_gyro_i2c.c
drivers/iio/gyro/st_gyro_spi.c
drivers/iio/humidity/Kconfig
drivers/iio/humidity/hdc100x.c
drivers/iio/humidity/hts221.h
drivers/iio/humidity/hts221_buffer.c
drivers/iio/humidity/hts221_core.c
drivers/iio/humidity/htu21.c
drivers/iio/imu/adis16400_core.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
drivers/iio/inkern.c
drivers/iio/light/rpr0521.c
drivers/iio/light/tcs3472.c
drivers/iio/magnetometer/ak8975.c
drivers/iio/magnetometer/st_magn_core.c
drivers/iio/magnetometer/st_magn_i2c.c
drivers/iio/magnetometer/st_magn_spi.c
drivers/iio/orientation/hid-sensor-rotation.c
drivers/iio/pressure/ms5637.c
drivers/iio/pressure/st_pressure_i2c.c
drivers/iio/pressure/st_pressure_spi.c
drivers/iio/pressure/zpa2326.c
drivers/iio/temperature/tsys01.c
drivers/staging/iio/adc/ad7280a.c
drivers/staging/iio/light/tsl2x7x.c
include/linux/iio/common/st_sensors.h
include/linux/iio/common/st_sensors_i2c.h

index 2db2cdf42d5417fc218ea29763274503467e7d01..7eead5f97e0295b009c56b1d82d13ecf9e6163e6 100644 (file)
@@ -119,6 +119,15 @@ Description:
                unique to allow association with event codes. Units after
                application of scale and offset are milliamps.
 
+What:          /sys/bus/iio/devices/iio:deviceX/in_powerY_raw
+KernelVersion: 4.5
+Contact:       linux-iio@vger.kernel.org
+Description:
+               Raw (unscaled no bias removal etc.) power measurement from
+               channel Y. The number must always be specified and
+               unique to allow association with event codes. Units after
+               application of scale and offset are milliwatts.
+
 What:          /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
 KernelVersion: 3.2
 Contact:       linux-iio@vger.kernel.org
index 3223684a643b81791454ee48b250a5fba4cb094a..552e7a83951d774bacb1b9e0211b72b766bbb7fa 100644 (file)
@@ -11,6 +11,11 @@ Required properties:
   - atmel,min-sample-rate-hz: Minimum sampling rate, it depends on SoC.
   - atmel,max-sample-rate-hz: Maximum sampling rate, it depends on SoC.
   - atmel,startup-time-ms: Startup time expressed in ms, it depends on SoC.
+  - atmel,trigger-edge-type: One of possible edge types for the ADTRG hardware
+  trigger pin. When the specific edge type is detected, the conversion will
+  start. Possible values are rising, falling, or both.
+  This property uses the IRQ edge types values: IRQ_TYPE_EDGE_RISING ,
+  IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH
 
 Example:
 
@@ -25,4 +30,5 @@ adc: adc@fc030000 {
        atmel,startup-time-ms = <4>;
        vddana-supply = <&vdd_3v3_lp_reg>;
        vref-supply = <&vdd_3v3_lp_reg>;
+       atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>;
 }
index 68c45cbbe3d9f7dcc04c0a00b5d3622273dcef4b..64dc4843c1803a261c6d68efff75ab6cd86608b3 100644 (file)
@@ -12,6 +12,7 @@ for the Thermal Controller which holds a phandle to the AUXADC.
 Required properties:
   - compatible: Should be one of:
     - "mediatek,mt2701-auxadc": For MT2701 family of SoCs
+    - "mediatek,mt7622-auxadc": For MT7622 family of SoCs
     - "mediatek,mt8173-auxadc": For MT8173 family of SoCs
   - reg: Address range of the AUXADC unit.
   - clocks: Should contain a clock specifier for each entry in clock-names
index bcee71f808d00d96dac04954f7ba464282460236..bf2925c671c68f7a357e4a0f125af6713c4956aa 100644 (file)
@@ -10,7 +10,9 @@ current.
 Contents of a stm32 dac root node:
 -----------------------------------
 Required properties:
-- compatible: Must be "st,stm32h7-dac-core".
+- compatible: Should be one of:
+  "st,stm32f4-dac-core"
+  "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)
diff --git a/Documentation/devicetree/bindings/iio/humidity/hdc100x.txt b/Documentation/devicetree/bindings/iio/humidity/hdc100x.txt
new file mode 100644 (file)
index 0000000..c52333b
--- /dev/null
@@ -0,0 +1,17 @@
+* HDC100x temperature + humidity sensors
+
+Required properties:
+  - compatible: Should contain one of the following:
+       ti,hdc1000
+       ti,hdc1008
+       ti,hdc1010
+       ti,hdc1050
+       ti,hdc1080
+  - reg: i2c address of the sensor
+
+Example:
+
+hdc100x@40 {
+       compatible = "ti,hdc1000";
+       reg = <0x40>;
+};
index b20ab9c12080e74877937c4b90c5955c283941a1..10adeb0d703d486694468ae15ea906849a8afaa9 100644 (file)
@@ -5,9 +5,18 @@ Required properties:
 - reg: i2c address of the sensor / spi cs line
 
 Optional properties:
+- drive-open-drain: the interrupt/data ready line will be configured
+  as open drain, which is useful if several sensors share the same
+  interrupt line. This is a boolean property.
+  If the requested interrupt is configured as IRQ_TYPE_LEVEL_HIGH or
+  IRQ_TYPE_EDGE_RISING a pull-down resistor is needed to drive the line
+  when it is not active, whereas a pull-up one is needed when interrupt
+  line is configured as IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_EDGE_FALLING.
+  Refer to pinctrl/pinctrl-bindings.txt for the property description.
 - interrupt-parent: should be the phandle for the interrupt controller
 - interrupts: interrupt mapping for IRQ. It should be configured with
-  flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
+  flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
+  IRQ_TYPE_EDGE_FALLING.
 
   Refer to interrupt-controller/interrupts.txt for generic interrupt
   client node bindings.
diff --git a/Documentation/devicetree/bindings/iio/humidity/htu21.txt b/Documentation/devicetree/bindings/iio/humidity/htu21.txt
new file mode 100644 (file)
index 0000000..97d7963
--- /dev/null
@@ -0,0 +1,13 @@
+*HTU21 - Measurement-Specialties htu21 temperature & humidity sensor and humidity part of MS8607 sensor
+
+Required properties:
+
+       - compatible: should be "meas,htu21" or "meas,ms8607-humidity"
+       - reg: I2C address of the sensor
+
+Example:
+
+htu21@40 {
+       compatible = "meas,htu21";
+       reg = <0x40>;
+};
index 6f28ff55f3ec2d58949b572d1d16d8dbf96f194e..1ff1af799c76f3dcad89ee065bbe0f423369f6d7 100644 (file)
@@ -11,6 +11,14 @@ Required properties:
 Optional properties:
 - st,drdy-int-pin: the pin on the package that will be used to signal
   "data ready" (valid values: 1 or 2).
+- drive-open-drain: the interrupt/data ready line will be configured
+  as open drain, which is useful if several sensors share the same
+  interrupt line. This is a boolean property.
+  (This binding is taken from pinctrl/pinctrl-bindings.txt)
+  If the requested interrupt is configured as IRQ_TYPE_LEVEL_HIGH or
+  IRQ_TYPE_EDGE_RISING a pull-down resistor is needed to drive the line
+  when it is not active, whereas a pull-up one is needed when interrupt
+  line is configured as IRQ_TYPE_LEVEL_LOW or IRQ_TYPE_EDGE_FALLING.
 - interrupt-parent: should be the phandle for the interrupt controller
 - interrupts: interrupt mapping for IRQ. It should be configured with
   flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
diff --git a/Documentation/devicetree/bindings/iio/pressure/ms5637.txt b/Documentation/devicetree/bindings/iio/pressure/ms5637.txt
new file mode 100644 (file)
index 0000000..1f43ffa
--- /dev/null
@@ -0,0 +1,17 @@
+* MS5637 - Measurement-Specialties MS5637, MS5805, MS5837 and MS8607 pressure & temperature sensor
+
+Required properties:
+
+       -compatible: should be one of the following
+               meas,ms5637
+               meas,ms5805
+               meas,ms5837
+               meas,ms8607-temppressure
+       -reg: I2C address of the sensor
+
+Example:
+
+ms5637@76 {
+       compatible = "meas,ms5637";
+       reg = <0x76>;
+};
index eaa8fbba34e2eb89f971eae2fdf5af136db0f751..1e305f61f3df4885d48ff1a3a0d9cead8ce0e458 100644 (file)
@@ -45,6 +45,7 @@ Accelerometers:
 - st,lis2dh12-accel
 - st,h3lis331dl-accel
 - st,lng2dm-accel
+- st,lis3l02dq
 
 Gyroscopes:
 - st,l3g4200d-gyro
@@ -52,6 +53,7 @@ Gyroscopes:
 - st,lsm330dl-gyro
 - st,lsm330dlc-gyro
 - st,l3gd20-gyro
+- st,l3gd20h-gyro
 - st,l3g4is-gyro
 - st,lsm330-gyro
 - st,lsm9ds0-gyro
diff --git a/Documentation/devicetree/bindings/iio/temperature/tsys01.txt b/Documentation/devicetree/bindings/iio/temperature/tsys01.txt
new file mode 100644 (file)
index 0000000..0d5cc55
--- /dev/null
@@ -0,0 +1,19 @@
+* TSYS01 - Measurement Specialties temperature sensor
+
+Required properties:
+
+       - compatible: should be "meas,tsys01"
+       - reg: I2C address of the sensor (changeable via CSB pin)
+
+               ------------------------
+               | CSB | Device Address |
+               ------------------------
+                  1         0x76
+                  0         0x77
+
+Example:
+
+tsys01@76 {
+       compatible = "meas,tsys01";
+       reg = <0x76>;
+};
index 55a653d153034f21f6499dbb8dee7e6e6a79bbf5..6abc755dbf94f80a3acdc9c9c8d2f85d0c988b81 100644 (file)
@@ -14,7 +14,7 @@ Example:
                compatible = "st,stm32-timers";
                reg = <0x40010000 0x400>;
                clocks = <&rcc 0 160>;
-               clock-names = "clk_int";
+               clock-names = "int";
 
                timer@0 {
                        compatible = "st,stm32-timer-trigger";
diff --git a/Documentation/iio/ep93xx_adc.txt b/Documentation/iio/ep93xx_adc.txt
new file mode 100644 (file)
index 0000000..23053e7
--- /dev/null
@@ -0,0 +1,29 @@
+Cirrus Logic EP93xx ADC driver.
+
+1. Overview
+
+The driver is intended to work on both low-end (EP9301, EP9302) devices with
+5-channel ADC and high-end (EP9307, EP9312, EP9315) devices with 10-channel
+touchscreen/ADC module.
+
+2. Channel numbering
+
+Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
+EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numbering is
+not defined. So the last three are numbered randomly, let's say.
+
+Assuming ep93xx_adc is IIO device0, you'd find the following entries under
+/sys/bus/iio/devices/iio:device0/:
+
+  +-----------------+---------------+
+  | sysfs entry     | ball/pin name |
+  +-----------------+---------------+
+  | in_voltage0_raw | YM            |
+  | in_voltage1_raw | SXP           |
+  | in_voltage2_raw | SXM           |
+  | in_voltage3_raw | SYP           |
+  | in_voltage4_raw | SYM           |
+  | in_voltage5_raw | XP            |
+  | in_voltage6_raw | XM            |
+  | in_voltage7_raw | YP            |
+  +-----------------+---------------+
index 8ca8041267ef91ecbde707b05e6b3d6b82b7a2ab..f85014fbaa1297ea32e3a847df5fb8c6ff4f9923 100644 (file)
@@ -64,6 +64,7 @@ static const struct acpi_device_id bmc150_accel_acpi_match[] = {
        {"BMA250E",     bma250e},
        {"BMA222E",     bma222e},
        {"BMA0280",     bma280},
+       {"BOSC0200"},
        { },
 };
 MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match);
index 537cfa8b6edfc77a60ae0f544f3cb364f51bbb3c..c0c1620d2a2f3a8b80d7f290d7b10cb445e269fb 100644 (file)
@@ -139,7 +139,7 @@ static int da311_register_mask_write(struct i2c_client *client, u16 addr,
 /* Init sequence taken from the android driver */
 static int da311_reset(struct i2c_client *client)
 {
-       const struct {
+       static const struct {
                u16 addr;
                u8 mask;
                u8 data;
index cb1d83fa19a06689c2c4f6299690912bcf9839e3..39ab210c44f69b5e273a202cb6d61834f64bf96d 100644 (file)
@@ -36,7 +36,7 @@
 #define   SCA3000_LOCKED                               BIT(5)
 #define   SCA3000_EEPROM_CS_ERROR                      BIT(1)
 #define   SCA3000_SPI_FRAME_ERROR                      BIT(0)
+
 /* All reads done using register decrement so no need to directly access LSBs */
 #define SCA3000_REG_X_MSB_ADDR                         0x05
 #define SCA3000_REG_Y_MSB_ADDR                         0x07
@@ -74,7 +74,7 @@
 #define SCA3000_REG_INT_STATUS_ADDR                    0x16
 #define   SCA3000_REG_INT_STATUS_THREE_QUARTERS                BIT(7)
 #define   SCA3000_REG_INT_STATUS_HALF                  BIT(6)
-       
+
 #define SCA3000_INT_STATUS_FREE_FALL                   BIT(3)
 #define SCA3000_INT_STATUS_Y_TRIGGER                   BIT(2)
 #define SCA3000_INT_STATUS_X_TRIGGER                   BIT(1)
 
 #define SCA3000_REG_INT_MASK_ADDR                      0x21
 #define   SCA3000_REG_INT_MASK_PROT_MASK               0x1C
+
 #define   SCA3000_REG_INT_MASK_RING_THREE_QUARTER      BIT(7)
 #define   SCA3000_REG_INT_MASK_RING_HALF               BIT(6)
 
index 3ad44ce7ae8217cb2844ef8c874b9c47fb08da5a..0fe521609a3a78ec33d28e0d96a074c1f79c4668 100644 (file)
@@ -29,10 +29,13 @@ enum st_accel_type {
        LIS2DH12,
        LIS3L02DQ,
        LNG2DM,
+       H3LIS331DL,
+       LIS331DL,
+       LIS3LV02DL,
        ST_ACCEL_MAX,
 };
 
-#define H3LIS331DL_DRIVER_NAME         "h3lis331dl_accel"
+#define H3LIS331DL_ACCEL_DEV_NAME      "h3lis331dl_accel"
 #define LIS3LV02DL_ACCEL_DEV_NAME      "lis3lv02dl_accel"
 #define LSM303DLHC_ACCEL_DEV_NAME      "lsm303dlhc_accel"
 #define LIS3DH_ACCEL_DEV_NAME          "lis3dh"
index 07d1489cd457a6b5445b8b3ba35dad95b1792acc..c7709494bed3ce8f7618048eb8d45f605ffdd968 100644 (file)
@@ -444,7 +444,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                .wai = 0x32,
                .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
                .sensors_supported = {
-                       [0] = H3LIS331DL_DRIVER_NAME,
+                       [0] = H3LIS331DL_ACCEL_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
                .odr = {
index 543f0ad7fd7e383922201ab258ade3761c766f5a..18cafb9f2468d8316ec58314112f8abcdca02534 100644 (file)
@@ -84,7 +84,7 @@ static const struct of_device_id st_accel_of_match[] = {
        },
        {
                .compatible = "st,h3lis331dl-accel",
-               .data = H3LIS331DL_DRIVER_NAME,
+               .data = H3LIS331DL_ACCEL_DEV_NAME,
        },
        {
                .compatible = "st,lis3l02dq",
@@ -126,6 +126,9 @@ static const struct i2c_device_id st_accel_id_table[] = {
        { LIS2DH12_ACCEL_DEV_NAME, LIS2DH12 },
        { LIS3L02DQ_ACCEL_DEV_NAME, LIS3L02DQ },
        { LNG2DM_ACCEL_DEV_NAME, LNG2DM },
+       { H3LIS331DL_ACCEL_DEV_NAME, H3LIS331DL },
+       { LIS331DL_ACCEL_DEV_NAME, LIS331DL },
+       { LIS3LV02DL_ACCEL_DEV_NAME, LIS3LV02DL },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
@@ -144,7 +147,8 @@ static int st_accel_i2c_probe(struct i2c_client *client,
        adata = iio_priv(indio_dev);
 
        if (client->dev.of_node) {
-               st_sensors_of_i2c_probe(client, st_accel_of_match);
+               st_sensors_of_name_probe(&client->dev, st_accel_of_match,
+                                        client->name, sizeof(client->name));
        } else if (ACPI_HANDLE(&client->dev)) {
                ret = st_sensors_match_acpi_device(&client->dev);
                if ((ret < 0) || (ret >= ST_ACCEL_MAX))
index 1a867f5563a4c741b8918af8a9d13170883e2642..915fa49085f7076b74de72e717e1a6858e504240 100644 (file)
 #include <linux/iio/common/st_sensors_spi.h>
 #include "st_accel.h"
 
+#ifdef CONFIG_OF
+/*
+ * For new single-chip sensors use <device_name> as compatible string.
+ * For old single-chip devices keep <device_name>-accel to maintain
+ * compatibility
+ */
+static const struct of_device_id st_accel_of_match[] = {
+       {
+               /* An older compatible */
+               .compatible = "st,lis302dl-spi",
+               .data = LIS3LV02DL_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lis3lv02dl-accel",
+               .data = LIS3LV02DL_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lis3dh-accel",
+               .data = LIS3DH_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330d-accel",
+               .data = LSM330D_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330dl-accel",
+               .data = LSM330DL_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330dlc-accel",
+               .data = LSM330DLC_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lis331dlh-accel",
+               .data = LIS331DLH_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330-accel",
+               .data = LSM330_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm303agr-accel",
+               .data = LSM303AGR_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lis2dh12-accel",
+               .data = LIS2DH12_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lis3l02dq",
+               .data = LIS3L02DQ_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lng2dm-accel",
+               .data = LNG2DM_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,h3lis331dl-accel",
+               .data = H3LIS331DL_ACCEL_DEV_NAME,
+       },
+       {
+               .compatible = "st,lis331dl-accel",
+               .data = LIS331DL_ACCEL_DEV_NAME,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, st_accel_of_match);
+#else
+#define st_accel_of_match      NULL
+#endif
+
 static int st_accel_spi_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
@@ -30,6 +101,8 @@ static int st_accel_spi_probe(struct spi_device *spi)
 
        adata = iio_priv(indio_dev);
 
+       st_sensors_of_name_probe(&spi->dev, st_accel_of_match,
+                                spi->modalias, sizeof(spi->modalias));
        st_sensors_spi_configure(indio_dev, spi, adata);
 
        err = st_accel_common_probe(indio_dev);
@@ -57,22 +130,17 @@ static const struct spi_device_id st_accel_id_table[] = {
        { LIS2DH12_ACCEL_DEV_NAME },
        { LIS3L02DQ_ACCEL_DEV_NAME },
        { LNG2DM_ACCEL_DEV_NAME },
+       { H3LIS331DL_ACCEL_DEV_NAME },
+       { LIS331DL_ACCEL_DEV_NAME },
+       { LIS3LV02DL_ACCEL_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_accel_id_table);
 
-#ifdef CONFIG_OF
-static const struct of_device_id lis302dl_spi_dt_ids[] = {
-       { .compatible = "st,lis302dl-spi" },
-       {}
-};
-MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids);
-#endif
-
 static struct spi_driver st_accel_driver = {
        .driver = {
                .name = "st-accel-spi",
-               .of_match_table = of_match_ptr(lis302dl_spi_dt_ids),
+               .of_match_table = of_match_ptr(st_accel_of_match),
        },
        .probe = st_accel_spi_probe,
        .remove = st_accel_spi_remove,
index 614fa41559b13059e715095efb99e0ffecc76578..e4eeebac52978c6c3188491a43273299ffb094a5 100644 (file)
@@ -239,6 +239,15 @@ config DA9150_GPADC
          To compile this driver as a module, choose M here: the module will be
          called berlin2-adc.
 
+config DLN2_ADC
+       tristate "Diolan DLN-2 ADC driver support"
+       depends on MFD_DLN2
+       help
+         Say yes here to build support for Diolan DLN-2 ADC.
+
+         This driver can also be built as a module. If so, the module will be
+         called adc_dln2.
+
 config ENVELOPE_DETECTOR
        tristate "Envelope detector using a DAC and a comparator"
        depends on OF
@@ -249,6 +258,17 @@ config ENVELOPE_DETECTOR
          To compile this driver as a module, choose M here: the module will be
          called envelope-detector.
 
+config EP93XX_ADC
+       tristate "Cirrus Logic EP93XX ADC driver"
+       depends on ARCH_EP93XX
+       help
+         Driver for the ADC module on the EP93XX series of SoC from Cirrus Logic.
+         It's recommended to switch on CONFIG_HIGH_RES_TIMERS option, in this
+         case driver will reduce its CPU usage by 90% in some use cases.
+
+         To compile this driver as a module, choose M here: the module will be
+         called ep93xx_adc.
+
 config EXYNOS_ADC
        tristate "Exynos ADC driver support"
        depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
@@ -322,7 +342,7 @@ config INA2XX_ADC
          This driver is mutually exclusive with the HWMON version.
 
 config IMX7D_ADC
-       tristate "IMX7D ADC driver"
+       tristate "Freescale IMX7D ADC driver"
        depends on ARCH_MXC || COMPILE_TEST
        depends on HAS_IOMEM
        help
@@ -362,6 +382,16 @@ config LPC32XX_ADC
          activate only one via device tree selection.  Provides direct access
          via sysfs.
 
+config LTC2471
+       tristate "Linear Technology LTC2471 and LTC2473 ADC driver"
+       depends on I2C
+       help
+         Say yes here to build support for Linear Technology LTC2471 and
+         LTC2473 16-bit I2C ADC.
+
+         This driver can also be built as a module. If so, the module will
+         be called ltc2471.
+
 config LTC2485
        tristate "Linear Technology LTC2485 ADC driver"
        depends on I2C
index b546736a55413a1848098b6ad6a778130baf9af7..9874e05f52d74f77267c15e9f8ea4b32d59f252c 100644 (file)
@@ -24,7 +24,9 @@ obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
 obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_CPCAP_ADC) += cpcap-adc.o
 obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
+obj-$(CONFIG_DLN2_ADC) += dln2-adc.o
 obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o
+obj-$(CONFIG_EP93XX_ADC) += ep93xx_adc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
 obj-$(CONFIG_HI8435) += hi8435.o
@@ -34,6 +36,7 @@ obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
 obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_LTC2471) += ltc2471.o
 obj-$(CONFIG_LTC2485) += ltc2485.o
 obj-$(CONFIG_LTC2497) += ltc2497.o
 obj-$(CONFIG_MAX1027) += max1027.o
index 75cca42b6e70cb548e4e4a60a3e21f4b3ba9f301..ce45037295d88932abd579a20d40cd28e0e4d652 100644 (file)
@@ -103,8 +103,7 @@ static int ad7766_preenable(struct iio_dev *indio_dev)
                return ret;
        }
 
-       if (ad7766->pd_gpio)
-               gpiod_set_value(ad7766->pd_gpio, 0);
+       gpiod_set_value(ad7766->pd_gpio, 0);
 
        return 0;
 }
@@ -113,8 +112,7 @@ static int ad7766_postdisable(struct iio_dev *indio_dev)
 {
        struct ad7766 *ad7766 = iio_priv(indio_dev);
 
-       if (ad7766->pd_gpio)
-               gpiod_set_value(ad7766->pd_gpio, 1);
+       gpiod_set_value(ad7766->pd_gpio, 1);
 
        /*
         * The PD pin is synchronous to the clock, so give it some time to
index e10dca3ed74be4633e7d9cccb28200dca685ee90..bc5b38e3a147e6559e4863bfc39e21115648d7b9 100644 (file)
 #include <linux/wait.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/regulator/consumer.h>
 
 /* Control Register */
 #define AT91_SAMA5D2_PRESSR    0xbc
 /* Trigger Register */
 #define AT91_SAMA5D2_TRGR      0xc0
+/* Mask for TRGMOD field of TRGR register */
+#define AT91_SAMA5D2_TRGR_TRGMOD_MASK GENMASK(2, 0)
+/* No trigger, only software trigger can start conversions */
+#define AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER 0
+/* Trigger Mode external trigger rising edge */
+#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_RISE 1
+/* Trigger Mode external trigger falling edge */
+#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL 2
+/* Trigger Mode external trigger any edge */
+#define AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY 3
+
 /* Correction Select Register */
 #define AT91_SAMA5D2_COSR      0xd0
 /* Correction Value Register */
 /* Version Register */
 #define AT91_SAMA5D2_VERSION   0xfc
 
+#define AT91_SAMA5D2_HW_TRIG_CNT 3
+#define AT91_SAMA5D2_SINGLE_CHAN_CNT 12
+#define AT91_SAMA5D2_DIFF_CHAN_CNT 6
+
+/*
+ * Maximum number of bytes to hold conversion from all channels
+ * plus the timestamp
+ */
+#define AT91_BUFFER_MAX_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT +         \
+                               AT91_SAMA5D2_DIFF_CHAN_CNT) * 2 + 8)
+
+#define AT91_BUFFER_MAX_HWORDS (AT91_BUFFER_MAX_BYTES / 2)
+
 #define AT91_SAMA5D2_CHAN_SINGLE(num, addr)                            \
        {                                                               \
                .type = IIO_VOLTAGE,                                    \
                .channel = num,                                         \
                .address = addr,                                        \
+               .scan_index = num,                                      \
                .scan_type = {                                          \
                        .sign = 'u',                                    \
                        .realbits = 12,                                 \
+                       .storagebits = 16,                              \
                },                                                      \
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
                .channel = num,                                         \
                .channel2 = num2,                                       \
                .address = addr,                                        \
+               .scan_index = num + AT91_SAMA5D2_SINGLE_CHAN_CNT,       \
                .scan_type = {                                          \
                        .sign = 's',                                    \
                        .realbits = 12,                                 \
+                       .storagebits = 16,                              \
                },                                                      \
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
@@ -188,6 +221,12 @@ struct at91_adc_soc_info {
        unsigned                        max_sample_rate;
 };
 
+struct at91_adc_trigger {
+       char                            *name;
+       unsigned int                    trgmod_value;
+       unsigned int                    edge_type;
+};
+
 struct at91_adc_state {
        void __iomem                    *base;
        int                             irq;
@@ -195,11 +234,14 @@ struct at91_adc_state {
        struct regulator                *reg;
        struct regulator                *vref;
        int                             vref_uv;
+       struct iio_trigger              *trig;
+       const struct at91_adc_trigger   *selected_trig;
        const struct iio_chan_spec      *chan;
        bool                            conversion_done;
        u32                             conversion_value;
        struct at91_adc_soc_info        soc_info;
        wait_queue_head_t               wq_data_available;
+       u16                             buffer[AT91_BUFFER_MAX_HWORDS];
        /*
         * lock to prevent concurrent 'single conversion' requests through
         * sysfs.
@@ -207,6 +249,24 @@ struct at91_adc_state {
        struct mutex                    lock;
 };
 
+static const struct at91_adc_trigger at91_adc_trigger_list[] = {
+       {
+               .name = "external_rising",
+               .trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_RISE,
+               .edge_type = IRQ_TYPE_EDGE_RISING,
+       },
+       {
+               .name = "external_falling",
+               .trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_FALL,
+               .edge_type = IRQ_TYPE_EDGE_FALLING,
+       },
+       {
+               .name = "external_any",
+               .trgmod_value = AT91_SAMA5D2_TRGR_TRGMOD_EXT_TRIG_ANY,
+               .edge_type = IRQ_TYPE_EDGE_BOTH,
+       },
+};
+
 static const struct iio_chan_spec at91_adc_channels[] = {
        AT91_SAMA5D2_CHAN_SINGLE(0, 0x50),
        AT91_SAMA5D2_CHAN_SINGLE(1, 0x54),
@@ -226,12 +286,132 @@ static const struct iio_chan_spec at91_adc_channels[] = {
        AT91_SAMA5D2_CHAN_DIFF(6, 7, 0x68),
        AT91_SAMA5D2_CHAN_DIFF(8, 9, 0x70),
        AT91_SAMA5D2_CHAN_DIFF(10, 11, 0x78),
+       IIO_CHAN_SOFT_TIMESTAMP(AT91_SAMA5D2_SINGLE_CHAN_CNT
+                               + AT91_SAMA5D2_DIFF_CHAN_CNT + 1),
+};
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+       struct iio_dev *indio = iio_trigger_get_drvdata(trig);
+       struct at91_adc_state *st = iio_priv(indio);
+       u32 status = at91_adc_readl(st, AT91_SAMA5D2_TRGR);
+       u8 bit;
+
+       /* clear TRGMOD */
+       status &= ~AT91_SAMA5D2_TRGR_TRGMOD_MASK;
+
+       if (state)
+               status |= st->selected_trig->trgmod_value;
+
+       /* set/unset hw trigger */
+       at91_adc_writel(st, AT91_SAMA5D2_TRGR, status);
+
+       for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
+               struct iio_chan_spec const *chan = indio->channels + bit;
+
+               if (state) {
+                       at91_adc_writel(st, AT91_SAMA5D2_CHER,
+                                       BIT(chan->channel));
+                       at91_adc_writel(st, AT91_SAMA5D2_IER,
+                                       BIT(chan->channel));
+               } else {
+                       at91_adc_writel(st, AT91_SAMA5D2_IDR,
+                                       BIT(chan->channel));
+                       at91_adc_writel(st, AT91_SAMA5D2_CHDR,
+                                       BIT(chan->channel));
+               }
+       }
+
+       return 0;
+}
+
+static int at91_adc_reenable_trigger(struct iio_trigger *trig)
+{
+       struct iio_dev *indio = iio_trigger_get_drvdata(trig);
+       struct at91_adc_state *st = iio_priv(indio);
+
+       enable_irq(st->irq);
+
+       /* Needed to ACK the DRDY interruption */
+       at91_adc_readl(st, AT91_SAMA5D2_LCDR);
+       return 0;
+}
+
+static const struct iio_trigger_ops at91_adc_trigger_ops = {
+       .owner = THIS_MODULE,
+       .set_trigger_state = &at91_adc_configure_trigger,
+       .try_reenable = &at91_adc_reenable_trigger,
 };
 
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio,
+                                                    char *trigger_name)
+{
+       struct iio_trigger *trig;
+       int ret;
+
+       trig = devm_iio_trigger_alloc(&indio->dev, "%s-dev%d-%s", indio->name,
+                                     indio->id, trigger_name);
+       if (!trig)
+               return NULL;
+
+       trig->dev.parent = indio->dev.parent;
+       iio_trigger_set_drvdata(trig, indio);
+       trig->ops = &at91_adc_trigger_ops;
+
+       ret = devm_iio_trigger_register(&indio->dev, trig);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return trig;
+}
+
+static int at91_adc_trigger_init(struct iio_dev *indio)
+{
+       struct at91_adc_state *st = iio_priv(indio);
+
+       st->trig = at91_adc_allocate_trigger(indio, st->selected_trig->name);
+       if (IS_ERR(st->trig)) {
+               dev_err(&indio->dev,
+                       "could not allocate trigger\n");
+               return PTR_ERR(st->trig);
+       }
+
+       return 0;
+}
+
+static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio = pf->indio_dev;
+       struct at91_adc_state *st = iio_priv(indio);
+       int i = 0;
+       u8 bit;
+
+       for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
+               struct iio_chan_spec const *chan = indio->channels + bit;
+
+               st->buffer[i] = at91_adc_readl(st, chan->address);
+               i++;
+       }
+
+       iio_push_to_buffers_with_timestamp(indio, st->buffer, pf->timestamp);
+
+       iio_trigger_notify_done(indio->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int at91_adc_buffer_init(struct iio_dev *indio)
+{
+       return devm_iio_triggered_buffer_setup(&indio->dev, indio,
+                       &iio_pollfunc_store_time,
+                       &at91_adc_trigger_handler, NULL);
+}
+
 static unsigned at91_adc_startup_time(unsigned startup_time_min,
                                      unsigned adc_clk_khz)
 {
-       const unsigned startup_lookup[] = {
+       static const unsigned int startup_lookup[] = {
                  0,   8,  16,  24,
                 64,  80,  96, 112,
                512, 576, 640, 704,
@@ -293,14 +473,18 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
        u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
        u32 imr = at91_adc_readl(st, AT91_SAMA5D2_IMR);
 
-       if (status & imr) {
+       if (!(status & imr))
+               return IRQ_NONE;
+
+       if (iio_buffer_enabled(indio)) {
+               disable_irq_nosync(irq);
+               iio_trigger_poll(indio->trig);
+       } else {
                st->conversion_value = at91_adc_readl(st, st->chan->address);
                st->conversion_done = true;
                wake_up_interruptible(&st->wq_data_available);
-               return IRQ_HANDLED;
        }
-
-       return IRQ_NONE;
+       return IRQ_HANDLED;
 }
 
 static int at91_adc_read_raw(struct iio_dev *indio_dev,
@@ -313,6 +497,11 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
+               /* we cannot use software trigger if hw trigger enabled */
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
                mutex_lock(&st->lock);
 
                st->chan = chan;
@@ -344,6 +533,8 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
                at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
 
                mutex_unlock(&st->lock);
+
+               iio_device_release_direct_mode(indio_dev);
                return ret;
 
        case IIO_CHAN_INFO_SCALE:
@@ -386,12 +577,27 @@ static const struct iio_info at91_adc_info = {
        .driver_module = THIS_MODULE,
 };
 
+static void at91_adc_hw_init(struct at91_adc_state *st)
+{
+       at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
+       at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
+       /*
+        * Transfer field must be set to 2 according to the datasheet and
+        * allows different analog settings for each channel.
+        */
+       at91_adc_writel(st, AT91_SAMA5D2_MR,
+                       AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
+
+       at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
+}
+
 static int at91_adc_probe(struct platform_device *pdev)
 {
        struct iio_dev *indio_dev;
        struct at91_adc_state *st;
        struct resource *res;
-       int ret;
+       int ret, i;
+       u32 edge_type;
 
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st));
        if (!indio_dev)
@@ -432,6 +638,27 @@ static int at91_adc_probe(struct platform_device *pdev)
                return ret;
        }
 
+       ret = of_property_read_u32(pdev->dev.of_node,
+                                  "atmel,trigger-edge-type", &edge_type);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "invalid or missing value for atmel,trigger-edge-type\n");
+               return ret;
+       }
+
+       st->selected_trig = NULL;
+
+       for (i = 0; i < AT91_SAMA5D2_HW_TRIG_CNT; i++)
+               if (at91_adc_trigger_list[i].edge_type == edge_type) {
+                       st->selected_trig = &at91_adc_trigger_list[i];
+                       break;
+               }
+
+       if (!st->selected_trig) {
+               dev_err(&pdev->dev, "invalid external trigger edge value\n");
+               return -EINVAL;
+       }
+
        init_waitqueue_head(&st->wq_data_available);
        mutex_init(&st->lock);
 
@@ -482,16 +709,7 @@ static int at91_adc_probe(struct platform_device *pdev)
                goto vref_disable;
        }
 
-       at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
-       at91_adc_writel(st, AT91_SAMA5D2_IDR, 0xffffffff);
-       /*
-        * Transfer field must be set to 2 according to the datasheet and
-        * allows different analog settings for each channel.
-        */
-       at91_adc_writel(st, AT91_SAMA5D2_MR,
-                       AT91_SAMA5D2_MR_TRANSFER(2) | AT91_SAMA5D2_MR_ANACH);
-
-       at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
+       at91_adc_hw_init(st);
 
        ret = clk_prepare_enable(st->per_clk);
        if (ret)
@@ -499,10 +717,25 @@ static int at91_adc_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, indio_dev);
 
+       ret = at91_adc_buffer_init(indio_dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "couldn't initialize the buffer.\n");
+               goto per_clk_disable_unprepare;
+       }
+
+       ret = at91_adc_trigger_init(indio_dev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "couldn't setup the triggers.\n");
+               goto per_clk_disable_unprepare;
+       }
+
        ret = iio_device_register(indio_dev);
        if (ret < 0)
                goto per_clk_disable_unprepare;
 
+       dev_info(&pdev->dev, "setting up trigger as %s\n",
+                st->selected_trig->name);
+
        dev_info(&pdev->dev, "version: %x\n",
                 readl_relaxed(st->base + AT91_SAMA5D2_VERSION));
 
@@ -532,6 +765,69 @@ static int at91_adc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static __maybe_unused int at91_adc_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev =
+                       platform_get_drvdata(to_platform_device(dev));
+       struct at91_adc_state *st = iio_priv(indio_dev);
+
+       /*
+        * Do a sofware reset of the ADC before we go to suspend.
+        * this will ensure that all pins are free from being muxed by the ADC
+        * and can be used by for other devices.
+        * Otherwise, ADC will hog them and we can't go to suspend mode.
+        */
+       at91_adc_writel(st, AT91_SAMA5D2_CR, AT91_SAMA5D2_CR_SWRST);
+
+       clk_disable_unprepare(st->per_clk);
+       regulator_disable(st->vref);
+       regulator_disable(st->reg);
+
+       return pinctrl_pm_select_sleep_state(dev);
+}
+
+static __maybe_unused int at91_adc_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev =
+                       platform_get_drvdata(to_platform_device(dev));
+       struct at91_adc_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = pinctrl_pm_select_default_state(dev);
+       if (ret)
+               goto resume_failed;
+
+       ret = regulator_enable(st->reg);
+       if (ret)
+               goto resume_failed;
+
+       ret = regulator_enable(st->vref);
+       if (ret)
+               goto reg_disable_resume;
+
+       ret = clk_prepare_enable(st->per_clk);
+       if (ret)
+               goto vref_disable_resume;
+
+       at91_adc_hw_init(st);
+
+       /* reconfiguring trigger hardware state */
+       if (iio_buffer_enabled(indio_dev))
+               at91_adc_configure_trigger(st->trig, true);
+
+       return 0;
+
+vref_disable_resume:
+       regulator_disable(st->vref);
+reg_disable_resume:
+       regulator_disable(st->reg);
+resume_failed:
+       dev_err(&indio_dev->dev, "failed to resume\n");
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(at91_adc_pm_ops, at91_adc_suspend, at91_adc_resume);
+
 static const struct of_device_id at91_adc_dt_match[] = {
        {
                .compatible = "atmel,sama5d2-adc",
@@ -547,6 +843,7 @@ static struct platform_driver at91_adc_driver = {
        .driver = {
                .name = "at91-sama5d2_adc",
                .of_match_table = at91_adc_dt_match,
+               .pm = &at91_adc_pm_ops,
        },
 };
 module_platform_driver(at91_adc_driver)
index 34b928cefeedbaff6932de3eba457930e3afd297..15109728cae79dde2ca248db0f92a97cc62f1849 100644 (file)
@@ -799,7 +799,7 @@ static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz)
         * For sama5d3x and at91sam9x5, the formula changes to:
         * Startup Time = <lookup_table_value> / ADC Clock
         */
-       const int startup_lookup[] = {
+       static const int startup_lookup[] = {
                0,   8,   16,  24,
                64,  80,  96,  112,
                512, 576, 640, 704,
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
new file mode 100644 (file)
index 0000000..ab8d6ae
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * Driver for the Diolan DLN-2 USB-ADC adapter
+ *
+ * Copyright (c) 2017 Jack Andersen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/dln2.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#define DLN2_ADC_MOD_NAME "dln2-adc"
+
+#define DLN2_ADC_ID             0x06
+
+#define DLN2_ADC_GET_CHANNEL_COUNT     DLN2_CMD(0x01, DLN2_ADC_ID)
+#define DLN2_ADC_ENABLE                        DLN2_CMD(0x02, DLN2_ADC_ID)
+#define DLN2_ADC_DISABLE               DLN2_CMD(0x03, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_ENABLE                DLN2_CMD(0x05, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_DISABLE       DLN2_CMD(0x06, DLN2_ADC_ID)
+#define DLN2_ADC_SET_RESOLUTION                DLN2_CMD(0x08, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_GET_VAL       DLN2_CMD(0x0A, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_GET_ALL_VAL   DLN2_CMD(0x0B, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_SET_CFG       DLN2_CMD(0x0C, DLN2_ADC_ID)
+#define DLN2_ADC_CHANNEL_GET_CFG       DLN2_CMD(0x0D, DLN2_ADC_ID)
+#define DLN2_ADC_CONDITION_MET_EV      DLN2_CMD(0x10, DLN2_ADC_ID)
+
+#define DLN2_ADC_EVENT_NONE            0
+#define DLN2_ADC_EVENT_BELOW           1
+#define DLN2_ADC_EVENT_LEVEL_ABOVE     2
+#define DLN2_ADC_EVENT_OUTSIDE         3
+#define DLN2_ADC_EVENT_INSIDE          4
+#define DLN2_ADC_EVENT_ALWAYS          5
+
+#define DLN2_ADC_MAX_CHANNELS 8
+#define DLN2_ADC_DATA_BITS 10
+
+/*
+ * Plays similar role to iio_demux_table in subsystem core; except allocated
+ * in a fixed 8-element array.
+ */
+struct dln2_adc_demux_table {
+       unsigned int from;
+       unsigned int to;
+       unsigned int length;
+};
+
+struct dln2_adc {
+       struct platform_device *pdev;
+       struct iio_chan_spec iio_channels[DLN2_ADC_MAX_CHANNELS + 1];
+       int port, trigger_chan;
+       struct iio_trigger *trig;
+       struct mutex mutex;
+       /* Cached sample period in milliseconds */
+       unsigned int sample_period;
+       /* Demux table */
+       unsigned int demux_count;
+       struct dln2_adc_demux_table demux[DLN2_ADC_MAX_CHANNELS];
+       /* Precomputed timestamp padding offset and length */
+       unsigned int ts_pad_offset, ts_pad_length;
+};
+
+struct dln2_adc_port_chan {
+       u8 port;
+       u8 chan;
+};
+
+struct dln2_adc_get_all_vals {
+       __le16 channel_mask;
+       __le16 values[DLN2_ADC_MAX_CHANNELS];
+};
+
+static void dln2_adc_add_demux(struct dln2_adc *dln2,
+       unsigned int in_loc, unsigned int out_loc,
+       unsigned int length)
+{
+       struct dln2_adc_demux_table *p = dln2->demux_count ?
+               &dln2->demux[dln2->demux_count - 1] : NULL;
+
+       if (p && p->from + p->length == in_loc &&
+               p->to + p->length == out_loc) {
+               p->length += length;
+       } else if (dln2->demux_count < DLN2_ADC_MAX_CHANNELS) {
+               p = &dln2->demux[dln2->demux_count++];
+               p->from = in_loc;
+               p->to = out_loc;
+               p->length = length;
+       }
+}
+
+static void dln2_adc_update_demux(struct dln2_adc *dln2)
+{
+       int in_ind = -1, out_ind;
+       unsigned int in_loc = 0, out_loc = 0;
+       struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);
+
+       /* Clear out any old demux */
+       dln2->demux_count = 0;
+
+       /* Optimize all 8-channels case */
+       if (indio_dev->masklength &&
+           (*indio_dev->active_scan_mask & 0xff) == 0xff) {
+               dln2_adc_add_demux(dln2, 0, 0, 16);
+               dln2->ts_pad_offset = 0;
+               dln2->ts_pad_length = 0;
+               return;
+       }
+
+       /* Build demux table from fixed 8-channels to active_scan_mask */
+       for_each_set_bit(out_ind,
+                        indio_dev->active_scan_mask,
+                        indio_dev->masklength) {
+               /* Handle timestamp separately */
+               if (out_ind == DLN2_ADC_MAX_CHANNELS)
+                       break;
+               for (++in_ind; in_ind != out_ind; ++in_ind)
+                       in_loc += 2;
+               dln2_adc_add_demux(dln2, in_loc, out_loc, 2);
+               out_loc += 2;
+               in_loc += 2;
+       }
+
+       if (indio_dev->scan_timestamp) {
+               size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
+
+               dln2->ts_pad_offset = out_loc;
+               dln2->ts_pad_length = ts_offset * sizeof(int64_t) - out_loc;
+       } else {
+               dln2->ts_pad_offset = 0;
+               dln2->ts_pad_length = 0;
+       }
+}
+
+static int dln2_adc_get_chan_count(struct dln2_adc *dln2)
+{
+       int ret;
+       u8 port = dln2->port;
+       u8 count;
+       int olen = sizeof(count);
+
+       ret = dln2_transfer(dln2->pdev, DLN2_ADC_GET_CHANNEL_COUNT,
+                           &port, sizeof(port), &count, &olen);
+       if (ret < 0) {
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+               return ret;
+       }
+       if (olen < sizeof(count))
+               return -EPROTO;
+
+       return count;
+}
+
+static int dln2_adc_set_port_resolution(struct dln2_adc *dln2)
+{
+       int ret;
+       struct dln2_adc_port_chan port_chan = {
+               .port = dln2->port,
+               .chan = DLN2_ADC_DATA_BITS,
+       };
+
+       ret = dln2_transfer_tx(dln2->pdev, DLN2_ADC_SET_RESOLUTION,
+                              &port_chan, sizeof(port_chan));
+       if (ret < 0)
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+
+       return ret;
+}
+
+static int dln2_adc_set_chan_enabled(struct dln2_adc *dln2,
+                                    int channel, bool enable)
+{
+       int ret;
+       struct dln2_adc_port_chan port_chan = {
+               .port = dln2->port,
+               .chan = channel,
+       };
+       u16 cmd = enable ? DLN2_ADC_CHANNEL_ENABLE : DLN2_ADC_CHANNEL_DISABLE;
+
+       ret = dln2_transfer_tx(dln2->pdev, cmd, &port_chan, sizeof(port_chan));
+       if (ret < 0)
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+
+       return ret;
+}
+
+static int dln2_adc_set_port_enabled(struct dln2_adc *dln2, bool enable,
+                                    u16 *conflict_out)
+{
+       int ret;
+       u8 port = dln2->port;
+       __le16 conflict;
+       int olen = sizeof(conflict);
+       u16 cmd = enable ? DLN2_ADC_ENABLE : DLN2_ADC_DISABLE;
+
+       if (conflict_out)
+               *conflict_out = 0;
+
+       ret = dln2_transfer(dln2->pdev, cmd, &port, sizeof(port),
+                           &conflict, &olen);
+       if (ret < 0) {
+               dev_dbg(&dln2->pdev->dev, "Problem in %s(%d)\n",
+                       __func__, (int)enable);
+               if (conflict_out && enable && olen >= sizeof(conflict))
+                       *conflict_out = le16_to_cpu(conflict);
+               return ret;
+       }
+       if (enable && olen < sizeof(conflict))
+               return -EPROTO;
+
+       return ret;
+}
+
+static int dln2_adc_set_chan_period(struct dln2_adc *dln2,
+       unsigned int channel, unsigned int period)
+{
+       int ret;
+       struct {
+               struct dln2_adc_port_chan port_chan;
+               __u8 type;
+               __le16 period;
+               __le16 low;
+               __le16 high;
+       } __packed set_cfg = {
+               .port_chan.port = dln2->port,
+               .port_chan.chan = channel,
+               .type = period ? DLN2_ADC_EVENT_ALWAYS : DLN2_ADC_EVENT_NONE,
+               .period = cpu_to_le16(period)
+       };
+
+       ret = dln2_transfer_tx(dln2->pdev, DLN2_ADC_CHANNEL_SET_CFG,
+                              &set_cfg, sizeof(set_cfg));
+       if (ret < 0)
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+
+       return ret;
+}
+
+static int dln2_adc_read(struct dln2_adc *dln2, unsigned int channel)
+{
+       int ret, i;
+       struct iio_dev *indio_dev = platform_get_drvdata(dln2->pdev);
+       u16 conflict;
+       __le16 value;
+       int olen = sizeof(value);
+       struct dln2_adc_port_chan port_chan = {
+               .port = dln2->port,
+               .chan = channel,
+       };
+
+       ret = iio_device_claim_direct_mode(indio_dev);
+       if (ret < 0)
+               return ret;
+
+       ret = dln2_adc_set_chan_enabled(dln2, channel, true);
+       if (ret < 0)
+               goto release_direct;
+
+       ret = dln2_adc_set_port_enabled(dln2, true, &conflict);
+       if (ret < 0) {
+               if (conflict) {
+                       dev_err(&dln2->pdev->dev,
+                               "ADC pins conflict with mask %04X\n",
+                               (int)conflict);
+                       ret = -EBUSY;
+               }
+               goto disable_chan;
+       }
+
+       /*
+        * Call GET_VAL twice due to initial zero-return immediately after
+        * enabling channel.
+        */
+       for (i = 0; i < 2; ++i) {
+               ret = dln2_transfer(dln2->pdev, DLN2_ADC_CHANNEL_GET_VAL,
+                                   &port_chan, sizeof(port_chan),
+                                   &value, &olen);
+               if (ret < 0) {
+                       dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+                       goto disable_port;
+               }
+               if (olen < sizeof(value)) {
+                       ret = -EPROTO;
+                       goto disable_port;
+               }
+       }
+
+       ret = le16_to_cpu(value);
+
+disable_port:
+       dln2_adc_set_port_enabled(dln2, false, NULL);
+disable_chan:
+       dln2_adc_set_chan_enabled(dln2, channel, false);
+release_direct:
+       iio_device_release_direct_mode(indio_dev);
+
+       return ret;
+}
+
+static int dln2_adc_read_all(struct dln2_adc *dln2,
+                            struct dln2_adc_get_all_vals *get_all_vals)
+{
+       int ret;
+       __u8 port = dln2->port;
+       int olen = sizeof(*get_all_vals);
+
+       ret = dln2_transfer(dln2->pdev, DLN2_ADC_CHANNEL_GET_ALL_VAL,
+                           &port, sizeof(port), get_all_vals, &olen);
+       if (ret < 0) {
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+               return ret;
+       }
+       if (olen < sizeof(*get_all_vals))
+               return -EPROTO;
+
+       return ret;
+}
+
+static int dln2_adc_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val,
+                            int *val2,
+                            long mask)
+{
+       int ret;
+       unsigned int microhertz;
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&dln2->mutex);
+               ret = dln2_adc_read(dln2, chan->channel);
+               mutex_unlock(&dln2->mutex);
+
+               if (ret < 0)
+                       return ret;
+
+               *val = ret;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               /*
+                * Voltage reference is fixed at 3.3v
+                *  3.3 / (1 << 10) * 1000000000
+                */
+               *val = 0;
+               *val2 = 3222656;
+               return IIO_VAL_INT_PLUS_NANO;
+
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (dln2->sample_period) {
+                       microhertz = 1000000000 / dln2->sample_period;
+                       *val = microhertz / 1000000;
+                       *val2 = microhertz % 1000000;
+               } else {
+                       *val = 0;
+                       *val2 = 0;
+               }
+
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int dln2_adc_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val,
+                             int val2,
+                             long mask)
+{
+       int ret;
+       unsigned int microhertz;
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               microhertz = 1000000 * val + val2;
+
+               mutex_lock(&dln2->mutex);
+
+               dln2->sample_period =
+                       microhertz ? 1000000000 / microhertz : UINT_MAX;
+               if (dln2->sample_period > 65535) {
+                       dln2->sample_period = 65535;
+                       dev_warn(&dln2->pdev->dev,
+                                "clamping period to 65535ms\n");
+               }
+
+               /*
+                * The first requested channel is arbitrated as a shared
+                * trigger source, so only one event is registered with the
+                * DLN. The event handler will then read all enabled channel
+                * values using DLN2_ADC_CHANNEL_GET_ALL_VAL to maintain
+                * synchronization between ADC readings.
+                */
+               if (dln2->trigger_chan != -1)
+                       ret = dln2_adc_set_chan_period(dln2,
+                               dln2->trigger_chan, dln2->sample_period);
+               else
+                       ret = 0;
+
+               mutex_unlock(&dln2->mutex);
+
+               return ret;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int dln2_update_scan_mode(struct iio_dev *indio_dev,
+                                const unsigned long *scan_mask)
+{
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+       int chan_count = indio_dev->num_channels - 1;
+       int ret, i, j;
+
+       mutex_lock(&dln2->mutex);
+
+       for (i = 0; i < chan_count; ++i) {
+               ret = dln2_adc_set_chan_enabled(dln2, i,
+                                               test_bit(i, scan_mask));
+               if (ret < 0) {
+                       for (j = 0; j < i; ++j)
+                               dln2_adc_set_chan_enabled(dln2, j, false);
+                       mutex_unlock(&dln2->mutex);
+                       dev_err(&dln2->pdev->dev,
+                               "Unable to enable ADC channel %d\n", i);
+                       return -EBUSY;
+               }
+       }
+
+       dln2_adc_update_demux(dln2);
+
+       mutex_unlock(&dln2->mutex);
+
+       return 0;
+}
+
+#define DLN2_ADC_CHAN(lval, idx) {                                     \
+       lval.type = IIO_VOLTAGE;                                        \
+       lval.channel = idx;                                             \
+       lval.indexed = 1;                                               \
+       lval.info_mask_separate = BIT(IIO_CHAN_INFO_RAW);               \
+       lval.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |       \
+                                      BIT(IIO_CHAN_INFO_SAMP_FREQ);    \
+       lval.scan_index = idx;                                          \
+       lval.scan_type.sign = 'u';                                      \
+       lval.scan_type.realbits = DLN2_ADC_DATA_BITS;                   \
+       lval.scan_type.storagebits = 16;                                \
+       lval.scan_type.endianness = IIO_LE;                             \
+}
+
+/* Assignment version of IIO_CHAN_SOFT_TIMESTAMP */
+#define IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(lval, _si) {    \
+       lval.type = IIO_TIMESTAMP;                      \
+       lval.channel = -1;                              \
+       lval.scan_index = _si;                          \
+       lval.scan_type.sign = 's';                      \
+       lval.scan_type.realbits = 64;                   \
+       lval.scan_type.storagebits = 64;                \
+}
+
+static const struct iio_info dln2_adc_info = {
+       .read_raw = dln2_adc_read_raw,
+       .write_raw = dln2_adc_write_raw,
+       .update_scan_mode = dln2_update_scan_mode,
+       .driver_module = THIS_MODULE,
+};
+
+static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct {
+               __le16 values[DLN2_ADC_MAX_CHANNELS];
+               int64_t timestamp_space;
+       } data;
+       struct dln2_adc_get_all_vals dev_data;
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+       const struct dln2_adc_demux_table *t;
+       int ret, i;
+
+       mutex_lock(&dln2->mutex);
+       ret = dln2_adc_read_all(dln2, &dev_data);
+       mutex_unlock(&dln2->mutex);
+       if (ret < 0)
+               goto done;
+
+       /* Demux operation */
+       for (i = 0; i < dln2->demux_count; ++i) {
+               t = &dln2->demux[i];
+               memcpy((void *)data.values + t->to,
+                      (void *)dev_data.values + t->from, t->length);
+       }
+
+       /* Zero padding space between values and timestamp */
+       if (dln2->ts_pad_length)
+               memset((void *)data.values + dln2->ts_pad_offset,
+                      0, dln2->ts_pad_length);
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &data,
+                                          iio_get_time_ns(indio_dev));
+
+done:
+       iio_trigger_notify_done(indio_dev->trig);
+       return IRQ_HANDLED;
+}
+
+static int dln2_adc_triggered_buffer_postenable(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+       u16 conflict;
+       unsigned int trigger_chan;
+
+       mutex_lock(&dln2->mutex);
+
+       /* Enable ADC */
+       ret = dln2_adc_set_port_enabled(dln2, true, &conflict);
+       if (ret < 0) {
+               mutex_unlock(&dln2->mutex);
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+               if (conflict) {
+                       dev_err(&dln2->pdev->dev,
+                               "ADC pins conflict with mask %04X\n",
+                               (int)conflict);
+                       ret = -EBUSY;
+               }
+               return ret;
+       }
+
+       /* Assign trigger channel based on first enabled channel */
+       trigger_chan = find_first_bit(indio_dev->active_scan_mask,
+                                     indio_dev->masklength);
+       if (trigger_chan < DLN2_ADC_MAX_CHANNELS) {
+               dln2->trigger_chan = trigger_chan;
+               ret = dln2_adc_set_chan_period(dln2, dln2->trigger_chan,
+                                              dln2->sample_period);
+               mutex_unlock(&dln2->mutex);
+               if (ret < 0) {
+                       dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+                       return ret;
+               }
+       } else {
+               dln2->trigger_chan = -1;
+               mutex_unlock(&dln2->mutex);
+       }
+
+       return iio_triggered_buffer_postenable(indio_dev);
+}
+
+static int dln2_adc_triggered_buffer_predisable(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+       mutex_lock(&dln2->mutex);
+
+       /* Disable trigger channel */
+       if (dln2->trigger_chan != -1) {
+               dln2_adc_set_chan_period(dln2, dln2->trigger_chan, 0);
+               dln2->trigger_chan = -1;
+       }
+
+       /* Disable ADC */
+       ret = dln2_adc_set_port_enabled(dln2, false, NULL);
+
+       mutex_unlock(&dln2->mutex);
+       if (ret < 0) {
+               dev_dbg(&dln2->pdev->dev, "Problem in %s\n", __func__);
+               return ret;
+       }
+
+       return iio_triggered_buffer_predisable(indio_dev);
+}
+
+static const struct iio_buffer_setup_ops dln2_adc_buffer_setup_ops = {
+       .postenable = dln2_adc_triggered_buffer_postenable,
+       .predisable = dln2_adc_triggered_buffer_predisable,
+};
+
+static void dln2_adc_event(struct platform_device *pdev, u16 echo,
+                          const void *data, int len)
+{
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+       struct dln2_adc *dln2 = iio_priv(indio_dev);
+
+       /* Called via URB completion handler */
+       iio_trigger_poll(dln2->trig);
+}
+
+static const struct iio_trigger_ops dln2_adc_trigger_ops = {
+       .owner = THIS_MODULE,
+};
+
+static int dln2_adc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct dln2_adc *dln2;
+       struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct iio_dev *indio_dev;
+       int i, ret, chans;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*dln2));
+       if (!indio_dev) {
+               dev_err(dev, "failed allocating iio device\n");
+               return -ENOMEM;
+       }
+
+       dln2 = iio_priv(indio_dev);
+       dln2->pdev = pdev;
+       dln2->port = pdata->port;
+       dln2->trigger_chan = -1;
+       mutex_init(&dln2->mutex);
+
+       platform_set_drvdata(pdev, indio_dev);
+
+       ret = dln2_adc_set_port_resolution(dln2);
+       if (ret < 0) {
+               dev_err(dev, "failed to set ADC resolution to 10 bits\n");
+               return ret;
+       }
+
+       chans = dln2_adc_get_chan_count(dln2);
+       if (chans < 0) {
+               dev_err(dev, "failed to get channel count: %d\n", chans);
+               return chans;
+       }
+       if (chans > DLN2_ADC_MAX_CHANNELS) {
+               chans = DLN2_ADC_MAX_CHANNELS;
+               dev_warn(dev, "clamping channels to %d\n",
+                        DLN2_ADC_MAX_CHANNELS);
+       }
+
+       for (i = 0; i < chans; ++i)
+               DLN2_ADC_CHAN(dln2->iio_channels[i], i)
+       IIO_CHAN_SOFT_TIMESTAMP_ASSIGN(dln2->iio_channels[i], i);
+
+       indio_dev->name = DLN2_ADC_MOD_NAME;
+       indio_dev->dev.parent = dev;
+       indio_dev->info = &dln2_adc_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = dln2->iio_channels;
+       indio_dev->num_channels = chans + 1;
+       indio_dev->setup_ops = &dln2_adc_buffer_setup_ops;
+
+       dln2->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+                                           indio_dev->name, indio_dev->id);
+       if (!dln2->trig) {
+               dev_err(dev, "failed to allocate trigger\n");
+               return -ENOMEM;
+       }
+       dln2->trig->ops = &dln2_adc_trigger_ops;
+       iio_trigger_set_drvdata(dln2->trig, dln2);
+       devm_iio_trigger_register(dev, dln2->trig);
+       iio_trigger_set_immutable(indio_dev, dln2->trig);
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             dln2_adc_trigger_h,
+                                             &dln2_adc_buffer_setup_ops);
+       if (ret) {
+               dev_err(dev, "failed to allocate triggered buffer: %d\n", ret);
+               return ret;
+       }
+
+       ret = dln2_register_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV,
+                                    dln2_adc_event);
+       if (ret) {
+               dev_err(dev, "failed to setup DLN2 periodic event: %d\n", ret);
+               return ret;
+       }
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(dev, "failed to register iio device: %d\n", ret);
+               goto unregister_event;
+       }
+
+       return ret;
+
+unregister_event:
+       dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV);
+
+       return ret;
+}
+
+static int dln2_adc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+       iio_device_unregister(indio_dev);
+       dln2_unregister_event_cb(pdev, DLN2_ADC_CONDITION_MET_EV);
+       return 0;
+}
+
+static struct platform_driver dln2_adc_driver = {
+       .driver.name    = DLN2_ADC_MOD_NAME,
+       .probe          = dln2_adc_probe,
+       .remove         = dln2_adc_remove,
+};
+
+module_platform_driver(dln2_adc_driver);
+
+MODULE_AUTHOR("Jack Andersen <jackoalan@gmail.com");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 ADC interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dln2-adc");
diff --git a/drivers/iio/adc/ep93xx_adc.c b/drivers/iio/adc/ep93xx_adc.c
new file mode 100644 (file)
index 0000000..a179ac4
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Driver for ADC module on the Cirrus Logic EP93xx series of SoCs
+ *
+ * Copyright (C) 2015 Alexander Sverdlin
+ *
+ * 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.
+ *
+ * The driver uses polling to get the conversion status. According to EP93xx
+ * datasheets, reading ADCResult register starts the conversion, but user is also
+ * responsible for ensuring that delay between adjacent conversion triggers is
+ * long enough so that maximum allowed conversion rate is not exceeded. This
+ * basically renders IRQ mode unusable.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/io.h>
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+/*
+ * This code could benefit from real HR Timers, but jiffy granularity would
+ * lower ADC conversion rate down to CONFIG_HZ, so we fallback to busy wait
+ * in such case.
+ *
+ * HR Timers-based version loads CPU only up to 10% during back to back ADC
+ * conversion, while busy wait-based version consumes whole CPU power.
+ */
+#ifdef CONFIG_HIGH_RES_TIMERS
+#define ep93xx_adc_delay(usmin, usmax) usleep_range(usmin, usmax)
+#else
+#define ep93xx_adc_delay(usmin, usmax) udelay(usmin)
+#endif
+
+#define EP93XX_ADC_RESULT      0x08
+#define   EP93XX_ADC_SDR       BIT(31)
+#define EP93XX_ADC_SWITCH      0x18
+#define EP93XX_ADC_SW_LOCK     0x20
+
+struct ep93xx_adc_priv {
+       struct clk *clk;
+       void __iomem *base;
+       int lastch;
+       struct mutex lock;
+};
+
+#define EP93XX_ADC_CH(index, dname, swcfg) {                   \
+       .type = IIO_VOLTAGE,                                    \
+       .indexed = 1,                                           \
+       .channel = index,                                       \
+       .address = swcfg,                                       \
+       .datasheet_name = dname,                                \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) |   \
+                                  BIT(IIO_CHAN_INFO_OFFSET),   \
+}
+
+/*
+ * Numbering scheme for channels 0..4 is defined in EP9301 and EP9302 datasheets.
+ * EP9307, EP9312 and EP9312 have 3 channels more (total 8), but the numbering is
+ * not defined. So the last three are numbered randomly, let's say.
+ */
+static const struct iio_chan_spec ep93xx_adc_channels[8] = {
+       EP93XX_ADC_CH(0, "YM",  0x608),
+       EP93XX_ADC_CH(1, "SXP", 0x680),
+       EP93XX_ADC_CH(2, "SXM", 0x640),
+       EP93XX_ADC_CH(3, "SYP", 0x620),
+       EP93XX_ADC_CH(4, "SYM", 0x610),
+       EP93XX_ADC_CH(5, "XP",  0x601),
+       EP93XX_ADC_CH(6, "XM",  0x602),
+       EP93XX_ADC_CH(7, "YP",  0x604),
+};
+
+static int ep93xx_read_raw(struct iio_dev *iiodev,
+                          struct iio_chan_spec const *channel, int *value,
+                          int *shift, long mask)
+{
+       struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+       unsigned long timeout;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&priv->lock);
+               if (priv->lastch != channel->channel) {
+                       priv->lastch = channel->channel;
+                       /*
+                        * Switch register is software-locked, unlocking must be
+                        * immediately followed by write
+                        */
+                       local_irq_disable();
+                       writel_relaxed(0xAA, priv->base + EP93XX_ADC_SW_LOCK);
+                       writel_relaxed(channel->address,
+                                      priv->base + EP93XX_ADC_SWITCH);
+                       local_irq_enable();
+                       /*
+                        * Settling delay depends on module clock and could be
+                        * 2ms or 500us
+                        */
+                       ep93xx_adc_delay(2000, 2000);
+               }
+               /* Start the conversion, eventually discarding old result */
+               readl_relaxed(priv->base + EP93XX_ADC_RESULT);
+               /* Ensure maximum conversion rate is not exceeded */
+               ep93xx_adc_delay(DIV_ROUND_UP(1000000, 925),
+                                DIV_ROUND_UP(1000000, 925));
+               /* At this point conversion must be completed, but anyway... */
+               ret = IIO_VAL_INT;
+               timeout = jiffies + msecs_to_jiffies(1) + 1;
+               while (1) {
+                       u32 t;
+
+                       t = readl_relaxed(priv->base + EP93XX_ADC_RESULT);
+                       if (t & EP93XX_ADC_SDR) {
+                               *value = sign_extend32(t, 15);
+                               break;
+                       }
+
+                       if (time_after(jiffies, timeout)) {
+                               dev_err(&iiodev->dev, "Conversion timeout\n");
+                               ret = -ETIMEDOUT;
+                               break;
+                       }
+
+                       cpu_relax();
+               }
+               mutex_unlock(&priv->lock);
+               return ret;
+
+       case IIO_CHAN_INFO_OFFSET:
+               /* According to datasheet, range is -25000..25000 */
+               *value = 25000;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               /* Typical supply voltage is 3.3v */
+               *value = (1ULL << 32) * 3300 / 50000;
+               *shift = 32;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_info ep93xx_adc_info = {
+       .driver_module = THIS_MODULE,
+       .read_raw = ep93xx_read_raw,
+};
+
+static int ep93xx_adc_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct iio_dev *iiodev;
+       struct ep93xx_adc_priv *priv;
+       struct clk *pclk;
+       struct resource *res;
+
+       iiodev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
+       if (!iiodev)
+               return -ENOMEM;
+       priv = iio_priv(iiodev);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Cannot obtain memory resource\n");
+               return -ENXIO;
+       }
+       priv->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->base)) {
+               dev_err(&pdev->dev, "Cannot map memory resource\n");
+               return PTR_ERR(priv->base);
+       }
+
+       iiodev->dev.parent = &pdev->dev;
+       iiodev->name = dev_name(&pdev->dev);
+       iiodev->modes = INDIO_DIRECT_MODE;
+       iiodev->info = &ep93xx_adc_info;
+       iiodev->num_channels = ARRAY_SIZE(ep93xx_adc_channels);
+       iiodev->channels = ep93xx_adc_channels;
+
+       priv->lastch = -1;
+       mutex_init(&priv->lock);
+
+       platform_set_drvdata(pdev, iiodev);
+
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(&pdev->dev, "Cannot obtain clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
+       pclk = clk_get_parent(priv->clk);
+       if (!pclk) {
+               dev_warn(&pdev->dev, "Cannot obtain parent clock\n");
+       } else {
+               /*
+                * This is actually a place for improvement:
+                * EP93xx ADC supports two clock divisors -- 4 and 16,
+                * resulting in conversion rates 3750 and 925 samples per second
+                * with 500us or 2ms settling time respectively.
+                * One might find this interesting enough to be configurable.
+                */
+               ret = clk_set_rate(priv->clk, clk_get_rate(pclk) / 16);
+               if (ret)
+                       dev_warn(&pdev->dev, "Cannot set clock rate\n");
+               /*
+                * We can tolerate rate setting failure because the module should
+                * work in any case.
+                */
+       }
+
+       ret = clk_enable(priv->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot enable clock\n");
+               return ret;
+       }
+
+       ret = iio_device_register(iiodev);
+       if (ret)
+               clk_disable(priv->clk);
+
+       return ret;
+}
+
+static int ep93xx_adc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *iiodev = platform_get_drvdata(pdev);
+       struct ep93xx_adc_priv *priv = iio_priv(iiodev);
+
+       iio_device_unregister(iiodev);
+       clk_disable(priv->clk);
+
+       return 0;
+}
+
+static struct platform_driver ep93xx_adc_driver = {
+       .driver = {
+               .name = "ep93xx-adc",
+       },
+       .probe = ep93xx_adc_probe,
+       .remove = ep93xx_adc_remove,
+};
+module_platform_driver(ep93xx_adc_driver);
+
+MODULE_AUTHOR("Alexander Sverdlin <alexander.sverdlin@gmail.com>");
+MODULE_DESCRIPTION("Cirrus Logic EP93XX ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-adc");
index 232c0b80d65893e497abe4e13c4b5273e3c9a7a0..68884d26b50cbcbd522f825e376479bb8ef091c0 100644 (file)
@@ -44,6 +44,7 @@
 
 #define INA226_MASK_ENABLE             0x06
 #define INA226_CVRF                    BIT(3)
+#define INA219_CNVR                    BIT(1)
 
 #define INA2XX_MAX_REGISTERS            8
 
@@ -592,6 +593,7 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
        int bit, ret, i = 0;
        s64 time_a, time_b;
        unsigned int alert;
+       int cnvr_need_clear = 0;
 
        time_a = iio_get_time_ns(indio_dev);
 
@@ -603,22 +605,30 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
         * we check the ConVersionReadyFlag.
         * On hardware that supports using the ALERT pin to toggle a
         * GPIO a triggered buffer could be used instead.
-        * For now, we pay for that extra read of the ALERT register
+        * For now, we do an extra read of the MASK_ENABLE register (INA226)
+        * resp. the BUS_VOLTAGE register (INA219).
         */
        if (!chip->allow_async_readout)
                do {
-                       ret = regmap_read(chip->regmap, INA226_MASK_ENABLE,
-                                         &alert);
+                       if (chip->config->chip_id == ina226) {
+                               ret = regmap_read(chip->regmap,
+                                                 INA226_MASK_ENABLE, &alert);
+                               alert &= INA226_CVRF;
+                       } else {
+                               ret = regmap_read(chip->regmap,
+                                                 INA2XX_BUS_VOLTAGE, &alert);
+                               alert &= INA219_CNVR;
+                               cnvr_need_clear = alert;
+                       }
+
                        if (ret < 0)
                                return ret;
 
-                       alert &= INA226_CVRF;
                } while (!alert);
 
        /*
-        * Single register reads: bulk_read will not work with ina226
-        * as there is no auto-increment of the address register for
-        * data length longer than 16bits.
+        * Single register reads: bulk_read will not work with ina226/219
+        * as there is no auto-increment of the register pointer.
         */
        for_each_set_bit(bit, indio_dev->active_scan_mask,
                         indio_dev->masklength) {
@@ -630,6 +640,18 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
                        return ret;
 
                data[i++] = val;
+
+               if (INA2XX_SHUNT_VOLTAGE + bit == INA2XX_POWER)
+                       cnvr_need_clear = 0;
+       }
+
+       /* Dummy read on INA219 power register to clear CNVR flag */
+       if (cnvr_need_clear && chip->config->chip_id == ina219) {
+               unsigned int val;
+
+               ret = regmap_read(chip->regmap, INA2XX_POWER, &val);
+               if (ret < 0)
+                       return ret;
        }
 
        time_b = iio_get_time_ns(indio_dev);
diff --git a/drivers/iio/adc/ltc2471.c b/drivers/iio/adc/ltc2471.c
new file mode 100644 (file)
index 0000000..29b7ed6
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Driver for Linear Technology LTC2471 and LTC2473 voltage monitors
+ * The LTC2473 is identical to the 2471, but reports a differential signal.
+ *
+ * Copyright (C) 2017 Topic Embedded Products
+ * Author: Mike Looijmans <mike.looijmans@topic.nl>
+ *
+ * License: GPLv2
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+enum ltc2471_chips {
+       ltc2471,
+       ltc2473,
+};
+
+struct ltc2471_data {
+       struct i2c_client *client;
+};
+
+/* Reference voltage is 1.25V */
+#define LTC2471_VREF 1250
+
+/* Read two bytes from the I2C bus to obtain the ADC result */
+static int ltc2471_get_value(struct i2c_client *client)
+{
+       int ret;
+       __be16 buf;
+
+       ret = i2c_master_recv(client, (char *)&buf, sizeof(buf));
+       if (ret < 0)
+               return ret;
+       if (ret != sizeof(buf))
+               return -EIO;
+
+       /* MSB first */
+       return be16_to_cpu(buf);
+}
+
+static int ltc2471_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long info)
+{
+       struct ltc2471_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (info) {
+       case IIO_CHAN_INFO_RAW:
+               ret = ltc2471_get_value(data->client);
+               if (ret < 0)
+                       return ret;
+               *val = ret;
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->differential)
+                       /* Output ranges from -VREF to +VREF */
+                       *val = 2 * LTC2471_VREF;
+               else
+                       /* Output ranges from 0 to VREF */
+                       *val = LTC2471_VREF;
+               *val2 = 16;     /* 16 data bits */
+               return IIO_VAL_FRACTIONAL_LOG2;
+
+       case IIO_CHAN_INFO_OFFSET:
+               /* Only differential chip has this property */
+               *val = -LTC2471_VREF;
+               return IIO_VAL_INT;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_chan_spec ltc2471_channel[] = {
+       {
+               .type = IIO_VOLTAGE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+       },
+};
+
+static const struct iio_chan_spec ltc2473_channel[] = {
+       {
+               .type = IIO_VOLTAGE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+                                           BIT(IIO_CHAN_INFO_OFFSET),
+               .differential = 1,
+       },
+};
+
+static const struct iio_info ltc2471_info = {
+       .read_raw = ltc2471_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static int ltc2471_i2c_probe(struct i2c_client *client,
+                            const struct i2c_device_id *id)
+{
+       struct iio_dev *indio_dev;
+       struct ltc2471_data *data;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -EOPNOTSUPP;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       data = iio_priv(indio_dev);
+       data->client = client;
+
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->name = id->name;
+       indio_dev->info = &ltc2471_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       if (id->driver_data == ltc2473)
+               indio_dev->channels = ltc2473_channel;
+       else
+               indio_dev->channels = ltc2471_channel;
+       indio_dev->num_channels = 1;
+
+       /* Trigger once to start conversion and check if chip is there */
+       ret = ltc2471_get_value(client);
+       if (ret < 0) {
+               dev_err(&client->dev, "Cannot read from device.\n");
+               return ret;
+       }
+
+       return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id ltc2471_i2c_id[] = {
+       { "ltc2471", ltc2471 },
+       { "ltc2473", ltc2473 },
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ltc2471_i2c_id);
+
+static struct i2c_driver ltc2471_i2c_driver = {
+       .driver = {
+               .name = "ltc2471",
+       },
+       .probe    = ltc2471_i2c_probe,
+       .id_table = ltc2471_i2c_id,
+};
+
+module_i2c_driver(ltc2471_i2c_driver);
+
+MODULE_DESCRIPTION("LTC2471/LTC2473 ADC driver");
+MODULE_AUTHOR("Topic Embedded Products");
+MODULE_LICENSE("GPL v2");
index 2691b10023f50b4833d02442a1e555fd93245a7f..5bf8011dcde9affb385c5ea4b22c3098ec27953c 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
 #include <linux/iio/sysfs.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -127,13 +128,14 @@ static int ltc2497_read_raw(struct iio_dev *indio_dev,
        }
 }
 
-#define LTC2497_CHAN(_chan, _addr) { \
+#define LTC2497_CHAN(_chan, _addr, _ds_name) { \
        .type = IIO_VOLTAGE, \
        .indexed = 1, \
        .channel = (_chan), \
        .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+       .datasheet_name = (_ds_name), \
 }
 
 #define LTC2497_CHAN_DIFF(_chan, _addr) { \
@@ -148,22 +150,22 @@ static int ltc2497_read_raw(struct iio_dev *indio_dev,
 }
 
 static const struct iio_chan_spec ltc2497_channel[] = {
-       LTC2497_CHAN(0, LTC2497_SGL),
-       LTC2497_CHAN(1, LTC2497_SGL),
-       LTC2497_CHAN(2, LTC2497_SGL),
-       LTC2497_CHAN(3, LTC2497_SGL),
-       LTC2497_CHAN(4, LTC2497_SGL),
-       LTC2497_CHAN(5, LTC2497_SGL),
-       LTC2497_CHAN(6, LTC2497_SGL),
-       LTC2497_CHAN(7, LTC2497_SGL),
-       LTC2497_CHAN(8, LTC2497_SGL),
-       LTC2497_CHAN(9, LTC2497_SGL),
-       LTC2497_CHAN(10, LTC2497_SGL),
-       LTC2497_CHAN(11, LTC2497_SGL),
-       LTC2497_CHAN(12, LTC2497_SGL),
-       LTC2497_CHAN(13, LTC2497_SGL),
-       LTC2497_CHAN(14, LTC2497_SGL),
-       LTC2497_CHAN(15, LTC2497_SGL),
+       LTC2497_CHAN(0, LTC2497_SGL, "CH0"),
+       LTC2497_CHAN(1, LTC2497_SGL, "CH1"),
+       LTC2497_CHAN(2, LTC2497_SGL, "CH2"),
+       LTC2497_CHAN(3, LTC2497_SGL, "CH3"),
+       LTC2497_CHAN(4, LTC2497_SGL, "CH4"),
+       LTC2497_CHAN(5, LTC2497_SGL, "CH5"),
+       LTC2497_CHAN(6, LTC2497_SGL, "CH6"),
+       LTC2497_CHAN(7, LTC2497_SGL, "CH7"),
+       LTC2497_CHAN(8, LTC2497_SGL, "CH8"),
+       LTC2497_CHAN(9, LTC2497_SGL, "CH9"),
+       LTC2497_CHAN(10, LTC2497_SGL, "CH10"),
+       LTC2497_CHAN(11, LTC2497_SGL, "CH11"),
+       LTC2497_CHAN(12, LTC2497_SGL, "CH12"),
+       LTC2497_CHAN(13, LTC2497_SGL, "CH13"),
+       LTC2497_CHAN(14, LTC2497_SGL, "CH14"),
+       LTC2497_CHAN(15, LTC2497_SGL, "CH15"),
        LTC2497_CHAN_DIFF(0, LTC2497_DIFF),
        LTC2497_CHAN_DIFF(1, LTC2497_DIFF),
        LTC2497_CHAN_DIFF(2, LTC2497_DIFF),
@@ -192,6 +194,7 @@ static int ltc2497_probe(struct i2c_client *client,
 {
        struct iio_dev *indio_dev;
        struct ltc2497_st *st;
+       struct iio_map *plat_data;
        int ret;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
@@ -221,19 +224,31 @@ static int ltc2497_probe(struct i2c_client *client,
        if (ret < 0)
                return ret;
 
+       if (client->dev.platform_data) {
+               plat_data = ((struct iio_map *)client->dev.platform_data);
+               ret = iio_map_array_register(indio_dev, plat_data);
+               if (ret) {
+                       dev_err(&indio_dev->dev, "iio map err: %d\n", ret);
+                       goto err_regulator_disable;
+               }
+       }
+
        ret = i2c_smbus_write_byte(st->client, LTC2497_CONFIG_DEFAULT);
        if (ret < 0)
-               goto err_regulator_disable;
+               goto err_array_unregister;
 
        st->addr_prev = LTC2497_CONFIG_DEFAULT;
        st->time_prev = ktime_get();
 
        ret = iio_device_register(indio_dev);
        if (ret < 0)
-               goto err_regulator_disable;
+               goto err_array_unregister;
 
        return 0;
 
+err_array_unregister:
+       iio_map_array_unregister(indio_dev);
+
 err_regulator_disable:
        regulator_disable(st->ref);
 
@@ -245,6 +260,7 @@ static int ltc2497_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct ltc2497_st *st = iio_priv(indio_dev);
 
+       iio_map_array_unregister(indio_dev);
        iio_device_unregister(indio_dev);
        regulator_disable(st->ref);
 
index b0526e4b9530a00265f5051736a22ba845f8004f..b1dd17cbce588c05bf0d056cc92e79e9495b77f1 100644 (file)
@@ -549,8 +549,8 @@ static int max9611_probe(struct i2c_client *client,
        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);
+                       "Missing %s property for %pOF node\n",
+                       shunt_res_prop, of_node);
                return ret;
        }
        max9611->shunt_resistor_uohm = of_shunt;
index 254135e07792295c886adcee861ccca960b317da..63de705086ed499addccaf978e22fe1366eeb60d 100644 (file)
@@ -379,10 +379,12 @@ static int mcp3422_probe(struct i2c_client *client,
 
        /* meaningful default configuration */
        config = (MCP3422_CONT_SAMPLING
-               | MCP3422_CHANNEL_VALUE(1)
+               | MCP3422_CHANNEL_VALUE(0)
                | MCP3422_PGA_VALUE(MCP3422_PGA_1)
                | MCP3422_SAMPLE_RATE_VALUE(MCP3422_SRATE_240));
-       mcp3422_update_config(adc, config);
+       err = mcp3422_update_config(adc, config);
+       if (err < 0)
+               return err;
 
        err = devm_iio_device_register(&client->dev, indio_dev);
        if (err < 0)
index 83da50ed73ab679ecbea5196ce6fa8df7f298216..2e8dbb89c8c968643d35d6564b9edd24e84bfbea 100644 (file)
@@ -572,8 +572,8 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
        struct clk_init_data init;
        const char *clk_parents[1];
 
-       init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
-                                  of_node_full_name(indio_dev->dev.of_node));
+       init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_div",
+                                  indio_dev->dev.of_node);
        init.flags = 0;
        init.ops = &clk_divider_ops;
        clk_parents[0] = __clk_get_name(priv->clkin);
@@ -591,8 +591,8 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
        if (WARN_ON(IS_ERR(priv->adc_div_clk)))
                return PTR_ERR(priv->adc_div_clk);
 
-       init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
-                                  of_node_full_name(indio_dev->dev.of_node));
+       init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_en",
+                                  indio_dev->dev.of_node);
        init.flags = CLK_SET_RATE_PARENT;
        init.ops = &clk_gate_ops;
        clk_parents[0] = __clk_get_name(priv->adc_div_clk);
@@ -915,6 +915,11 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
        init_completion(&priv->done);
 
        match = of_match_device(meson_sar_adc_of_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
        priv->data = match->data;
 
        indio_dev->name = priv->data->name;
index 2d104c8280410e28ff14c145131423391aac82e3..414cf44bf19d0f7b16f7653cf6ff9523889765a0 100644 (file)
@@ -184,6 +184,37 @@ static const struct iio_info mt6577_auxadc_info = {
        .read_raw = &mt6577_auxadc_read_raw,
 };
 
+static int __maybe_unused mt6577_auxadc_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+       int ret;
+
+       ret = clk_prepare_enable(adc_dev->adc_clk);
+       if (ret) {
+               pr_err("failed to enable auxadc clock\n");
+               return ret;
+       }
+
+       mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+                             MT6577_AUXADC_PDN_EN, 0);
+       mdelay(MT6577_AUXADC_POWER_READY_MS);
+
+       return 0;
+}
+
+static int __maybe_unused mt6577_auxadc_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
+
+       mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
+                             0, MT6577_AUXADC_PDN_EN);
+       clk_disable_unprepare(adc_dev->adc_clk);
+
+       return 0;
+}
+
 static int mt6577_auxadc_probe(struct platform_device *pdev)
 {
        struct mt6577_auxadc_device *adc_dev;
@@ -269,8 +300,13 @@ static int mt6577_auxadc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(mt6577_auxadc_pm_ops,
+                        mt6577_auxadc_suspend,
+                        mt6577_auxadc_resume);
+
 static const struct of_device_id mt6577_auxadc_of_match[] = {
        { .compatible = "mediatek,mt2701-auxadc", },
+       { .compatible = "mediatek,mt7622-auxadc", },
        { .compatible = "mediatek,mt8173-auxadc", },
        { }
 };
@@ -280,6 +316,7 @@ static struct platform_driver mt6577_auxadc_driver = {
        .driver = {
                .name   = "mt6577-auxadc",
                .of_match_table = mt6577_auxadc_of_match,
+               .pm = &mt6577_auxadc_pm_ops,
        },
        .probe  = mt6577_auxadc_probe,
        .remove = mt6577_auxadc_remove,
index ae6d3324f51839a24fc7411b73c6d55179b76346..2bf2ed15a8708bdea4ee11e9210874ef725cf1bc 100644 (file)
@@ -224,6 +224,11 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
        info = iio_priv(indio_dev);
 
        match = of_match_device(rockchip_saradc_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "failed to match device\n");
+               return -ENODEV;
+       }
+
        info->data = match->data;
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index e09233b03c055b01c1d3cab229b66e5d093c1c3d..9d083c2338f9e8d618c2802f024896aaa8863d1b 100644 (file)
@@ -172,7 +172,7 @@ struct stm32h7_adc_ck_spec {
        int div;
 };
 
-const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
+static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
        /* 00: CK_ADC[1..3]: Asynchronous clock modes */
        { 0, 0, 1 },
        { 0, 1, 2 },
index 884b8e461b1755ddbcbfbb3611deaa3b4a4c8fb9..7972845b382399272bdde1856e7b3b0bd4577183 100644 (file)
@@ -505,24 +505,24 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
                unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
 
                if (of_property_read_u32(node, "reg", &pval)) {
-                       dev_err(&client->dev, "invalid reg on %s\n",
-                               node->full_name);
+                       dev_err(&client->dev, "invalid reg on %pOF\n",
+                               node);
                        continue;
                }
 
                channel = pval;
                if (channel >= ADS1015_CHANNELS) {
                        dev_err(&client->dev,
-                               "invalid channel index %d on %s\n",
-                               channel, node->full_name);
+                               "invalid channel index %d on %pOF\n",
+                               channel, node);
                        continue;
                }
 
                if (!of_property_read_u32(node, "ti,gain", &pval)) {
                        pga = pval;
                        if (pga > 6) {
-                               dev_err(&client->dev, "invalid gain on %s\n",
-                                       node->full_name);
+                               dev_err(&client->dev, "invalid gain on %pOF\n",
+                                       node);
                                of_node_put(node);
                                return -EINVAL;
                        }
@@ -532,8 +532,8 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
                        data_rate = pval;
                        if (data_rate > 7) {
                                dev_err(&client->dev,
-                                       "invalid data_rate on %s\n",
-                                       node->full_name);
+                                       "invalid data_rate on %pOF\n",
+                                       node);
                                of_node_put(node);
                                return -EINVAL;
                        }
index cea7f9857a1f7ee920ef6db7eb4aaf8bca32980e..4d799b5cceac27d4f13941cb5ffd5c1c07e732f6 100644 (file)
@@ -21,6 +21,13 @@ config ATLAS_PH_SENSOR
         To compile this driver as module, choose M here: the
         module will be called atlas-ph-sensor.
 
+config CCS811
+       tristate "AMS CCS811 VOC sensor"
+       depends on I2C
+       help
+         Say Y here to build I2C interface support for the AMS
+         CCS811 VOC (Volatile Organic Compounds) sensor
+
 config IAQCORE
        tristate "AMS iAQ-Core VOC sensors"
        depends on I2C
index b02202b412890cef588908c37769a1fcf60f9c42..a629b29d1e0b4c1558c19b893502c5868d0b8644 100644 (file)
@@ -4,5 +4,6 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_ATLAS_PH_SENSOR)  += atlas-ph-sensor.o
+obj-$(CONFIG_CCS811)           += ccs811.o
 obj-$(CONFIG_IAQCORE)          += ams-iaq-core.o
 obj-$(CONFIG_VZ89X)            += vz89x.o
diff --git a/drivers/iio/chemical/ccs811.c b/drivers/iio/chemical/ccs811.c
new file mode 100644 (file)
index 0000000..8dbb5ed
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * ccs811.c - Support for AMS CCS811 VOC Sensor
+ *
+ * Copyright (C) 2017 Narcisa Vasile <narcisaanamaria12@gmail.com>
+ *
+ * Datasheet: ams.com/content/download/951091/2269479/CCS811_DS000459_3-00.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * IIO driver for AMS CCS811 (I2C address 0x5A/0x5B set by ADDR Low/High)
+ *
+ * TODO:
+ * 1. Make the drive mode selectable form userspace
+ * 2. Add support for interrupts
+ * 3. Adjust time to wait for data to be ready based on selected operation mode
+ * 4. Read error register and put the information in logs
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+
+#define CCS811_STATUS          0x00
+#define CCS811_MEAS_MODE       0x01
+#define CCS811_ALG_RESULT_DATA 0x02
+#define CCS811_RAW_DATA                0x03
+#define CCS811_HW_ID           0x20
+#define CCS881_HW_ID_VALUE     0x81
+#define CCS811_HW_VERSION      0x21
+#define CCS811_HW_VERSION_VALUE        0x10
+#define CCS811_HW_VERSION_MASK 0xF0
+#define CCS811_ERR             0xE0
+/* Used to transition from boot to application mode */
+#define CCS811_APP_START       0xF4
+
+/* Status register flags */
+#define CCS811_STATUS_ERROR            BIT(0)
+#define CCS811_STATUS_DATA_READY       BIT(3)
+#define CCS811_STATUS_APP_VALID_MASK   BIT(4)
+#define CCS811_STATUS_APP_VALID_LOADED BIT(4)
+/*
+ * Value of FW_MODE bit of STATUS register describes the sensor's state:
+ * 0: Firmware is in boot mode, this allows new firmware to be loaded
+ * 1: Firmware is in application mode. CCS811 is ready to take ADC measurements
+ */
+#define CCS811_STATUS_FW_MODE_MASK     BIT(7)
+#define CCS811_STATUS_FW_MODE_APPLICATION      BIT(7)
+
+/* Measurement modes */
+#define CCS811_MODE_IDLE       0x00
+#define CCS811_MODE_IAQ_1SEC   0x10
+#define CCS811_MODE_IAQ_10SEC  0x20
+#define CCS811_MODE_IAQ_60SEC  0x30
+#define CCS811_MODE_RAW_DATA   0x40
+
+#define CCS811_VOLTAGE_MASK    0x3FF
+
+struct ccs811_reading {
+       __be16 co2;
+       __be16 voc;
+       u8 status;
+       u8 error;
+       __be16 resistance;
+} __attribute__((__packed__));
+
+struct ccs811_data {
+       struct i2c_client *client;
+       struct mutex lock; /* Protect readings */
+       struct ccs811_reading buffer;
+};
+
+static const struct iio_chan_spec ccs811_channels[] = {
+       {
+               .type = IIO_CURRENT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE)
+       }, {
+               .type = IIO_VOLTAGE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SCALE)
+       }, {
+               .type = IIO_CONCENTRATION,
+               .channel2 = IIO_MOD_CO2,
+               .modified = 1,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_OFFSET) |
+                                     BIT(IIO_CHAN_INFO_SCALE)
+       }, {
+               .type = IIO_CONCENTRATION,
+               .channel2 = IIO_MOD_VOC,
+               .modified = 1,
+               .info_mask_separate =  BIT(IIO_CHAN_INFO_RAW) |
+                                      BIT(IIO_CHAN_INFO_SCALE)
+       },
+};
+
+/*
+ * The CCS811 powers-up in boot mode. A setup write to CCS811_APP_START will
+ * transition the sensor to application mode.
+ */
+static int ccs811_start_sensor_application(struct i2c_client *client)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & CCS811_STATUS_APP_VALID_MASK) !=
+           CCS811_STATUS_APP_VALID_LOADED)
+               return -EIO;
+
+       ret = i2c_smbus_write_byte(client, CCS811_APP_START);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_read_byte_data(client, CCS811_STATUS);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & CCS811_STATUS_FW_MODE_MASK) !=
+           CCS811_STATUS_FW_MODE_APPLICATION) {
+               dev_err(&client->dev, "Application failed to start. Sensor is still in boot mode.\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int ccs811_setup(struct i2c_client *client)
+{
+       int ret;
+
+       ret = ccs811_start_sensor_application(client);
+       if (ret < 0)
+               return ret;
+
+       return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
+                                        CCS811_MODE_IAQ_1SEC);
+}
+
+static int ccs811_get_measurement(struct ccs811_data *data)
+{
+       int ret, tries = 11;
+
+       /* Maximum waiting time: 1s, as measurements are made every second */
+       while (tries-- > 0) {
+               ret = i2c_smbus_read_byte_data(data->client, CCS811_STATUS);
+               if (ret < 0)
+                       return ret;
+
+               if ((ret & CCS811_STATUS_DATA_READY) || tries == 0)
+                       break;
+               msleep(100);
+       }
+       if (!(ret & CCS811_STATUS_DATA_READY))
+               return -EIO;
+
+       return i2c_smbus_read_i2c_block_data(data->client,
+                                           CCS811_ALG_RESULT_DATA, 8,
+                                           (char *)&data->buffer);
+}
+
+static int ccs811_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *chan,
+                          int *val, int *val2, long mask)
+{
+       struct ccs811_data *data = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               mutex_lock(&data->lock);
+               ret = ccs811_get_measurement(data);
+               if (ret < 0) {
+                       mutex_unlock(&data->lock);
+                       return ret;
+               }
+
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       *val = be16_to_cpu(data->buffer.resistance) &
+                                          CCS811_VOLTAGE_MASK;
+                       ret = IIO_VAL_INT;
+                       break;
+               case IIO_CURRENT:
+                       *val = be16_to_cpu(data->buffer.resistance) >> 10;
+                       ret = IIO_VAL_INT;
+                       break;
+               case IIO_CONCENTRATION:
+                       switch (chan->channel2) {
+                       case IIO_MOD_CO2:
+                               *val = be16_to_cpu(data->buffer.co2);
+                               ret =  IIO_VAL_INT;
+                               break;
+                       case IIO_MOD_VOC:
+                               *val = be16_to_cpu(data->buffer.voc);
+                               ret = IIO_VAL_INT;
+                               break;
+                       default:
+                               ret = -EINVAL;
+                       }
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+               mutex_unlock(&data->lock);
+
+               return ret;
+
+       case IIO_CHAN_INFO_SCALE:
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       *val = 1;
+                       *val2 = 612903;
+                       return IIO_VAL_INT_PLUS_MICRO;
+               case IIO_CURRENT:
+                       *val = 0;
+                       *val2 = 1000;
+                       return IIO_VAL_INT_PLUS_MICRO;
+               case IIO_CONCENTRATION:
+                       switch (chan->channel2) {
+                       case IIO_MOD_CO2:
+                               *val = 0;
+                               *val2 = 12834;
+                               return IIO_VAL_INT_PLUS_MICRO;
+                       case IIO_MOD_VOC:
+                               *val = 0;
+                               *val2 = 84246;
+                               return IIO_VAL_INT_PLUS_MICRO;
+                       default:
+                               return -EINVAL;
+                       }
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_OFFSET:
+               if (!(chan->type == IIO_CONCENTRATION &&
+                     chan->channel2 == IIO_MOD_CO2))
+                       return -EINVAL;
+               *val = -400;
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info ccs811_info = {
+       .read_raw = ccs811_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static int ccs811_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct iio_dev *indio_dev;
+       struct ccs811_data *data;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE
+                                    | I2C_FUNC_SMBUS_BYTE_DATA
+                                    | I2C_FUNC_SMBUS_READ_I2C_BLOCK))
+               return -EOPNOTSUPP;
+
+       /* Check hardware id (should be 0x81 for this family of devices) */
+       ret = i2c_smbus_read_byte_data(client, CCS811_HW_ID);
+       if (ret < 0)
+               return ret;
+
+       if (ret != CCS881_HW_ID_VALUE) {
+               dev_err(&client->dev, "hardware id doesn't match CCS81x\n");
+               return -ENODEV;
+       }
+
+       ret = i2c_smbus_read_byte_data(client, CCS811_HW_VERSION);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & CCS811_HW_VERSION_MASK) != CCS811_HW_VERSION_VALUE) {
+               dev_err(&client->dev, "no CCS811 sensor\n");
+               return -ENODEV;
+       }
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       ret = ccs811_setup(client);
+       if (ret < 0)
+               return ret;
+
+       data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
+       data->client = client;
+
+       mutex_init(&data->lock);
+
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->name = id->name;
+       indio_dev->info = &ccs811_info;
+
+       indio_dev->channels = ccs811_channels;
+       indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
+
+       return iio_device_register(indio_dev);
+}
+
+static int ccs811_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+       iio_device_unregister(indio_dev);
+
+       return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
+                                        CCS811_MODE_IDLE);
+}
+
+static const struct i2c_device_id ccs811_id[] = {
+       {"ccs811", 0},
+       {       }
+};
+MODULE_DEVICE_TABLE(i2c, ccs811_id);
+
+static struct i2c_driver ccs811_driver = {
+       .driver = {
+               .name = "ccs811",
+       },
+       .probe = ccs811_probe,
+       .remove = ccs811_remove,
+       .id_table = ccs811_id,
+};
+module_i2c_driver(ccs811_driver);
+
+MODULE_AUTHOR("Narcisa Vasile <narcisaanamaria12@gmail.com>");
+MODULE_DESCRIPTION("CCS811 volatile organic compounds sensor");
+MODULE_LICENSE("GPL v2");
index 79c8c7cd70d5c6d74fc2e32cad372f8644233c6b..274868100fd088e382e228cdfd49ec0919f66eb5 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/iio/iio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/unaligned.h>
 #include <linux/iio/common/st_sensors.h>
 
@@ -345,6 +346,36 @@ static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
 
        return pdata;
 }
+
+/**
+ * st_sensors_of_name_probe() - device tree probe for ST sensor name
+ * @dev: driver model representation of the device.
+ * @match: the OF match table for the device, containing compatible strings
+ *     but also a .data field with the corresponding internal kernel name
+ *     used by this sensor.
+ * @name: device name buffer reference.
+ * @len: device name buffer length.
+ *
+ * In effect this function matches a compatible string to an internal kernel
+ * name for a certain sensor device, so that the rest of the autodetection can
+ * rely on that name from this point on. I2C/SPI devices will be renamed
+ * to match the internal kernel convention.
+ */
+void st_sensors_of_name_probe(struct device *dev,
+                             const struct of_device_id *match,
+                             char *name, int len)
+{
+       const struct of_device_id *of_id;
+
+       of_id = of_match_device(match, dev);
+       if (!of_id || !of_id->data)
+               return;
+
+       /* The name from the OF match takes precedence if present */
+       strncpy(name, of_id->data, len);
+       name[len - 1] = '\0';
+}
+EXPORT_SYMBOL(st_sensors_of_name_probe);
 #else
 static struct st_sensors_platform_data *st_sensors_of_probe(struct device *dev,
                struct st_sensors_platform_data *defdata)
index c83df4dbfcd73567440e8d186938644b6bf02c91..b81e48e9f27e0db1edf1c097e7412d0ab2c34fda 100644 (file)
@@ -79,35 +79,6 @@ void st_sensors_i2c_configure(struct iio_dev *indio_dev,
 }
 EXPORT_SYMBOL(st_sensors_i2c_configure);
 
-#ifdef CONFIG_OF
-/**
- * st_sensors_of_i2c_probe() - device tree probe for ST I2C sensors
- * @client: the I2C client device for the sensor
- * @match: the OF match table for the device, containing compatible strings
- *     but also a .data field with the corresponding internal kernel name
- *     used by this sensor.
- *
- * In effect this function matches a compatible string to an internal kernel
- * name for a certain sensor device, so that the rest of the autodetection can
- * rely on that name from this point on. I2C client devices will be renamed
- * to match the internal kernel convention.
- */
-void st_sensors_of_i2c_probe(struct i2c_client *client,
-                            const struct of_device_id *match)
-{
-       const struct of_device_id *of_id;
-
-       of_id = of_match_device(match, &client->dev);
-       if (!of_id)
-               return;
-
-       /* The name from the OF match takes precedence if present */
-       strncpy(client->name, of_id->data, sizeof(client->name));
-       client->name[sizeof(client->name) - 1] = '\0';
-}
-EXPORT_SYMBOL(st_sensors_of_i2c_probe);
-#endif
-
 #ifdef CONFIG_ACPI
 int st_sensors_match_acpi_device(struct device *dev)
 {
index 75e48788c7ead07923a7232b7de96f4986ad7d17..32701be71cf7b47218b4c2adda9f2797f30179b5 100644 (file)
@@ -42,6 +42,14 @@ struct stm32_dac_priv {
        struct stm32_dac_common common;
 };
 
+/**
+ * struct stm32_dac_cfg - DAC configuration
+ * @has_hfsel: DAC has high frequency control
+ */
+struct stm32_dac_cfg {
+       bool has_hfsel;
+};
+
 static struct stm32_dac_priv *to_stm32_dac_priv(struct stm32_dac_common *com)
 {
        return container_of(com, struct stm32_dac_priv, common);
@@ -57,6 +65,7 @@ static const struct regmap_config stm32_dac_regmap_cfg = {
 static int stm32_dac_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       const struct stm32_dac_cfg *cfg;
        struct stm32_dac_priv *priv;
        struct regmap *regmap;
        struct resource *res;
@@ -69,6 +78,8 @@ static int stm32_dac_probe(struct platform_device *pdev)
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
+       cfg = (const struct stm32_dac_cfg *)
+               of_match_device(dev->driver->of_match_table, dev)->data;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mmio = devm_ioremap_resource(dev, res);
@@ -121,12 +132,16 @@ static int stm32_dac_probe(struct platform_device *pdev)
                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;
+       if (cfg && cfg->has_hfsel) {
+               /* 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);
 
@@ -158,8 +173,17 @@ static int stm32_dac_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct stm32_dac_cfg stm32h7_dac_cfg = {
+       .has_hfsel = true,
+};
+
 static const struct of_device_id stm32_dac_of_match[] = {
-       { .compatible = "st,stm32h7-dac-core", },
+       {
+               .compatible = "st,stm32f4-dac-core",
+       }, {
+               .compatible = "st,stm32h7-dac-core",
+               .data = (void *)&stm32h7_dac_cfg,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
index 50f8ec091058bc1f9b602b77ace89302c8a3e61a..c1864e8aa851f6040250407d5260d6a4c80fbcbb 100644 (file)
@@ -268,7 +268,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
                        break;
        }
        if (i >= ARRAY_SIZE(stm32_dac_channels)) {
-               dev_err(&indio_dev->dev, "Invalid st,dac-channel\n");
+               dev_err(&indio_dev->dev, "Invalid reg property\n");
                return -EINVAL;
        }
 
index 2be2a5d287e694516157b3a8cb430bd7839f43d2..e0d241a9aa3033a532eb228baeb7f149b95e4c6f 100644 (file)
@@ -1063,11 +1063,6 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq)
        case IRQF_TRIGGER_RISING:
                dev_info(&indio_dev->dev,
                         "pulse interrupts on the rising edge\n");
-               if (mpu3050->irq_opendrain) {
-                       dev_info(&indio_dev->dev,
-                                "rising edge incompatible with open drain\n");
-                       mpu3050->irq_opendrain = false;
-               }
                break;
        case IRQF_TRIGGER_FALLING:
                mpu3050->irq_actl = true;
@@ -1078,11 +1073,6 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq)
                mpu3050->irq_latch = true;
                dev_info(&indio_dev->dev,
                         "interrupts active high level\n");
-               if (mpu3050->irq_opendrain) {
-                       dev_info(&indio_dev->dev,
-                                "active high incompatible with open drain\n");
-                       mpu3050->irq_opendrain = false;
-               }
                /*
                 * With level IRQs, we mask the IRQ until it is processed,
                 * but with edge IRQs (pulses) we can queue several interrupts
index a5c5c4e29addc38a94c4a5683f64904550ed32d2..48923ae6ac3bd04051e1640f31c65302bf38bf8a 100644 (file)
@@ -19,6 +19,7 @@
 #define LSM330DL_GYRO_DEV_NAME         "lsm330dl_gyro"
 #define LSM330DLC_GYRO_DEV_NAME                "lsm330dlc_gyro"
 #define L3GD20_GYRO_DEV_NAME           "l3gd20"
+#define L3GD20H_GYRO_DEV_NAME          "l3gd20h"
 #define L3G4IS_GYRO_DEV_NAME           "l3g4is_ui"
 #define LSM330_GYRO_DEV_NAME           "lsm330_gyro"
 #define LSM9DS0_GYRO_DEV_NAME          "lsm9ds0_gyro"
index 2a42b3d583e85b45d9f93c9b1400e8551eac034a..e366422e85127f27f2ab1df6a47019755af8d52d 100644 (file)
@@ -35,6 +35,7 @@
 #define ST_GYRO_DEFAULT_OUT_Z_L_ADDR           0x2c
 
 /* FULLSCALE */
+#define ST_GYRO_FS_AVL_245DPS                  245
 #define ST_GYRO_FS_AVL_250DPS                  250
 #define ST_GYRO_FS_AVL_500DPS                  500
 #define ST_GYRO_FS_AVL_2000DPS                 2000
@@ -196,17 +197,17 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
                .wai = 0xd7,
                .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
                .sensors_supported = {
-                       [0] = L3GD20_GYRO_DEV_NAME,
+                       [0] = L3GD20H_GYRO_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_gyro_16bit_channels,
                .odr = {
                        .addr = 0x20,
                        .mask = 0xc0,
                        .odr_avl = {
-                               { .hz = 95, .value = 0x00, },
-                               { .hz = 190, .value = 0x01, },
-                               { .hz = 380, .value = 0x02, },
-                               { .hz = 760, .value = 0x03, },
+                               { .hz = 100, .value = 0x00, },
+                               { .hz = 200, .value = 0x01, },
+                               { .hz = 400, .value = 0x02, },
+                               { .hz = 800, .value = 0x03, },
                        },
                },
                .pw = {
@@ -224,7 +225,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
                        .mask = 0x30,
                        .fs_avl = {
                                [0] = {
-                                       .num = ST_GYRO_FS_AVL_250DPS,
+                                       .num = ST_GYRO_FS_AVL_245DPS,
                                        .value = 0x00,
                                        .gain = IIO_DEGREE_TO_RAD(8750),
                                },
index 40056b82103640b467db0c10733555476928aaec..b405b82b91772424ed75546ccfa60f33cce5e98a 100644 (file)
@@ -40,6 +40,10 @@ static const struct of_device_id st_gyro_of_match[] = {
                .compatible = "st,l3gd20-gyro",
                .data = L3GD20_GYRO_DEV_NAME,
        },
+       {
+               .compatible = "st,l3gd20h-gyro",
+               .data = L3GD20H_GYRO_DEV_NAME,
+       },
        {
                .compatible = "st,l3g4is-gyro",
                .data = L3G4IS_GYRO_DEV_NAME,
@@ -71,7 +75,8 @@ static int st_gyro_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        gdata = iio_priv(indio_dev);
-       st_sensors_of_i2c_probe(client, st_gyro_of_match);
+       st_sensors_of_name_probe(&client->dev, st_gyro_of_match,
+                                client->name, sizeof(client->name));
 
        st_sensors_i2c_configure(indio_dev, client, gdata);
 
@@ -95,6 +100,7 @@ static const struct i2c_device_id st_gyro_id_table[] = {
        { LSM330DL_GYRO_DEV_NAME },
        { LSM330DLC_GYRO_DEV_NAME },
        { L3GD20_GYRO_DEV_NAME },
+       { L3GD20H_GYRO_DEV_NAME },
        { L3G4IS_GYRO_DEV_NAME },
        { LSM330_GYRO_DEV_NAME },
        { LSM9DS0_GYRO_DEV_NAME },
index fbf2faed501c8628ed23d0ff0fa7590f6e091c01..0b52ed577dc21c26b8b40de9d82ff4e1448418ee 100644 (file)
 #include <linux/iio/common/st_sensors_spi.h>
 #include "st_gyro.h"
 
+#ifdef CONFIG_OF
+/*
+ * For new single-chip sensors use <device_name> as compatible string.
+ * For old single-chip devices keep <device_name>-gyro to maintain
+ * compatibility
+ */
+static const struct of_device_id st_gyro_of_match[] = {
+       {
+               .compatible = "st,l3g4200d-gyro",
+               .data = L3G4200D_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330d-gyro",
+               .data = LSM330D_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330dl-gyro",
+               .data = LSM330DL_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330dlc-gyro",
+               .data = LSM330DLC_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,l3gd20-gyro",
+               .data = L3GD20_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,l3gd20h-gyro",
+               .data = L3GD20H_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,l3g4is-gyro",
+               .data = L3G4IS_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm330-gyro",
+               .data = LSM330_GYRO_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm9ds0-gyro",
+               .data = LSM9DS0_GYRO_DEV_NAME,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, st_gyro_of_match);
+#else
+#define st_gyro_of_match       NULL
+#endif
+
 static int st_gyro_spi_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
@@ -30,6 +80,8 @@ static int st_gyro_spi_probe(struct spi_device *spi)
 
        gdata = iio_priv(indio_dev);
 
+       st_sensors_of_name_probe(&spi->dev, st_gyro_of_match,
+                                spi->modalias, sizeof(spi->modalias));
        st_sensors_spi_configure(indio_dev, spi, gdata);
 
        err = st_gyro_common_probe(indio_dev);
@@ -52,6 +104,7 @@ static const struct spi_device_id st_gyro_id_table[] = {
        { LSM330DL_GYRO_DEV_NAME },
        { LSM330DLC_GYRO_DEV_NAME },
        { L3GD20_GYRO_DEV_NAME },
+       { L3GD20H_GYRO_DEV_NAME },
        { L3G4IS_GYRO_DEV_NAME },
        { LSM330_GYRO_DEV_NAME },
        { LSM9DS0_GYRO_DEV_NAME },
@@ -62,6 +115,7 @@ MODULE_DEVICE_TABLE(spi, st_gyro_id_table);
 static struct spi_driver st_gyro_driver = {
        .driver = {
                .name = "st-gyro-spi",
+               .of_match_table = of_match_ptr(st_gyro_of_match),
        },
        .probe = st_gyro_spi_probe,
        .remove = st_gyro_spi_remove,
index 14b9ce453d9de004cd51459857e68667ff0cdd00..2c0fc9a400b8d3d799421eb5c03c472f2de2661f 100644 (file)
@@ -31,7 +31,8 @@ config HDC100X
        select IIO_TRIGGERED_BUFFER
        help
          Say yes here to build support for the Texas Instruments
-         HDC1000 and HDC1008 relative humidity and temperature sensors.
+         HDC1000, HDC1008, HDC1010, HDC1050, and HDC1080 relative
+         humidity and temperature sensors.
 
          To compile this driver as a module, choose M here: the module
          will be called hdc100x.
index aa17115f54c91a8fb104b31146b307b392db6ef8..7851bd90ef64e2ef3cf9313d591a8e328b433fe8 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
+ * Datasheets:
+ * http://www.ti.com/product/HDC1000/datasheet
+ * http://www.ti.com/product/HDC1008/datasheet
+ * http://www.ti.com/product/HDC1010/datasheet
+ * http://www.ti.com/product/HDC1050/datasheet
+ * http://www.ti.com/product/HDC1080/datasheet
  */
 
 #include <linux/delay.h>
@@ -414,13 +420,29 @@ static int hdc100x_remove(struct i2c_client *client)
 
 static const struct i2c_device_id hdc100x_id[] = {
        { "hdc100x", 0 },
+       { "hdc1000", 0 },
+       { "hdc1008", 0 },
+       { "hdc1010", 0 },
+       { "hdc1050", 0 },
+       { "hdc1080", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, hdc100x_id);
 
+static const struct of_device_id hdc100x_dt_ids[] = {
+       { .compatible = "ti,hdc1000" },
+       { .compatible = "ti,hdc1008" },
+       { .compatible = "ti,hdc1010" },
+       { .compatible = "ti,hdc1050" },
+       { .compatible = "ti,hdc1080" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, hdc100x_dt_ids);
+
 static struct i2c_driver hdc100x_driver = {
        .driver = {
                .name   = "hdc100x",
+               .of_match_table = of_match_ptr(hdc100x_dt_ids),
        },
        .probe = hdc100x_probe,
        .remove = hdc100x_remove,
index 94510266e0a51e5844a7ca25528e2b7a3564292a..51d021966222f572dd4300a1f77c3ea0d5385d50 100644 (file)
@@ -30,12 +30,6 @@ struct hts221_transfer_function {
        int (*write)(struct device *dev, u8 addr, int len, u8 *data);
 };
 
-#define HTS221_AVG_DEPTH       8
-struct hts221_avg_avl {
-       u16 avg;
-       u8 val;
-};
-
 enum hts221_sensor_type {
        HTS221_SENSOR_H,
        HTS221_SENSOR_T,
@@ -66,10 +60,9 @@ struct hts221_hw {
 
 extern const struct dev_pm_ops hts221_pm_ops;
 
-int hts221_config_drdy(struct hts221_hw *hw, bool enable);
+int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val);
 int hts221_probe(struct iio_dev *iio_dev);
-int hts221_power_on(struct hts221_hw *hw);
-int hts221_power_off(struct hts221_hw *hw);
+int hts221_set_enable(struct hts221_hw *hw, bool enable);
 int hts221_allocate_buffers(struct hts221_hw *hw);
 int hts221_allocate_trigger(struct hts221_hw *hw);
 
index 7d19a3da7ab740394463a0ed2c3128ea57ea5dff..9690dfe9a844486ef810101d951f9f1285292615 100644 (file)
 #include <linux/iio/triggered_buffer.h>
 #include <linux/iio/buffer.h>
 
+#include <linux/platform_data/st_sensors_pdata.h>
+
 #include "hts221.h"
 
+#define HTS221_REG_DRDY_HL_ADDR                0x22
+#define HTS221_REG_DRDY_HL_MASK                BIT(7)
+#define HTS221_REG_DRDY_PP_OD_ADDR     0x22
+#define HTS221_REG_DRDY_PP_OD_MASK     BIT(6)
+#define HTS221_REG_DRDY_EN_ADDR                0x22
+#define HTS221_REG_DRDY_EN_MASK                BIT(2)
 #define HTS221_REG_STATUS_ADDR         0x27
 #define HTS221_RH_DRDY_MASK            BIT(1)
 #define HTS221_TEMP_DRDY_MASK          BIT(0)
@@ -30,8 +38,12 @@ static int hts221_trig_set_state(struct iio_trigger *trig, bool state)
 {
        struct iio_dev *iio_dev = iio_trigger_get_drvdata(trig);
        struct hts221_hw *hw = iio_priv(iio_dev);
+       int err;
+
+       err = hts221_write_with_mask(hw, HTS221_REG_DRDY_EN_ADDR,
+                                    HTS221_REG_DRDY_EN_MASK, state);
 
-       return hts221_config_drdy(hw, state);
+       return err < 0 ? err : 0;
 }
 
 static const struct iio_trigger_ops hts221_trigger_ops = {
@@ -67,6 +79,9 @@ static irqreturn_t hts221_trigger_handler_thread(int irq, void *private)
 int hts221_allocate_trigger(struct hts221_hw *hw)
 {
        struct iio_dev *iio_dev = iio_priv_to_dev(hw);
+       bool irq_active_low = false, open_drain = false;
+       struct device_node *np = hw->dev->of_node;
+       struct st_sensors_platform_data *pdata;
        unsigned long irq_type;
        int err;
 
@@ -76,6 +91,10 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
        case IRQF_TRIGGER_HIGH:
        case IRQF_TRIGGER_RISING:
                break;
+       case IRQF_TRIGGER_LOW:
+       case IRQF_TRIGGER_FALLING:
+               irq_active_low = true;
+               break;
        default:
                dev_info(hw->dev,
                         "mode %lx unsupported, using IRQF_TRIGGER_RISING\n",
@@ -84,6 +103,24 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
                break;
        }
 
+       err = hts221_write_with_mask(hw, HTS221_REG_DRDY_HL_ADDR,
+                                    HTS221_REG_DRDY_HL_MASK, irq_active_low);
+       if (err < 0)
+               return err;
+
+       pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
+       if ((np && of_property_read_bool(np, "drive-open-drain")) ||
+           (pdata && pdata->open_drain)) {
+               irq_type |= IRQF_SHARED;
+               open_drain = true;
+       }
+
+       err = hts221_write_with_mask(hw, HTS221_REG_DRDY_PP_OD_ADDR,
+                                    HTS221_REG_DRDY_PP_OD_MASK,
+                                    open_drain);
+       if (err < 0)
+               return err;
+
        err = devm_request_threaded_irq(hw->dev, hw->irq, NULL,
                                        hts221_trigger_handler_thread,
                                        irq_type | IRQF_ONESHOT,
@@ -109,12 +146,12 @@ int hts221_allocate_trigger(struct hts221_hw *hw)
 
 static int hts221_buffer_preenable(struct iio_dev *iio_dev)
 {
-       return hts221_power_on(iio_priv(iio_dev));
+       return hts221_set_enable(iio_priv(iio_dev), true);
 }
 
 static int hts221_buffer_postdisable(struct iio_dev *iio_dev)
 {
-       return hts221_power_off(iio_priv(iio_dev));
+       return hts221_set_enable(iio_priv(iio_dev), false);
 }
 
 static const struct iio_buffer_setup_ops hts221_buffer_ops = {
index a56da3999e00a89b82001bb0a8c8aabb671e8ea2..32524a8dc66f6555ee155792284377f03b57d8b1 100644 (file)
@@ -23,7 +23,6 @@
 
 #define HTS221_REG_CNTRL1_ADDR         0x20
 #define HTS221_REG_CNTRL2_ADDR         0x21
-#define HTS221_REG_CNTRL3_ADDR         0x22
 
 #define HTS221_REG_AVG_ADDR            0x10
 #define HTS221_REG_H_OUT_L             0x28
 #define HTS221_HUMIDITY_AVG_MASK       0x07
 #define HTS221_TEMP_AVG_MASK           0x38
 
-#define HTS221_ODR_MASK                        0x87
+#define HTS221_ODR_MASK                        0x03
 #define HTS221_BDU_MASK                        BIT(2)
-
-#define HTS221_DRDY_MASK               BIT(2)
-
-#define HTS221_ENABLE_SENSOR           BIT(7)
-
-#define HTS221_HUMIDITY_AVG_4          0x00 /* 0.4 %RH */
-#define HTS221_HUMIDITY_AVG_8          0x01 /* 0.3 %RH */
-#define HTS221_HUMIDITY_AVG_16         0x02 /* 0.2 %RH */
-#define HTS221_HUMIDITY_AVG_32         0x03 /* 0.15 %RH */
-#define HTS221_HUMIDITY_AVG_64         0x04 /* 0.1 %RH */
-#define HTS221_HUMIDITY_AVG_128                0x05 /* 0.07 %RH */
-#define HTS221_HUMIDITY_AVG_256                0x06 /* 0.05 %RH */
-#define HTS221_HUMIDITY_AVG_512                0x07 /* 0.03 %RH */
-
-#define HTS221_TEMP_AVG_2              0x00 /* 0.08 degC */
-#define HTS221_TEMP_AVG_4              0x08 /* 0.05 degC */
-#define HTS221_TEMP_AVG_8              0x10 /* 0.04 degC */
-#define HTS221_TEMP_AVG_16             0x18 /* 0.03 degC */
-#define HTS221_TEMP_AVG_32             0x20 /* 0.02 degC */
-#define HTS221_TEMP_AVG_64             0x28 /* 0.015 degC */
-#define HTS221_TEMP_AVG_128            0x30 /* 0.01 degC */
-#define HTS221_TEMP_AVG_256            0x38 /* 0.007 degC */
+#define HTS221_ENABLE_MASK             BIT(7)
 
 /* calibration registers */
 #define HTS221_REG_0RH_CAL_X_H         0x36
@@ -73,10 +51,11 @@ struct hts221_odr {
        u8 val;
 };
 
+#define HTS221_AVG_DEPTH               8
 struct hts221_avg {
        u8 addr;
        u8 mask;
-       struct hts221_avg_avl avg_avl[HTS221_AVG_DEPTH];
+       u16 avg_avl[HTS221_AVG_DEPTH];
 };
 
 static const struct hts221_odr hts221_odr_table[] = {
@@ -90,28 +69,28 @@ static const struct hts221_avg hts221_avg_list[] = {
                .addr = HTS221_REG_AVG_ADDR,
                .mask = HTS221_HUMIDITY_AVG_MASK,
                .avg_avl = {
-                       { 4, HTS221_HUMIDITY_AVG_4 },
-                       { 8, HTS221_HUMIDITY_AVG_8 },
-                       { 16, HTS221_HUMIDITY_AVG_16 },
-                       { 32, HTS221_HUMIDITY_AVG_32 },
-                       { 64, HTS221_HUMIDITY_AVG_64 },
-                       { 128, HTS221_HUMIDITY_AVG_128 },
-                       { 256, HTS221_HUMIDITY_AVG_256 },
-                       { 512, HTS221_HUMIDITY_AVG_512 },
+                       4, /* 0.4 %RH */
+                       8, /* 0.3 %RH */
+                       16, /* 0.2 %RH */
+                       32, /* 0.15 %RH */
+                       64, /* 0.1 %RH */
+                       128, /* 0.07 %RH */
+                       256, /* 0.05 %RH */
+                       512, /* 0.03 %RH */
                },
        },
        {
                .addr = HTS221_REG_AVG_ADDR,
                .mask = HTS221_TEMP_AVG_MASK,
                .avg_avl = {
-                       { 2, HTS221_TEMP_AVG_2 },
-                       { 4, HTS221_TEMP_AVG_4 },
-                       { 8, HTS221_TEMP_AVG_8 },
-                       { 16, HTS221_TEMP_AVG_16 },
-                       { 32, HTS221_TEMP_AVG_32 },
-                       { 64, HTS221_TEMP_AVG_64 },
-                       { 128, HTS221_TEMP_AVG_128 },
-                       { 256, HTS221_TEMP_AVG_256 },
+                       2, /* 0.08 degC */
+                       4, /* 0.05 degC */
+                       8, /* 0.04 degC */
+                       16, /* 0.03 degC */
+                       32, /* 0.02 degC */
+                       64, /* 0.015 degC */
+                       128, /* 0.01 degC */
+                       256, /* 0.007 degC */
                },
        },
 };
@@ -152,8 +131,7 @@ static const struct iio_chan_spec hts221_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
-static int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask,
-                                 u8 val)
+int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask, u8 val)
 {
        u8 data;
        int err;
@@ -166,7 +144,7 @@ static int hts221_write_with_mask(struct hts221_hw *hw, u8 addr, u8 mask,
                goto unlock;
        }
 
-       data = (data & ~mask) | (val & mask);
+       data = (data & ~mask) | ((val << __ffs(mask)) & mask);
 
        err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
        if (err < 0)
@@ -199,21 +177,9 @@ static int hts221_check_whoami(struct hts221_hw *hw)
        return 0;
 }
 
-int hts221_config_drdy(struct hts221_hw *hw, bool enable)
-{
-       u8 val = enable ? BIT(2) : 0;
-       int err;
-
-       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL3_ADDR,
-                                    HTS221_DRDY_MASK, val);
-
-       return err < 0 ? err : 0;
-}
-
 static int hts221_update_odr(struct hts221_hw *hw, u8 odr)
 {
        int i, err;
-       u8 val;
 
        for (i = 0; i < ARRAY_SIZE(hts221_odr_table); i++)
                if (hts221_odr_table[i].hz == odr)
@@ -222,9 +188,8 @@ static int hts221_update_odr(struct hts221_hw *hw, u8 odr)
        if (i == ARRAY_SIZE(hts221_odr_table))
                return -EINVAL;
 
-       val = HTS221_ENABLE_SENSOR | HTS221_BDU_MASK | hts221_odr_table[i].val;
        err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
-                                    HTS221_ODR_MASK, val);
+                                    HTS221_ODR_MASK, hts221_odr_table[i].val);
        if (err < 0)
                return err;
 
@@ -241,14 +206,13 @@ static int hts221_update_avg(struct hts221_hw *hw,
        const struct hts221_avg *avg = &hts221_avg_list[type];
 
        for (i = 0; i < HTS221_AVG_DEPTH; i++)
-               if (avg->avg_avl[i].avg == val)
+               if (avg->avg_avl[i] == val)
                        break;
 
        if (i == HTS221_AVG_DEPTH)
                return -EINVAL;
 
-       err = hts221_write_with_mask(hw, avg->addr, avg->mask,
-                                    avg->avg_avl[i].val);
+       err = hts221_write_with_mask(hw, avg->addr, avg->mask, i);
        if (err < 0)
                return err;
 
@@ -283,7 +247,7 @@ hts221_sysfs_rh_oversampling_avail(struct device *dev,
 
        for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)
                len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
-                                avg->avg_avl[i].avg);
+                                avg->avg_avl[i]);
        buf[len - 1] = '\n';
 
        return len;
@@ -300,36 +264,22 @@ hts221_sysfs_temp_oversampling_avail(struct device *dev,
 
        for (i = 0; i < ARRAY_SIZE(avg->avg_avl); i++)
                len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
-                                avg->avg_avl[i].avg);
+                                avg->avg_avl[i]);
        buf[len - 1] = '\n';
 
        return len;
 }
 
-int hts221_power_on(struct hts221_hw *hw)
-{
-       int err;
-
-       err = hts221_update_odr(hw, hw->odr);
-       if (err < 0)
-               return err;
-
-       hw->enabled = true;
-
-       return 0;
-}
-
-int hts221_power_off(struct hts221_hw *hw)
+int hts221_set_enable(struct hts221_hw *hw, bool enable)
 {
-       __le16 data = 0;
        int err;
 
-       err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
-                           (u8 *)&data);
+       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
+                                    HTS221_ENABLE_MASK, enable);
        if (err < 0)
                return err;
 
-       hw->enabled = false;
+       hw->enabled = enable;
 
        return 0;
 }
@@ -484,7 +434,7 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
        u8 data[HTS221_DATA_SIZE];
        int err;
 
-       err = hts221_power_on(hw);
+       err = hts221_set_enable(hw, true);
        if (err < 0)
                return err;
 
@@ -494,7 +444,7 @@ static int hts221_read_oneshot(struct hts221_hw *hw, u8 addr, int *val)
        if (err < 0)
                return err;
 
-       hts221_power_off(hw);
+       hts221_set_enable(hw, false);
 
        *val = (s16)get_unaligned_le16(data);
 
@@ -534,13 +484,13 @@ static int hts221_read_raw(struct iio_dev *iio_dev,
                case IIO_HUMIDITYRELATIVE:
                        avg = &hts221_avg_list[HTS221_SENSOR_H];
                        idx = hw->sensors[HTS221_SENSOR_H].cur_avg_idx;
-                       *val = avg->avg_avl[idx].avg;
+                       *val = avg->avg_avl[idx];
                        ret = IIO_VAL_INT;
                        break;
                case IIO_TEMP:
                        avg = &hts221_avg_list[HTS221_SENSOR_T];
                        idx = hw->sensors[HTS221_SENSOR_T].cur_avg_idx;
-                       *val = avg->avg_avl[idx].avg;
+                       *val = avg->avg_avl[idx];
                        ret = IIO_VAL_INT;
                        break;
                default:
@@ -644,8 +594,6 @@ int hts221_probe(struct iio_dev *iio_dev)
        if (err < 0)
                return err;
 
-       hw->odr = hts221_odr_table[0].hz;
-
        iio_dev->modes = INDIO_DIRECT_MODE;
        iio_dev->dev.parent = hw->dev;
        iio_dev->available_scan_masks = hts221_scan_masks;
@@ -654,6 +602,16 @@ int hts221_probe(struct iio_dev *iio_dev)
        iio_dev->name = HTS221_DEV_NAME;
        iio_dev->info = &hts221_info;
 
+       /* enable Block Data Update */
+       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
+                                    HTS221_BDU_MASK, 1);
+       if (err < 0)
+               return err;
+
+       err = hts221_update_odr(hw, hts221_odr_table[0].hz);
+       if (err < 0)
+               return err;
+
        /* configure humidity sensor */
        err = hts221_parse_rh_caldata(hw);
        if (err < 0) {
@@ -661,7 +619,7 @@ int hts221_probe(struct iio_dev *iio_dev)
                return err;
        }
 
-       data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3].avg;
+       data = hts221_avg_list[HTS221_SENSOR_H].avg_avl[3];
        err = hts221_update_avg(hw, HTS221_SENSOR_H, data);
        if (err < 0) {
                dev_err(hw->dev, "failed to set rh oversampling ratio\n");
@@ -676,7 +634,7 @@ int hts221_probe(struct iio_dev *iio_dev)
                return err;
        }
 
-       data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3].avg;
+       data = hts221_avg_list[HTS221_SENSOR_T].avg_avl[3];
        err = hts221_update_avg(hw, HTS221_SENSOR_T, data);
        if (err < 0) {
                dev_err(hw->dev,
@@ -702,11 +660,10 @@ static int __maybe_unused hts221_suspend(struct device *dev)
 {
        struct iio_dev *iio_dev = dev_get_drvdata(dev);
        struct hts221_hw *hw = iio_priv(iio_dev);
-       __le16 data = 0;
        int err;
 
-       err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
-                           (u8 *)&data);
+       err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
+                                    HTS221_ENABLE_MASK, false);
 
        return err < 0 ? err : 0;
 }
@@ -718,7 +675,8 @@ static int __maybe_unused hts221_resume(struct device *dev)
        int err = 0;
 
        if (hw->enabled)
-               err = hts221_update_odr(hw, hw->odr);
+               err = hts221_write_with_mask(hw, HTS221_REG_CNTRL1_ADDR,
+                                            HTS221_ENABLE_MASK, true);
 
        return err;
 }
index 0fbbd8c408945358fbdc58510d539ab24717be13..2c4b9be85a05a95b7980ddb3b2146033a120c566 100644 (file)
@@ -238,11 +238,19 @@ static const struct i2c_device_id htu21_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, htu21_id);
 
+static const struct of_device_id htu21_of_match[] = {
+       { .compatible = "meas,htu21", },
+       { .compatible = "meas,ms8607-humidity", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, htu21_of_match);
+
 static struct i2c_driver htu21_driver = {
        .probe = htu21_probe,
        .id_table = htu21_id,
        .driver = {
                   .name = "htu21",
+                  .of_match_table = of_match_ptr(htu21_of_match),
                   },
 };
 
index fb7c0dbed51cb9b78872949a1807c1e610d8a056..9b697d35dbef04b4ba6a97b1ddc6085c30774017 100644 (file)
@@ -217,7 +217,7 @@ static int adis16400_set_freq(struct adis16400_state *st, unsigned int freq)
        return adis_write_reg_8(&st->adis, ADIS16400_SMPL_PRD, val);
 }
 
-static const unsigned adis16400_3db_divisors[] = {
+static const unsigned int adis16400_3db_divisors[] = {
        [0] = 2, /* Special case */
        [1] = 6,
        [2] = 12,
@@ -890,7 +890,7 @@ static const struct adis_data adis16400_data = {
 static void adis16400_setup_chan_mask(struct adis16400_state *st)
 {
        const struct adis16400_chip_info *chip_info = st->variant;
-       unsigned i;
+       unsigned int i;
 
        for (i = 0; i < chip_info->num_channels; i++) {
                const struct iio_chan_spec *ch = &chip_info->channels[i];
index 2a72acc6e0493e48ae6391ae38c29da24fb38d5b..e2737dc71b677665a5a67b319d1a8c22a91b0efc 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/buffer.h>
 
+#include <linux/platform_data/st_sensors_pdata.h>
+
 #include "st_lsm6dsx.h"
 
 #define ST_LSM6DSX_REG_FIFO_THL_ADDR           0x06
@@ -39,6 +41,8 @@
 #define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR       0x08
 #define ST_LSM6DSX_REG_HLACTIVE_ADDR           0x12
 #define ST_LSM6DSX_REG_HLACTIVE_MASK           BIT(5)
+#define ST_LSM6DSX_REG_PP_OD_ADDR              0x12
+#define ST_LSM6DSX_REG_PP_OD_MASK              BIT(4)
 #define ST_LSM6DSX_REG_FIFO_MODE_ADDR          0x0a
 #define ST_LSM6DSX_FIFO_MODE_MASK              GENMASK(2, 0)
 #define ST_LSM6DSX_FIFO_ODR_MASK               GENMASK(6, 3)
@@ -417,6 +421,8 @@ static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
 
 int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
 {
+       struct device_node *np = hw->dev->of_node;
+       struct st_sensors_platform_data *pdata;
        struct iio_buffer *buffer;
        unsigned long irq_type;
        bool irq_active_low;
@@ -444,6 +450,17 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
        if (err < 0)
                return err;
 
+       pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
+       if ((np && of_property_read_bool(np, "drive-open-drain")) ||
+           (pdata && pdata->open_drain)) {
+               err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_PP_OD_ADDR,
+                                                ST_LSM6DSX_REG_PP_OD_MASK, 1);
+               if (err < 0)
+                       return err;
+
+               irq_type |= IRQF_SHARED;
+       }
+
        err = devm_request_threaded_irq(hw->dev, hw->irq,
                                        st_lsm6dsx_handler_irq,
                                        st_lsm6dsx_handler_thread,
index da3d06b073bb2af2b51faa63601ade8b17320212..069defcc6d9bec73438c292ec98ac3d4195833c6 100644 (file)
@@ -44,7 +44,7 @@ int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
                }
                mapi->map = &maps[i];
                mapi->indio_dev = indio_dev;
-               list_add(&mapi->l, &iio_map_list);
+               list_add_tail(&mapi->l, &iio_map_list);
                i++;
        }
 error_ret:
@@ -205,8 +205,8 @@ static struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
                if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
                        break;
                else if (name && index >= 0) {
-                       pr_err("ERROR: could not get IIO channel %s:%s(%i)\n",
-                               np->full_name, name ? name : "", index);
+                       pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n",
+                               np, name ? name : "", index);
                        return NULL;
                }
 
index 9d0c2e859bb2935a81966d4fadd9c6b94f194f32..a6efa12613a26234d6b2135b935b7a825714e8d2 100644 (file)
@@ -9,7 +9,7 @@
  *
  * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38).
  *
- * TODO: illuminance channel, buffer
+ * TODO: illuminance channel
  */
 
 #include <linux/module.h>
 #include <linux/acpi.h>
 
 #include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 #include <linux/iio/sysfs.h>
 #include <linux/pm_runtime.h>
 
@@ -30,6 +34,7 @@
 #define RPR0521_REG_PXS_DATA           0x44 /* 16-bit, little endian */
 #define RPR0521_REG_ALS_DATA0          0x46 /* 16-bit, little endian */
 #define RPR0521_REG_ALS_DATA1          0x48 /* 16-bit, little endian */
+#define RPR0521_REG_INTERRUPT          0x4A
 #define RPR0521_REG_PS_OFFSET_LSB      0x53
 #define RPR0521_REG_ID                 0x92
 
 #define RPR0521_ALS_DATA1_GAIN_SHIFT   2
 #define RPR0521_PXS_GAIN_MASK          GENMASK(5, 4)
 #define RPR0521_PXS_GAIN_SHIFT         4
+#define RPR0521_PXS_PERSISTENCE_MASK   GENMASK(3, 0)
+#define RPR0521_INTERRUPT_INT_TRIG_PS_MASK     BIT(0)
+#define RPR0521_INTERRUPT_INT_TRIG_ALS_MASK    BIT(1)
+#define RPR0521_INTERRUPT_INT_REASSERT_MASK    BIT(3)
+#define RPR0521_INTERRUPT_ALS_INT_STATUS_MASK  BIT(6)
+#define RPR0521_INTERRUPT_PS_INT_STATUS_MASK   BIT(7)
 
 #define RPR0521_MODE_ALS_ENABLE                BIT(7)
 #define RPR0521_MODE_ALS_DISABLE       0x00
 #define RPR0521_MODE_PXS_ENABLE                BIT(6)
 #define RPR0521_MODE_PXS_DISABLE       0x00
+#define RPR0521_PXS_PERSISTENCE_DRDY   0x00
+
+#define RPR0521_INTERRUPT_INT_TRIG_PS_ENABLE   BIT(0)
+#define RPR0521_INTERRUPT_INT_TRIG_PS_DISABLE  0x00
+#define RPR0521_INTERRUPT_INT_TRIG_ALS_ENABLE  BIT(1)
+#define RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE 0x00
+#define RPR0521_INTERRUPT_INT_REASSERT_ENABLE  BIT(3)
+#define RPR0521_INTERRUPT_INT_REASSERT_DISABLE 0x00
 
 #define RPR0521_MANUFACT_ID            0xE0
 #define RPR0521_DEFAULT_MEAS_TIME      0x06 /* ALS - 100ms, PXS - 100ms */
 
 #define RPR0521_DRV_NAME               "RPR0521"
+#define RPR0521_IRQ_NAME               "rpr0521_event"
 #define RPR0521_REGMAP_NAME            "rpr0521_regmap"
 
 #define RPR0521_SLEEP_DELAY_MS 2000
@@ -167,6 +187,9 @@ struct rpr0521_data {
        bool als_dev_en;
        bool pxs_dev_en;
 
+       struct iio_trigger *drdy_trigger0;
+       s64 irq_timestamp;
+
        /* optimize runtime pm ops - enable/disable device only if needed */
        bool als_ps_need_en;
        bool pxs_ps_need_en;
@@ -196,6 +219,19 @@ static const struct attribute_group rpr0521_attribute_group = {
        .attrs = rpr0521_attributes,
 };
 
+/* Order of the channel data in buffer */
+enum rpr0521_scan_index_order {
+       RPR0521_CHAN_INDEX_PXS,
+       RPR0521_CHAN_INDEX_BOTH,
+       RPR0521_CHAN_INDEX_IR,
+};
+
+static const unsigned long rpr0521_available_scan_masks[] = {
+       BIT(RPR0521_CHAN_INDEX_PXS) | BIT(RPR0521_CHAN_INDEX_BOTH) |
+       BIT(RPR0521_CHAN_INDEX_IR),
+       0
+};
+
 static const struct iio_chan_spec rpr0521_channels[] = {
        {
                .type = IIO_PROXIMITY,
@@ -204,6 +240,13 @@ static const struct iio_chan_spec rpr0521_channels[] = {
                        BIT(IIO_CHAN_INFO_OFFSET) |
                        BIT(IIO_CHAN_INFO_SCALE),
                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .scan_index = RPR0521_CHAN_INDEX_PXS,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_LE,
+               },
        },
        {
                .type = IIO_INTENSITY,
@@ -213,6 +256,13 @@ static const struct iio_chan_spec rpr0521_channels[] = {
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                        BIT(IIO_CHAN_INFO_SCALE),
                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .scan_index = RPR0521_CHAN_INDEX_BOTH,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_LE,
+               },
        },
        {
                .type = IIO_INTENSITY,
@@ -222,6 +272,13 @@ static const struct iio_chan_spec rpr0521_channels[] = {
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                        BIT(IIO_CHAN_INFO_SCALE),
                .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .scan_index = RPR0521_CHAN_INDEX_IR,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_LE,
+               },
        },
 };
 
@@ -330,6 +387,198 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
        return 0;
 }
 
+/* Interrupt register tells if this sensor caused the interrupt or not. */
+static inline bool rpr0521_is_triggered(struct rpr0521_data *data)
+{
+       int ret;
+       int reg;
+
+       ret = regmap_read(data->regmap, RPR0521_REG_INTERRUPT, &reg);
+       if (ret < 0)
+               return false;   /* Reg read failed. */
+       if (reg &
+           (RPR0521_INTERRUPT_ALS_INT_STATUS_MASK |
+           RPR0521_INTERRUPT_PS_INT_STATUS_MASK))
+               return true;
+       else
+               return false;   /* Int not from this sensor. */
+}
+
+/* IRQ to trigger handler */
+static irqreturn_t rpr0521_drdy_irq_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct rpr0521_data *data = iio_priv(indio_dev);
+
+       data->irq_timestamp = iio_get_time_ns(indio_dev);
+       /*
+        * We need to wake the thread to read the interrupt reg. It
+        * is not possible to do that here because regmap_read takes a
+        * mutex.
+        */
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t rpr0521_drdy_irq_thread(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct rpr0521_data *data = iio_priv(indio_dev);
+
+       if (rpr0521_is_triggered(data)) {
+               iio_trigger_poll_chained(data->drdy_trigger0);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static irqreturn_t rpr0521_trigger_consumer_store_time(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+
+       /* Other trigger polls store time here. */
+       if (!iio_trigger_using_own(indio_dev))
+               pf->timestamp = iio_get_time_ns(indio_dev);
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t rpr0521_trigger_consumer_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct rpr0521_data *data = iio_priv(indio_dev);
+       int err;
+
+       u8 buffer[16]; /* 3 16-bit channels + padding + ts */
+
+       /* Use irq timestamp when reasonable. */
+       if (iio_trigger_using_own(indio_dev) && data->irq_timestamp) {
+               pf->timestamp = data->irq_timestamp;
+               data->irq_timestamp = 0;
+       }
+       /* Other chained trigger polls get timestamp only here. */
+       if (!pf->timestamp)
+               pf->timestamp = iio_get_time_ns(indio_dev);
+
+       err = regmap_bulk_read(data->regmap, RPR0521_REG_PXS_DATA,
+               &buffer,
+               (3 * 2) + 1);   /* 3 * 16-bit + (discarded) int clear reg. */
+       if (!err)
+               iio_push_to_buffers_with_timestamp(indio_dev,
+                                                  buffer, pf->timestamp);
+       else
+               dev_err(&data->client->dev,
+                       "Trigger consumer can't read from sensor.\n");
+       pf->timestamp = 0;
+
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int rpr0521_write_int_enable(struct rpr0521_data *data)
+{
+       int err;
+
+       /* Interrupt after each measurement */
+       err = regmap_update_bits(data->regmap, RPR0521_REG_PXS_CTRL,
+               RPR0521_PXS_PERSISTENCE_MASK,
+               RPR0521_PXS_PERSISTENCE_DRDY);
+       if (err) {
+               dev_err(&data->client->dev, "PS control reg write fail.\n");
+               return -EBUSY;
+               }
+
+       /* Ignore latch and mode because of drdy */
+       err = regmap_write(data->regmap, RPR0521_REG_INTERRUPT,
+               RPR0521_INTERRUPT_INT_REASSERT_DISABLE |
+               RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE |
+               RPR0521_INTERRUPT_INT_TRIG_PS_ENABLE
+               );
+       if (err) {
+               dev_err(&data->client->dev, "Interrupt setup write fail.\n");
+               return -EBUSY;
+               }
+
+       return 0;
+}
+
+static int rpr0521_write_int_disable(struct rpr0521_data *data)
+{
+       /* Don't care of clearing mode, assert and latch. */
+       return regmap_write(data->regmap, RPR0521_REG_INTERRUPT,
+                               RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE |
+                               RPR0521_INTERRUPT_INT_TRIG_PS_DISABLE
+                               );
+}
+
+/*
+ * Trigger producer enable / disable. Note that there will be trigs only when
+ * measurement data is ready to be read.
+ */
+static int rpr0521_pxs_drdy_set_state(struct iio_trigger *trigger,
+       bool enable_drdy)
+{
+       struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
+       struct rpr0521_data *data = iio_priv(indio_dev);
+       int err;
+
+       if (enable_drdy)
+               err = rpr0521_write_int_enable(data);
+       else
+               err = rpr0521_write_int_disable(data);
+       if (err)
+               dev_err(&data->client->dev, "rpr0521_pxs_drdy_set_state failed\n");
+
+       return err;
+}
+
+static const struct iio_trigger_ops rpr0521_trigger_ops = {
+       .set_trigger_state = rpr0521_pxs_drdy_set_state,
+       .owner = THIS_MODULE,
+       };
+
+
+static int rpr0521_buffer_preenable(struct iio_dev *indio_dev)
+{
+       int err;
+       struct rpr0521_data *data = iio_priv(indio_dev);
+
+       mutex_lock(&data->lock);
+       err = rpr0521_set_power_state(data, true,
+               (RPR0521_MODE_PXS_MASK | RPR0521_MODE_ALS_MASK));
+       mutex_unlock(&data->lock);
+       if (err)
+               dev_err(&data->client->dev, "_buffer_preenable fail\n");
+
+       return err;
+}
+
+static int rpr0521_buffer_postdisable(struct iio_dev *indio_dev)
+{
+       int err;
+       struct rpr0521_data *data = iio_priv(indio_dev);
+
+       mutex_lock(&data->lock);
+       err = rpr0521_set_power_state(data, false,
+               (RPR0521_MODE_PXS_MASK | RPR0521_MODE_ALS_MASK));
+       mutex_unlock(&data->lock);
+       if (err)
+               dev_err(&data->client->dev, "_buffer_postdisable fail\n");
+
+       return err;
+}
+
+static const struct iio_buffer_setup_ops rpr0521_buffer_setup_ops = {
+       .preenable = rpr0521_buffer_preenable,
+       .postenable = iio_triggered_buffer_postenable,
+       .predisable = iio_triggered_buffer_predisable,
+       .postdisable = rpr0521_buffer_postdisable,
+};
+
 static int rpr0521_get_gain(struct rpr0521_data *data, int chan,
                            int *val, int *val2)
 {
@@ -473,6 +722,7 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev,
 {
        struct rpr0521_data *data = iio_priv(indio_dev);
        int ret;
+       int busy;
        u8 device_mask;
        __le16 raw_data;
 
@@ -481,26 +731,30 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev,
                if (chan->type != IIO_INTENSITY && chan->type != IIO_PROXIMITY)
                        return -EINVAL;
 
+               busy = iio_device_claim_direct_mode(indio_dev);
+               if (busy)
+                       return -EBUSY;
+
                device_mask = rpr0521_data_reg[chan->address].device_mask;
 
                mutex_lock(&data->lock);
                ret = rpr0521_set_power_state(data, true, device_mask);
-               if (ret < 0) {
-                       mutex_unlock(&data->lock);
-                       return ret;
-               }
+               if (ret < 0)
+                       goto rpr0521_read_raw_out;
 
                ret = regmap_bulk_read(data->regmap,
                                       rpr0521_data_reg[chan->address].address,
                                       &raw_data, sizeof(raw_data));
                if (ret < 0) {
                        rpr0521_set_power_state(data, false, device_mask);
-                       mutex_unlock(&data->lock);
-                       return ret;
+                       goto rpr0521_read_raw_out;
                }
 
                ret = rpr0521_set_power_state(data, false, device_mask);
+
+rpr0521_read_raw_out:
                mutex_unlock(&data->lock);
+               iio_device_release_direct_mode(indio_dev);
                if (ret < 0)
                        return ret;
 
@@ -617,12 +871,15 @@ static int rpr0521_init(struct rpr0521_data *data)
                return ret;
 #endif
 
+       data->irq_timestamp = 0;
+
        return 0;
 }
 
 static int rpr0521_poweroff(struct rpr0521_data *data)
 {
        int ret;
+       int tmp;
 
        ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
                                 RPR0521_MODE_ALS_MASK |
@@ -635,6 +892,16 @@ static int rpr0521_poweroff(struct rpr0521_data *data)
        data->als_dev_en = false;
        data->pxs_dev_en = false;
 
+       /*
+        * Int pin keeps state after power off. Set pin to high impedance
+        * mode to prevent power drain.
+        */
+       ret = regmap_read(data->regmap, RPR0521_REG_INTERRUPT, &tmp);
+       if (ret) {
+               dev_err(&data->client->dev, "Failed to reset int pin.\n");
+               return ret;
+       }
+
        return 0;
 }
 
@@ -707,6 +974,61 @@ static int rpr0521_probe(struct i2c_client *client,
        pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
+       /*
+        * If sensor write/read is needed in _probe after _use_autosuspend,
+        * sensor needs to be _resumed first using rpr0521_set_power_state().
+        */
+
+       /* IRQ to trigger setup */
+       if (client->irq) {
+               /* Trigger0 producer setup */
+               data->drdy_trigger0 = devm_iio_trigger_alloc(
+                       indio_dev->dev.parent,
+                       "%s-dev%d", indio_dev->name, indio_dev->id);
+               if (!data->drdy_trigger0) {
+                       ret = -ENOMEM;
+                       goto err_pm_disable;
+               }
+               data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
+               data->drdy_trigger0->ops = &rpr0521_trigger_ops;
+               indio_dev->available_scan_masks = rpr0521_available_scan_masks;
+               iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
+
+               /* Ties irq to trigger producer handler. */
+               ret = devm_request_threaded_irq(&client->dev, client->irq,
+                       rpr0521_drdy_irq_handler, rpr0521_drdy_irq_thread,
+                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       RPR0521_IRQ_NAME, indio_dev);
+               if (ret < 0) {
+                       dev_err(&client->dev, "request irq %d for trigger0 failed\n",
+                               client->irq);
+                       goto err_pm_disable;
+                       }
+
+               ret = devm_iio_trigger_register(indio_dev->dev.parent,
+                                               data->drdy_trigger0);
+               if (ret) {
+                       dev_err(&client->dev, "iio trigger register failed\n");
+                       goto err_pm_disable;
+               }
+
+               /*
+                * Now whole pipe from physical interrupt (irq defined by
+                * devicetree to device) to trigger0 output is set up.
+                */
+
+               /* Trigger consumer setup */
+               ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent,
+                       indio_dev,
+                       rpr0521_trigger_consumer_store_time,
+                       rpr0521_trigger_consumer_handler,
+                       &rpr0521_buffer_setup_ops);
+               if (ret < 0) {
+                       dev_err(&client->dev, "iio triggered buffer setup failed\n");
+                       goto err_pm_disable;
+               }
+       }
+
        ret = iio_device_register(indio_dev);
        if (ret)
                goto err_pm_disable;
index 3aa71e34ae28b39350033616805eb6f2d5480714..09e6ca5e332e97aac9e13a54e009ab2f2cd4678d 100644 (file)
@@ -11,6 +11,8 @@
  * 7-bit I2C slave address 0x39 (TCS34721, TCS34723) or 0x29 (TCS34725,
  * TCS34727)
  *
+ * Datasheet: http://ams.com/eng/content/download/319364/1117183/file/TCS3472_Datasheet_EN_v2.pdf
+ *
  * TODO: interrupt support, thresholds, wait time
  */
 
@@ -169,7 +171,7 @@ static int tcs3472_write_raw(struct iio_dev *indio_dev,
                for (i = 0; i < 256; i++) {
                        if (val2 == (256 - i) * 2400) {
                                data->atime = i;
-                               return i2c_smbus_write_word_data(
+                               return i2c_smbus_write_byte_data(
                                        data->client, TCS3472_ATIME,
                                        data->atime);
                        }
index 825369fb1c57b3a66475c0c2d430cb2dd76a53df..4ff883942f7b7581dc686ac6d600fe6e4eb91539 100644 (file)
@@ -784,6 +784,7 @@ static const struct iio_info ak8975_info = {
        .driver_module = THIS_MODULE,
 };
 
+#ifdef CONFIG_ACPI
 static const struct acpi_device_id ak_acpi_match[] = {
        {"AK8975", AK8975},
        {"AK8963", AK8963},
@@ -793,6 +794,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
        { },
 };
 MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
+#endif
 
 static const char *ak8975_match_acpi_device(struct device *dev,
                                            enum asahi_compass_chipset *chipset)
index 8e1b0861fbe4a63b6b50466f320bd65e6e48f3c9..3573636bad8e0ce3aa035c4b57e76a926f71ed20 100644 (file)
@@ -315,7 +315,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
                                },
                        },
                },
-               .multi_read_bit = false,
+               .multi_read_bit = true,
                .bootime = 2,
        },
        {
index 8aa37af306edd61f83424f77314a922523a8c2f1..6a6c8121ac2c153a20e22340443b9e84ec5981ce 100644 (file)
@@ -59,7 +59,8 @@ static int st_magn_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        mdata = iio_priv(indio_dev);
-       st_sensors_of_i2c_probe(client, st_magn_of_match);
+       st_sensors_of_name_probe(&client->dev, st_magn_of_match,
+                                client->name, sizeof(client->name));
 
        st_sensors_i2c_configure(indio_dev, client, mdata);
 
index f3cb4dc0539144e84a5b61c4f213596aec514ca7..1ea64dd318aa10128b6e42a163bb25b6a42d61c9 100644 (file)
 #include <linux/iio/common/st_sensors_spi.h>
 #include "st_magn.h"
 
+#ifdef CONFIG_OF
+/*
+ * For new single-chip sensors use <device_name> as compatible string.
+ * For old single-chip devices keep <device_name>-magn to maintain
+ * compatibility
+ */
+static const struct of_device_id st_magn_of_match[] = {
+       {
+               .compatible = "st,lis3mdl-magn",
+               .data = LIS3MDL_MAGN_DEV_NAME,
+       },
+       {
+               .compatible = "st,lsm303agr-magn",
+               .data = LSM303AGR_MAGN_DEV_NAME,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, st_magn_of_match);
+#else
+#define st_magn_of_match       NULL
+#endif
+
 static int st_magn_spi_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
@@ -30,6 +52,8 @@ static int st_magn_spi_probe(struct spi_device *spi)
 
        mdata = iio_priv(indio_dev);
 
+       st_sensors_of_name_probe(&spi->dev, st_magn_of_match,
+                                spi->modalias, sizeof(spi->modalias));
        st_sensors_spi_configure(indio_dev, spi, mdata);
 
        err = st_magn_common_probe(indio_dev);
@@ -57,6 +81,7 @@ MODULE_DEVICE_TABLE(spi, st_magn_id_table);
 static struct spi_driver st_magn_driver = {
        .driver = {
                .name = "st-magn-spi",
+               .of_match_table = of_match_ptr(st_magn_of_match),
        },
        .probe = st_magn_spi_probe,
        .remove = st_magn_spi_remove,
index e9fa86c87db5c0e3cd64354495c1ec3d7b1ea774..98fe0c5df3807b2eac71dc20d9169e9ed7b531b7 100644 (file)
@@ -238,7 +238,7 @@ static int dev_rot_parse_report(struct platform_device *pdev,
 static int hid_dev_rot_probe(struct platform_device *pdev)
 {
        int ret;
-       static char *name;
+       char *name;
        struct iio_dev *indio_dev;
        struct dev_rot_state *rot_state;
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
index 953ffbc0ef96046546c81ce5c497e59a64cc4134..c413f8a84a633950d4fc483f28702887cbf9b266 100644 (file)
@@ -181,11 +181,21 @@ static const struct i2c_device_id ms5637_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ms5637_id);
 
+static const struct of_device_id ms5637_of_match[] = {
+       { .compatible = "meas,ms5637", },
+       { .compatible = "meas,ms5805", },
+       { .compatible = "meas,ms5837", },
+       { .compatible = "meas,ms8607-temppressure", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ms5637_of_match);
+
 static struct i2c_driver ms5637_driver = {
        .probe = ms5637_probe,
        .id_table = ms5637_id,
        .driver = {
-                  .name = "ms5637"
+                  .name = "ms5637",
+                  .of_match_table = of_match_ptr(ms5637_of_match),
                   },
 };
 
index 17417a4d5a5f955be36aeb48ff8ec73f558e4bdc..7f15e927fa2bce3acf5e190a16c7b4878fb123d2 100644 (file)
@@ -77,7 +77,8 @@ static int st_press_i2c_probe(struct i2c_client *client,
        press_data = iio_priv(indio_dev);
 
        if (client->dev.of_node) {
-               st_sensors_of_i2c_probe(client, st_press_of_match);
+               st_sensors_of_name_probe(&client->dev, st_press_of_match,
+                                        client->name, sizeof(client->name));
        } else if (ACPI_HANDLE(&client->dev)) {
                ret = st_sensors_match_acpi_device(&client->dev);
                if ((ret < 0) || (ret >= ST_PRESS_MAX))
index 550508025af1a31dfcf48a5803fce711e12f9243..f5ebd36bb4bf9cabfe0320175056e866e54b7dc4 100644 (file)
 #include <linux/iio/common/st_sensors_spi.h>
 #include "st_pressure.h"
 
+#ifdef CONFIG_OF
+/*
+ * For new single-chip sensors use <device_name> as compatible string.
+ * For old single-chip devices keep <device_name>-press to maintain
+ * compatibility
+ */
+static const struct of_device_id st_press_of_match[] = {
+       {
+               .compatible = "st,lps001wp-press",
+               .data = LPS001WP_PRESS_DEV_NAME,
+       },
+       {
+               .compatible = "st,lps25h-press",
+               .data = LPS25H_PRESS_DEV_NAME,
+       },
+       {
+               .compatible = "st,lps331ap-press",
+               .data = LPS331AP_PRESS_DEV_NAME,
+       },
+       {
+               .compatible = "st,lps22hb-press",
+               .data = LPS22HB_PRESS_DEV_NAME,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, st_press_of_match);
+#else
+#define st_press_of_match      NULL
+#endif
+
 static int st_press_spi_probe(struct spi_device *spi)
 {
        struct iio_dev *indio_dev;
@@ -30,6 +60,8 @@ static int st_press_spi_probe(struct spi_device *spi)
 
        press_data = iio_priv(indio_dev);
 
+       st_sensors_of_name_probe(&spi->dev, st_press_of_match,
+                                spi->modalias, sizeof(spi->modalias));
        st_sensors_spi_configure(indio_dev, spi, press_data);
 
        err = st_press_common_probe(indio_dev);
@@ -58,6 +90,7 @@ MODULE_DEVICE_TABLE(spi, st_press_id_table);
 static struct spi_driver st_press_driver = {
        .driver = {
                .name = "st-press-spi",
+               .of_match_table = of_match_ptr(st_press_of_match),
        },
        .probe = st_press_spi_probe,
        .remove = st_press_spi_remove,
index c92a95f9f52c21410ea9f372c3254530008914bd..ebfb1de7377ffb5b0c30cf3c23c61b0f7afcdddd 100644 (file)
@@ -141,14 +141,14 @@ struct zpa2326_private {
        struct regulator               *vdd;
 };
 
-#define zpa2326_err(_idev, _format, _arg...) \
-       dev_err(_idev->dev.parent, _format, ##_arg)
+#define zpa2326_err(idev, fmt, ...)                                    \
+       dev_err(idev->dev.parent, fmt "\n", ##__VA_ARGS__)
 
-#define zpa2326_warn(_idev, _format, _arg...) \
-       dev_warn(_idev->dev.parent, _format, ##_arg)
+#define zpa2326_warn(idev, fmt, ...)                                   \
+       dev_warn(idev->dev.parent, fmt "\n", ##__VA_ARGS__)
 
-#define zpa2326_dbg(_idev, _format, _arg...) \
-       dev_dbg(_idev->dev.parent, _format, ##_arg)
+#define zpa2326_dbg(idev, fmt, ...)                                    \
+       dev_dbg(idev->dev.parent, fmt "\n", ##__VA_ARGS__)
 
 bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg)
 {
index 3e60c6189d98b8d30d1f4d4c32186eeae1e62276..d8aa211d76e42cb543a82b91eac9acffec6c6e4a 100644 (file)
@@ -214,11 +214,18 @@ static const struct i2c_device_id tsys01_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, tsys01_id);
 
+static const struct of_device_id tsys01_of_match[] = {
+       { .compatible = "meas,tsys01", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, tsys01_of_match);
+
 static struct i2c_driver tsys01_driver = {
        .probe = tsys01_i2c_probe,
        .id_table = tsys01_id,
        .driver = {
                   .name = "tsys01",
+                  .of_match_table = of_match_ptr(tsys01_of_match),
                   },
 };
 
index d5ab83f0236dd31131ed8b2fe20c8ff9875dfc03..f85dde9805e0b8ec930a0b964593c98f2047a8d8 100644 (file)
 #define AD7280A_DEVADDR_MASTER         0
 #define AD7280A_DEVADDR_ALL            0x1F
 /* 5-bit device address is sent LSB first */
-#define AD7280A_DEVADDR(addr)  (((addr & 0x1) << 4) | ((addr & 0x2) << 3) | \
-                               (addr & 0x4) | ((addr & 0x8) >> 3) | \
-                               ((addr & 0x10) >> 4))
+static unsigned int ad7280a_devaddr(unsigned int addr)
+{
+       return ((addr & 0x1) << 4) |
+              ((addr & 0x2) << 3) |
+              (addr & 0x4) |
+              ((addr & 0x8) >> 3) |
+              ((addr & 0x10) >> 4);
+}
 
 /* During a read a valid write is mandatory.
  * So writing to the highest available address (Address 0x1F)
@@ -372,7 +377,7 @@ static int ad7280_chain_setup(struct ad7280_state *st)
                if (ad7280_check_crc(st, val))
                        return -EIO;
 
-               if (n != AD7280A_DEVADDR(val >> 27))
+               if (n != ad7280a_devaddr(val >> 27))
                        return -EIO;
        }
 
@@ -511,7 +516,7 @@ static int ad7280_channel_init(struct ad7280_state *st)
                        st->channels[cnt].info_mask_shared_by_type =
                                BIT(IIO_CHAN_INFO_SCALE);
                        st->channels[cnt].address =
-                               AD7280A_DEVADDR(dev) << 8 | ch;
+                               ad7280a_devaddr(dev) << 8 | ch;
                        st->channels[cnt].scan_index = cnt;
                        st->channels[cnt].scan_type.sign = 'u';
                        st->channels[cnt].scan_type.realbits = 12;
@@ -558,7 +563,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
                for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6;
                        ch++, cnt++) {
                        st->iio_attr[cnt].address =
-                               AD7280A_DEVADDR(dev) << 8 | ch;
+                               ad7280a_devaddr(dev) << 8 | ch;
                        st->iio_attr[cnt].dev_attr.attr.mode =
                                0644;
                        st->iio_attr[cnt].dev_attr.show =
@@ -574,7 +579,7 @@ static int ad7280_attr_init(struct ad7280_state *st)
                                &st->iio_attr[cnt].dev_attr.attr;
                        cnt++;
                        st->iio_attr[cnt].address =
-                               AD7280A_DEVADDR(dev) << 8 |
+                               ad7280a_devaddr(dev) << 8 |
                                (AD7280A_CB1_TIMER + ch);
                        st->iio_attr[cnt].dev_attr.attr.mode =
                                0644;
@@ -918,7 +923,7 @@ static int ad7280_probe(struct spi_device *spi)
                if (ret)
                        goto error_unregister;
 
-               ret = ad7280_write(st, AD7280A_DEVADDR(st->slave_num),
+               ret = ad7280_write(st, ad7280a_devaddr(st->slave_num),
                                   AD7280A_ALERT, 0,
                                   AD7280A_ALERT_GEN_STATIC_HIGH |
                                   (pdata->chain_last_alert_ignore & 0xF));
index 146719928fb31d842539a6ca0ed3983b50d644c1..786e93f16ce9531d56484ec7fe5e8d15baa32027 100644 (file)
@@ -284,35 +284,6 @@ static const u8 device_channel_config[] = {
        ALSPRX2
 };
 
-/**
- * tsl2x7x_i2c_read() - Read a byte from a register.
- * @client:    i2c client
- * @reg:       device register to read from
- * @*val:      pointer to location to store register contents.
- *
- */
-static int
-tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
-{
-       int ret;
-
-       /* select register to write */
-       ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg));
-       if (ret < 0) {
-               dev_err(&client->dev, "failed to write register %x\n", reg);
-               return ret;
-       }
-
-       /* read the data */
-       ret = i2c_smbus_read_byte(client);
-       if (ret >= 0)
-               *val = (u8)ret;
-       else
-               dev_err(&client->dev, "failed to read register %x\n", reg);
-
-       return ret;
-}
-
 /**
  * tsl2x7x_get_lux() - Reads and calculates current lux value.
  * @indio_dev: pointer to IIO device
@@ -352,15 +323,15 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
                goto out_unlock;
        }
 
-       ret = tsl2x7x_i2c_read(chip->client,
-                              (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
+       ret = i2c_smbus_read_byte_data(chip->client,
+                                      TSL2X7X_CMD_REG | TSL2X7X_STATUS);
        if (ret < 0) {
                dev_err(&chip->client->dev,
                        "%s: Failed to read STATUS Reg\n", __func__);
                goto out_unlock;
        }
        /* is data new & valid */
-       if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) {
+       if (!(ret & TSL2X7X_STA_ADC_VALID)) {
                dev_err(&chip->client->dev,
                        "%s: data not valid yet\n", __func__);
                ret = chip->als_cur_info.lux; /* return LAST VALUE */
@@ -368,14 +339,16 @@ static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
        }
 
        for (i = 0; i < 4; i++) {
-               ret = tsl2x7x_i2c_read(chip->client,
-                                      (TSL2X7X_CMD_REG |
-                                      (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]);
+               int reg = TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i);
+
+               ret = i2c_smbus_read_byte_data(chip->client, reg);
                if (ret < 0) {
                        dev_err(&chip->client->dev,
                                "failed to read. err=%x\n", ret);
                        goto out_unlock;
                }
+
+               buf[i] = ret;
        }
 
        /* clear any existing interrupt status */
@@ -475,7 +448,6 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
 {
        int i;
        int ret;
-       u8 status;
        u8 chdata[2];
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
 
@@ -485,8 +457,8 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
                return -EBUSY;
        }
 
-       ret = tsl2x7x_i2c_read(chip->client,
-                              (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
+       ret = i2c_smbus_read_byte_data(chip->client,
+                                      TSL2X7X_CMD_REG | TSL2X7X_STATUS);
        if (ret < 0) {
                dev_err(&chip->client->dev, "i2c err=%d\n", ret);
                goto prox_poll_err;
@@ -498,7 +470,7 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
        case tmd2671:
        case tsl2771:
        case tmd2771:
-               if (!(status & TSL2X7X_STA_ADC_VALID))
+               if (!(ret & TSL2X7X_STA_ADC_VALID))
                        goto prox_poll_err;
        break;
        case tsl2572:
@@ -506,17 +478,19 @@ static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
        case tmd2672:
        case tsl2772:
        case tmd2772:
-               if (!(status & TSL2X7X_STA_PRX_VALID))
+               if (!(ret & TSL2X7X_STA_PRX_VALID))
                        goto prox_poll_err;
        break;
        }
 
        for (i = 0; i < 2; i++) {
-               ret = tsl2x7x_i2c_read(chip->client,
-                                      (TSL2X7X_CMD_REG |
-                                      (TSL2X7X_PRX_LO + i)), &chdata[i]);
+               int reg = TSL2X7X_CMD_REG | (TSL2X7X_PRX_LO + i);
+
+               ret = i2c_smbus_read_byte_data(chip->client, reg);
                if (ret < 0)
                        goto prox_poll_err;
+
+               chdata[i] = ret;
        }
 
        chip->prox_data =
@@ -568,39 +542,29 @@ static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
 static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
 {
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       u8 reg_val;
        int gain_trim_val;
        int ret;
        int lux_val;
 
-       ret = i2c_smbus_write_byte(chip->client,
-                                  (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+       ret = i2c_smbus_read_byte_data(chip->client,
+                                      TSL2X7X_CMD_REG | TSL2X7X_CNTRL);
        if (ret < 0) {
                dev_err(&chip->client->dev,
-                       "failed to write CNTRL register, ret=%d\n", ret);
+                       "%s: failed to read from the CNTRL register\n",
+                       __func__);
                return ret;
        }
 
-       reg_val = i2c_smbus_read_byte(chip->client);
-       if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON))
-               != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) {
-               dev_err(&chip->client->dev,
-                       "%s: failed: ADC not enabled\n", __func__);
-               return -1;
-       }
-
-       ret = i2c_smbus_write_byte(chip->client,
-                                  (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
-       if (ret < 0) {
+       if ((ret & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON))
+                       != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) {
                dev_err(&chip->client->dev,
-                       "failed to write ctrl reg: ret=%d\n", ret);
-               return ret;
-       }
-
-       reg_val = i2c_smbus_read_byte(chip->client);
-       if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) {
+                       "%s: Device is not powered on and/or ADC is not enabled\n",
+                       __func__);
+               return -EINVAL;
+       } else if ((ret & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) {
                dev_err(&chip->client->dev,
-                       "%s: failed: STATUS - ADC not valid.\n", __func__);
+                       "%s: The two ADC channels have not completed an integration cycle\n",
+                       __func__);
                return -ENODATA;
        }
 
@@ -722,7 +686,8 @@ static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
                }
        }
 
-       mdelay(3);      /* Power-on settling time */
+       /* Power-on settling time */
+       usleep_range(3000, 3500);
 
        /*
         * NOW enable the ADC
@@ -806,22 +771,24 @@ int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
 {
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
        int device_status = chip->tsl2x7x_chip_status;
+       int ret;
 
        mutex_lock(&chip->als_mutex);
        mutex_lock(&chip->prox_mutex);
 
-       if (device_status == TSL2X7X_CHIP_WORKING)
-               tsl2x7x_chip_off(indio_dev);
-
-       tsl2x7x_chip_on(indio_dev);
+       if (device_status == TSL2X7X_CHIP_WORKING) {
+               ret = tsl2x7x_chip_off(indio_dev);
+               if (ret < 0)
+                       goto unlock;
+       }
 
-       if (device_status != TSL2X7X_CHIP_WORKING)
-               tsl2x7x_chip_off(indio_dev);
+       ret = tsl2x7x_chip_on(indio_dev);
 
+unlock:
        mutex_unlock(&chip->prox_mutex);
        mutex_unlock(&chip->als_mutex);
 
-       return 0;
+       return ret;
 }
 
 static
@@ -889,7 +856,7 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
 
        /*gather the samples*/
        for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
-               mdelay(15);
+               usleep_range(15000, 17500);
                tsl2x7x_get_prox(indio_dev);
                prox_history[i] = chip->prox_data;
                dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
@@ -915,33 +882,6 @@ static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
                tsl2x7x_chip_on(indio_dev);
 }
 
-static ssize_t power_state_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status);
-}
-
-static ssize_t power_state_store(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       bool value;
-
-       if (strtobool(buf, &value))
-               return -EINVAL;
-
-       if (value)
-               tsl2x7x_chip_on(indio_dev);
-       else
-               tsl2x7x_chip_off(indio_dev);
-
-       return len;
-}
-
 static ssize_t in_illuminance0_calibscale_available_show(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
@@ -1027,6 +967,7 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
        unsigned long value;
+       int ret;
 
        if (kstrtoul(buf, 0, &value))
                return -EINVAL;
@@ -1034,7 +975,9 @@ static ssize_t in_illuminance0_target_input_store(struct device *dev,
        if (value)
                chip->tsl2x7x_settings.als_cal_target = value;
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
        return len;
 }
@@ -1083,7 +1026,9 @@ static ssize_t in_intensity0_thresh_period_store(struct device *dev,
        dev_info(&chip->client->dev, "%s: als persistence = %d",
                 __func__, filter_delay);
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
        return IIO_VAL_INT_PLUS_MICRO;
 }
@@ -1131,7 +1076,10 @@ static ssize_t in_proximity0_thresh_period_store(struct device *dev,
        dev_info(&chip->client->dev, "%s: prox persistence = %d",
                 __func__, filter_delay);
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
+
 
        return IIO_VAL_INT_PLUS_MICRO;
 }
@@ -1142,6 +1090,7 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev,
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        bool value;
+       int ret;
 
        if (strtobool(buf, &value))
                return -EINVAL;
@@ -1149,7 +1098,9 @@ static ssize_t in_illuminance0_calibrate_store(struct device *dev,
        if (value)
                tsl2x7x_als_calibrate(indio_dev);
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
        return len;
 }
@@ -1189,7 +1140,7 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
        int value[ARRAY_SIZE(chip->tsl2x7x_device_lux) * 3 + 1];
-       int n;
+       int n, ret;
 
        get_options(buf, ARRAY_SIZE(value), value);
 
@@ -1217,7 +1168,9 @@ static ssize_t in_illuminance0_lux_table_store(struct device *dev,
        memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux));
        memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4));
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
        return len;
 }
@@ -1228,6 +1181,7 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev,
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        bool value;
+       int ret;
 
        if (strtobool(buf, &value))
                return -EINVAL;
@@ -1235,7 +1189,9 @@ static ssize_t in_proximity0_calibrate_store(struct device *dev,
        if (value)
                tsl2x7x_prox_cal(indio_dev);
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
        return len;
 }
@@ -1263,6 +1219,7 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
                                          int val)
 {
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int ret;
 
        if (chan->type == IIO_INTENSITY) {
                if (val)
@@ -1276,83 +1233,108 @@ static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
                        chip->tsl2x7x_settings.interrupts_en &= 0x10;
        }
 
-       tsl2x7x_invoke_change(indio_dev);
+       ret = tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
        return 0;
 }
 
-static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
-                               const struct iio_chan_spec *chan,
-                               enum iio_event_type type,
-                               enum iio_event_direction dir,
-                               enum iio_event_info info,
-                               int val, int val2)
+static int tsl2x7x_write_event_value(struct iio_dev *indio_dev,
+                                    const struct iio_chan_spec *chan,
+                                    enum iio_event_type type,
+                                    enum iio_event_direction dir,
+                                    enum iio_event_info info,
+                                    int val, int val2)
 {
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int ret = -EINVAL;
 
-       if (chan->type == IIO_INTENSITY) {
-               switch (dir) {
-               case IIO_EV_DIR_RISING:
-                       chip->tsl2x7x_settings.als_thresh_high = val;
-                       break;
-               case IIO_EV_DIR_FALLING:
-                       chip->tsl2x7x_settings.als_thresh_low = val;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else {
-               switch (dir) {
-               case IIO_EV_DIR_RISING:
-                       chip->tsl2x7x_settings.prox_thres_high = val;
-                       break;
-               case IIO_EV_DIR_FALLING:
-                       chip->tsl2x7x_settings.prox_thres_low = val;
-                       break;
-               default:
-                       return -EINVAL;
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               if (chan->type == IIO_INTENSITY) {
+                       switch (dir) {
+                       case IIO_EV_DIR_RISING:
+                               chip->tsl2x7x_settings.als_thresh_high = val;
+                               ret = 0;
+                               break;
+                       case IIO_EV_DIR_FALLING:
+                               chip->tsl2x7x_settings.als_thresh_low = val;
+                               ret = 0;
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       switch (dir) {
+                       case IIO_EV_DIR_RISING:
+                               chip->tsl2x7x_settings.prox_thres_high = val;
+                               ret = 0;
+                               break;
+                       case IIO_EV_DIR_FALLING:
+                               chip->tsl2x7x_settings.prox_thres_low = val;
+                               ret = 0;
+                               break;
+                       default:
+                               break;
+                       }
                }
+               break;
+       default:
+               break;
        }
 
-       tsl2x7x_invoke_change(indio_dev);
+       if (ret < 0)
+               return ret;
 
-       return 0;
+       return tsl2x7x_invoke_change(indio_dev);
 }
 
-static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
-                              const struct iio_chan_spec *chan,
-                              enum iio_event_type type,
-                              enum iio_event_direction dir,
-                                  enum iio_event_info info,
-                              int *val, int *val2)
+static int tsl2x7x_read_event_value(struct iio_dev *indio_dev,
+                                   const struct iio_chan_spec *chan,
+                                   enum iio_event_type type,
+                                   enum iio_event_direction dir,
+                                   enum iio_event_info info,
+                                   int *val, int *val2)
 {
        struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int ret = -EINVAL;
 
-       if (chan->type == IIO_INTENSITY) {
-               switch (dir) {
-               case IIO_EV_DIR_RISING:
-                       *val = chip->tsl2x7x_settings.als_thresh_high;
-                       break;
-               case IIO_EV_DIR_FALLING:
-                       *val = chip->tsl2x7x_settings.als_thresh_low;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       } else {
-               switch (dir) {
-               case IIO_EV_DIR_RISING:
-                       *val = chip->tsl2x7x_settings.prox_thres_high;
-                       break;
-               case IIO_EV_DIR_FALLING:
-                       *val = chip->tsl2x7x_settings.prox_thres_low;
-                       break;
-               default:
-                       return -EINVAL;
+       switch (info) {
+       case IIO_EV_INFO_VALUE:
+               if (chan->type == IIO_INTENSITY) {
+                       switch (dir) {
+                       case IIO_EV_DIR_RISING:
+                               *val = chip->tsl2x7x_settings.als_thresh_high;
+                               ret = IIO_VAL_INT;
+                               break;
+                       case IIO_EV_DIR_FALLING:
+                               *val = chip->tsl2x7x_settings.als_thresh_low;
+                               ret = IIO_VAL_INT;
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       switch (dir) {
+                       case IIO_EV_DIR_RISING:
+                               *val = chip->tsl2x7x_settings.prox_thres_high;
+                               ret = IIO_VAL_INT;
+                               break;
+                       case IIO_EV_DIR_FALLING:
+                               *val = chip->tsl2x7x_settings.prox_thres_low;
+                               ret = IIO_VAL_INT;
+                               break;
+                       default:
+                               break;
+                       }
                }
+               break;
+       default:
+               break;
        }
 
-       return IIO_VAL_INT;
+       return ret;
 }
 
 static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
@@ -1489,13 +1471,9 @@ static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
                return -EINVAL;
        }
 
-       tsl2x7x_invoke_change(indio_dev);
-
-       return 0;
+       return tsl2x7x_invoke_change(indio_dev);
 }
 
-static DEVICE_ATTR_RW(power_state);
-
 static DEVICE_ATTR_RO(in_proximity0_calibscale_available);
 
 static DEVICE_ATTR_RO(in_illuminance0_calibscale_available);
@@ -1515,7 +1493,7 @@ static DEVICE_ATTR_RW(in_intensity0_thresh_period);
 static DEVICE_ATTR_RW(in_proximity0_thresh_period);
 
 /* Use the default register values to identify the Taos device */
-static int tsl2x7x_device_id(unsigned char *id, int target)
+static int tsl2x7x_device_id(int *id, int target)
 {
        switch (target) {
        case tsl2571:
@@ -1580,7 +1558,6 @@ static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
 }
 
 static struct attribute *tsl2x7x_ALS_device_attrs[] = {
-       &dev_attr_power_state.attr,
        &dev_attr_in_illuminance0_calibscale_available.attr,
        &dev_attr_in_illuminance0_integration_time.attr,
        &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr,
@@ -1591,13 +1568,11 @@ static struct attribute *tsl2x7x_ALS_device_attrs[] = {
 };
 
 static struct attribute *tsl2x7x_PRX_device_attrs[] = {
-       &dev_attr_power_state.attr,
        &dev_attr_in_proximity0_calibrate.attr,
        NULL
 };
 
 static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
-       &dev_attr_power_state.attr,
        &dev_attr_in_illuminance0_calibscale_available.attr,
        &dev_attr_in_illuminance0_integration_time.attr,
        &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr,
@@ -1609,14 +1584,12 @@ static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
 };
 
 static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
-       &dev_attr_power_state.attr,
        &dev_attr_in_proximity0_calibrate.attr,
        &dev_attr_in_proximity0_calibscale_available.attr,
        NULL
 };
 
 static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
-       &dev_attr_power_state.attr,
        &dev_attr_in_illuminance0_calibscale_available.attr,
        &dev_attr_in_illuminance0_integration_time.attr,
        &iio_const_attr_in_illuminance0_integration_time_available.dev_attr.attr,
@@ -1684,8 +1657,8 @@ static const struct iio_info tsl2X7X_device_info[] = {
                .driver_module = THIS_MODULE,
                .read_raw = &tsl2x7x_read_raw,
                .write_raw = &tsl2x7x_write_raw,
-               .read_event_value = &tsl2x7x_read_thresh,
-               .write_event_value = &tsl2x7x_write_thresh,
+               .read_event_value = &tsl2x7x_read_event_value,
+               .write_event_value = &tsl2x7x_write_event_value,
                .read_event_config = &tsl2x7x_read_interrupt_config,
                .write_event_config = &tsl2x7x_write_interrupt_config,
        },
@@ -1695,8 +1668,8 @@ static const struct iio_info tsl2X7X_device_info[] = {
                .driver_module = THIS_MODULE,
                .read_raw = &tsl2x7x_read_raw,
                .write_raw = &tsl2x7x_write_raw,
-               .read_event_value = &tsl2x7x_read_thresh,
-               .write_event_value = &tsl2x7x_write_thresh,
+               .read_event_value = &tsl2x7x_read_event_value,
+               .write_event_value = &tsl2x7x_write_event_value,
                .read_event_config = &tsl2x7x_read_interrupt_config,
                .write_event_config = &tsl2x7x_write_interrupt_config,
        },
@@ -1706,8 +1679,8 @@ static const struct iio_info tsl2X7X_device_info[] = {
                .driver_module = THIS_MODULE,
                .read_raw = &tsl2x7x_read_raw,
                .write_raw = &tsl2x7x_write_raw,
-               .read_event_value = &tsl2x7x_read_thresh,
-               .write_event_value = &tsl2x7x_write_thresh,
+               .read_event_value = &tsl2x7x_read_event_value,
+               .write_event_value = &tsl2x7x_write_event_value,
                .read_event_config = &tsl2x7x_read_interrupt_config,
                .write_event_config = &tsl2x7x_write_interrupt_config,
        },
@@ -1717,8 +1690,8 @@ static const struct iio_info tsl2X7X_device_info[] = {
                .driver_module = THIS_MODULE,
                .read_raw = &tsl2x7x_read_raw,
                .write_raw = &tsl2x7x_write_raw,
-               .read_event_value = &tsl2x7x_read_thresh,
-               .write_event_value = &tsl2x7x_write_thresh,
+               .read_event_value = &tsl2x7x_read_event_value,
+               .write_event_value = &tsl2x7x_write_event_value,
                .read_event_config = &tsl2x7x_read_interrupt_config,
                .write_event_config = &tsl2x7x_write_interrupt_config,
        },
@@ -1728,8 +1701,8 @@ static const struct iio_info tsl2X7X_device_info[] = {
                .driver_module = THIS_MODULE,
                .read_raw = &tsl2x7x_read_raw,
                .write_raw = &tsl2x7x_write_raw,
-               .read_event_value = &tsl2x7x_read_thresh,
-               .write_event_value = &tsl2x7x_write_thresh,
+               .read_event_value = &tsl2x7x_read_event_value,
+               .write_event_value = &tsl2x7x_write_event_value,
                .read_event_config = &tsl2x7x_read_interrupt_config,
                .write_event_config = &tsl2x7x_write_interrupt_config,
        },
@@ -1877,7 +1850,6 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
                         const struct i2c_device_id *id)
 {
        int ret;
-       unsigned char device_id;
        struct iio_dev *indio_dev;
        struct tsl2X7X_chip *chip;
 
@@ -1889,13 +1861,13 @@ static int tsl2x7x_probe(struct i2c_client *clientp,
        chip->client = clientp;
        i2c_set_clientdata(clientp, indio_dev);
 
-       ret = tsl2x7x_i2c_read(chip->client,
-                              TSL2X7X_CHIPID, &device_id);
+       ret = i2c_smbus_read_byte_data(chip->client,
+                                      TSL2X7X_CMD_REG | TSL2X7X_CHIPID);
        if (ret < 0)
                return ret;
 
-       if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
-           (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
+       if ((!tsl2x7x_device_id(&ret, id->driver_data)) ||
+           (tsl2x7x_device_id(&ret, id->driver_data) == -EINVAL)) {
                dev_info(&chip->client->dev,
                         "%s: i2c device found does not match expected id\n",
                                __func__);
@@ -2026,6 +1998,21 @@ static struct i2c_device_id tsl2x7x_idtable[] = {
 
 MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
 
+static const struct of_device_id tsl2x7x_of_match[] = {
+       { .compatible = "amstaos,tsl2571" },
+       { .compatible = "amstaos,tsl2671" },
+       { .compatible = "amstaos,tmd2671" },
+       { .compatible = "amstaos,tsl2771" },
+       { .compatible = "amstaos,tmd2771" },
+       { .compatible = "amstaos,tsl2572" },
+       { .compatible = "amstaos,tsl2672" },
+       { .compatible = "amstaos,tmd2672" },
+       { .compatible = "amstaos,tsl2772" },
+       { .compatible = "amstaos,tmd2772" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, tsl2x7x_of_match);
+
 static const struct dev_pm_ops tsl2x7x_pm_ops = {
        .suspend = tsl2x7x_suspend,
        .resume  = tsl2x7x_resume,
@@ -2035,6 +2022,7 @@ static const struct dev_pm_ops tsl2x7x_pm_ops = {
 static struct i2c_driver tsl2x7x_driver = {
        .driver = {
                .name = "tsl2x7x",
+               .of_match_table = tsl2x7x_of_match,
                .pm = &tsl2x7x_pm_ops,
        },
        .id_table = tsl2x7x_idtable,
index 497f2b3a5a62c8da6f87107de16519b176cc9f1f..1f8211b6438b86e152a2a06f0f0c535d0c7579c5 100644 (file)
@@ -325,4 +325,16 @@ ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
 ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
                                struct device_attribute *attr, char *buf);
 
+#ifdef CONFIG_OF
+void st_sensors_of_name_probe(struct device *dev,
+                             const struct of_device_id *match,
+                             char *name, int len);
+#else
+static inline void st_sensors_of_name_probe(struct device *dev,
+                                           const struct of_device_id *match,
+                                           char *name, int len)
+{
+}
+#endif
+
 #endif /* ST_SENSORS_H */
index 254de3c7dde8aa348139e4783ce9376251213688..0a2c25e06d1f95001a9f56bd2c7b3aad607a17f3 100644 (file)
 void st_sensors_i2c_configure(struct iio_dev *indio_dev,
                struct i2c_client *client, struct st_sensor_data *sdata);
 
-#ifdef CONFIG_OF
-void st_sensors_of_i2c_probe(struct i2c_client *client,
-                            const struct of_device_id *match);
-#else
-static inline void st_sensors_of_i2c_probe(struct i2c_client *client,
-                                          const struct of_device_id *match)
-{
-}
-#endif
-
 #ifdef CONFIG_ACPI
 int st_sensors_match_acpi_device(struct device *dev);
 #else