]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge tag 'iio-for-4.13a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 29 May 2017 13:53:42 +0000 (15:53 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 29 May 2017 13:53:42 +0000 (15:53 +0200)
Jonathan writes:

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

Two entirely new drivers in here plus the usual range of cleanups and features.

New device support
* ad5064
  - add ltc2631, ltc2633 and ltc2635 support.
* bma180
  - trivial support for bma250e (new id)
* hid-sensor-rotation
  - add relative orientation and geometric orientation support.
* isl29028
  - add isl29030 support (its effectively the same part from a driver point of
  view)
* maxim_thermocouple
  - add max31856 id.
* meson-saradc
  - add meson8b SoC adc support.
* ti-adc084s021
  - new driver and bindings.
* ti-adc108s102
  - new driver and bindings.

Staging graduations
* isl29028

Features
* bma180
  - ACPI enumeration for BMA250E which is used in various x86 tablets.
* hi8453
  - add raw access rather than only events.
* hid-sensor-hub
  - Implement batch mode in which we can set a threshold on the amount of time
  between data coming from the fifos.  This is the first device to do this
  rather than use a watershed on the number of samples.
* hts221
  - power management support
* lsm6dsx
  - add system power management support.
* rpr0521
  - sampling frequency read / write
* stm32-trigger
  - add support for TRG02 triggers.
* tsl2583
  - runtime power management support.

Cleanups
* core
  - inkern: fix a double unlock in iio_read_available_channel_raw when raw
  value doesn't appear to be raw (error path).
  - fixup accidental sizeof pointer in iio_device_add_mask_type.
* docs
  - fix an accidental duplicated line in sysfs-bus-iio-meas-spec.
* tools
  - use local include/uapi headers to ensure always up to date.
  - increase length of allowed trigger names.
* ad9834
  - symbolic to octal permissions.
ade7753
  - symbolic to octal permissions.
  - fix indentation
ade7754
  - symbolic to octal permissions.
ade7758
  - symbolic to octal permissions.
ade7854
  - symbolic to octal permissions.
* as3935
  - move out of storm check to given consistent results for raw and processed
  values.
* bmp280
  - fix bme280 naming in Kconfig help.
* hi8435
  - avoid garbage on event after enable.
  - add missing in_voltage_sensing_mode_available to list possible enum options.
  - handle the reset gpio with the obvious polarity rather than relying on
  DT to provide it correctly.
* hid-sensors
  - fix a wrong error path scrubbing of return values.
* hid-sensors-accel
  - drop static on a local variable
* hid-sensors-rotation
  - Add missing scale and offset property parsing support.
* ina2xx
  - Fix a bad use of GENMASK and some typos and whitespace issues.
* isl29018
  - only declare the ACPI table when ACPI is enabled.
* isl29028
  - fix proximity sleep times.
* lsm6dsx
  - replace ifdef CONFIG_PM with __maybe_unused to avoid the complexity of
  dealing with the various PM config variables.
* meson-saradc
  - mark meson_sar_adc_data static and const.
* rcar-gyroadc
  - derive the interface clock speed from the fck clock on the basis they are
  the same actual clock.
  - drop the now unused if clock from the bindings.
* rpr0521
  - disable sensor when marked as such rather than always enabling it.
  - poweroff if probe fails and we can talk to device.
  - make sure device powered off when it doesn't need to be on.
  - use sizeof rather than hardcoded size on value read.
  - whitespace fixup.
  - reorder channel numbers ready for buffered support which didn't quite
  make this pull request.
* st-accel
  - fix platform data initialization to allow remove and reprobe.
* st-pressure
  - fix platform data initialization to allow remove and reprobe.
* tsl2x7x
  - S_IRUGO, S_IWUSR to octal values
  - rename driver for consistency with more recent drivers
  - drop FSF mailing address
  - replace DEVICE_ATTR macros with the shorter DEVICE_ATTR_RW form and
  relevant function renames.
* zpa2326
  - report an error for consistency with other error paths.

64 files changed:
Documentation/ABI/testing/sysfs-bus-iio
Documentation/ABI/testing/sysfs-bus-iio-meas-spec
Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt
Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt [new file with mode: 0644]
Documentation/devicetree/bindings/trivial-devices.txt
drivers/iio/accel/bma180.c
drivers/iio/accel/hid-sensor-accel-3d.c
drivers/iio/accel/st_accel_core.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/hi8435.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/rcar-gyroadc.c
drivers/iio/adc/ti-adc084s021.c [new file with mode: 0644]
drivers/iio/adc/ti-adc108s102.c [new file with mode: 0644]
drivers/iio/common/hid-sensors/hid-sensor-attributes.c
drivers/iio/common/hid-sensors/hid-sensor-trigger.c
drivers/iio/dac/Kconfig
drivers/iio/dac/ad5064.c
drivers/iio/humidity/hts221.h
drivers/iio/humidity/hts221_core.c
drivers/iio/humidity/hts221_i2c.c
drivers/iio/humidity/hts221_spi.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
drivers/iio/industrialio-core.c
drivers/iio/inkern.c
drivers/iio/light/Kconfig
drivers/iio/light/Makefile
drivers/iio/light/isl29018.c
drivers/iio/light/isl29028.c [new file with mode: 0644]
drivers/iio/light/rpr0521.c
drivers/iio/light/tsl2583.c
drivers/iio/orientation/hid-sensor-rotation.c
drivers/iio/pressure/Kconfig
drivers/iio/pressure/st_pressure_core.c
drivers/iio/pressure/zpa2326.c
drivers/iio/proximity/as3935.c
drivers/iio/temperature/maxim_thermocouple.c
drivers/iio/trigger/stm32-timer-trigger.c
drivers/staging/iio/frequency/ad9834.c
drivers/staging/iio/frequency/dds.h
drivers/staging/iio/light/Kconfig
drivers/staging/iio/light/Makefile
drivers/staging/iio/light/isl29028.c [deleted file]
drivers/staging/iio/light/tsl2x7x.c [new file with mode: 0644]
drivers/staging/iio/light/tsl2x7x_core.c [deleted file]
drivers/staging/iio/meter/ade7753.c
drivers/staging/iio/meter/ade7754.c
drivers/staging/iio/meter/ade7758_core.c
drivers/staging/iio/meter/ade7854.c
include/linux/hid-sensor-hub.h
include/linux/hid-sensor-ids.h
include/linux/iio/timer/stm32-timer-trigger.h
include/linux/mfd/stm32-timers.h
tools/iio/Makefile
tools/iio/iio_utils.h

index 8c24d0892f61e36727fdeee50c5bd39313ecc04a..2db2cdf42d5417fc218ea29763274503467e7d01 100644 (file)
@@ -1425,6 +1425,17 @@ Description:
                guarantees that the hardware fifo is flushed to the device
                buffer.
 
+What:          /sys/bus/iio/devices/iio:device*/buffer/hwfifo_timeout
+KernelVersion: 4.12
+Contact:       linux-iio@vger.kernel.org
+Description:
+               A read/write property to provide capability to delay reporting of
+               samples till a timeout is reached. This allows host processors to
+               sleep, while the sensor is storing samples in its internal fifo.
+               The maximum timeout in seconds can be specified by setting
+               hwfifo_timeout.The current delay can be read by reading
+               hwfifo_timeout. A value of 0 means that there is no timeout.
+
 What:          /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark
 KernelVersion: 4.2
 Contact:       linux-iio@vger.kernel.org
index 1a6265e92e2faac745a5f06af3971205d443cb42..6d47e548eee503516764e22ee87f6c3a20da4d04 100644 (file)
@@ -5,4 +5,3 @@ Description:
                 Reading returns either '1' or '0'. '1' means that the
                 battery level supplied to sensor is below 2.25V.
                 This ABI is available for tsys02d, htu21, ms8607
-               This ABI is available for htu21, ms8607
index 230020e06677d73a2b8b24c031962e3fbda19c45..deb01593568393586399e0a6e5f8e0b72c973b30 100644 (file)
@@ -16,6 +16,54 @@ Description:
                - "OC2REF"    : OC2REF signal is used as trigger output.
                - "OC3REF"    : OC3REF signal is used as trigger output.
                - "OC4REF"    : OC4REF signal is used as trigger output.
+               Additional modes (on TRGO2 only):
+               - "OC5REF"    : OC5REF signal is used as trigger output.
+               - "OC6REF"    : OC6REF signal is used as trigger output.
+               - "compare_pulse_OC4REF":
+                 OC4REF rising or falling edges generate pulses.
+               - "compare_pulse_OC6REF":
+                 OC6REF rising or falling edges generate pulses.
+               - "compare_pulse_OC4REF_r_or_OC6REF_r":
+                 OC4REF or OC6REF rising edges generate pulses.
+               - "compare_pulse_OC4REF_r_or_OC6REF_f":
+                 OC4REF rising or OC6REF falling edges generate pulses.
+               - "compare_pulse_OC5REF_r_or_OC6REF_r":
+                 OC5REF or OC6REF rising edges generate pulses.
+               - "compare_pulse_OC5REF_r_or_OC6REF_f":
+                 OC5REF rising or OC6REF falling edges generate pulses.
+
+               +-----------+   +-------------+            +---------+
+               | Prescaler +-> | Counter     |        +-> | Master  | TRGO(2)
+               +-----------+   +--+--------+-+        |-> | Control +-->
+                                  |        |          ||  +---------+
+                               +--v--------+-+ OCxREF ||  +---------+
+                               | Chx compare +----------> | Output  | ChX
+                               +-----------+-+         |  | Control +-->
+                                     .     |           |  +---------+
+                                     .     |           |    .
+                               +-----------v-+ OC6REF  |    .
+                               | Ch6 compare +---------+>
+                               +-------------+
+
+               Example with: "compare_pulse_OC4REF_r_or_OC6REF_r":
+
+                               X
+                             X   X
+                           X .   . X
+                         X   .   .   X
+                       X     .   .     X
+               count X .     .   .     . X
+                       .     .   .     .
+                       .     .   .     .
+                       +---------------+
+               OC4REF  |     .   .     |
+                     +-+     .   .     +-+
+                       .     +---+     .
+               OC6REF  .     |   |     .
+                     +-------+   +-------+
+                       +-+   +-+
+               TRGO2   | |   | |
+                     +-+ +---+ +---------+
 
 What:          /sys/bus/iio/devices/triggerX/master_mode
 KernelVersion: 4.11
index 047189192aec2691f93cb28120bd4fe1a5746ef6..f413e82c8b837516ec5c72196fc19e43839dfd02 100644 (file)
@@ -2,6 +2,8 @@
 
 Required properties:
 - compatible:  depending on the SoC this should be one of:
+                       - "amlogic,meson8-saradc" for Meson8
+                       - "amlogic,meson8b-saradc" for Meson8b
                        - "amlogic,meson-gxbb-saradc" for GXBB
                        - "amlogic,meson-gxl-saradc" for GXL
                        - "amlogic,meson-gxm-saradc" for GXM
index f5b0adae6010a0d6bb4bea97477214d752554cf3..2a62908a774ae11cd91af186dd29927f55744060 100644 (file)
@@ -16,8 +16,7 @@ Required properties:
 - clocks:      References to all the clocks specified in the clock-names
                property as specified in
                Documentation/devicetree/bindings/clock/clock-bindings.txt.
-- clock-names: Shall contain "fck" and "if". The "fck" is the GyroADC block
-               clock, the "if" is the interface clock.
+- clock-names: Shall contain "fck". The "fck" is the GyroADC block clock.
 - power-domains: Must contain a reference to the PM domain, if available.
 - #address-cells: Should be <1> (setting for the subnodes) for all ADCs
                except for "fujitsu,mb88101a". Should be <0> (setting for
@@ -75,8 +74,8 @@ Example:
        adc@e6e54000 {
                compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
                reg = <0 0xe6e54000 0 64>;
-               clocks = <&mstp9_clks R8A7791_CLK_GYROADC>, <&clk_65m>;
-               clock-names = "fck", "if";
+               clocks = <&mstp9_clks R8A7791_CLK_GYROADC>;
+               clock-names = "fck";
                power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
 
                pinctrl-0 = <&adc_pins>;
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc084s021.txt
new file mode 100644 (file)
index 0000000..4259e50
--- /dev/null
@@ -0,0 +1,19 @@
+* Texas Instruments' ADC084S021
+
+Required properties:
+ - compatible        : Must be "ti,adc084s021"
+ - reg               : SPI chip select number for the device
+ - vref-supply       : The regulator supply for ADC reference voltage
+ - spi-cpol          : Per spi-bus bindings
+ - spi-cpha          : Per spi-bus bindings
+ - spi-max-frequency : Per spi-bus bindings
+
+Example:
+adc@0 {
+       compatible = "ti,adc084s021";
+       reg = <0>;
+       vref-supply = <&adc_vref>;
+       spi-cpol;
+       spi-cpha;
+       spi-max-frequency = <16000000>;
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt
new file mode 100644 (file)
index 0000000..bbbbb4a
--- /dev/null
@@ -0,0 +1,18 @@
+* Texas Instruments' ADC108S102 and ADC128S102 ADC chip
+
+Required properties:
+ - compatible: Should be "ti,adc108s102"
+ - reg: spi chip select number for the device
+ - vref-supply: The regulator supply for ADC reference voltage
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+               Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+adc@0 {
+       compatible = "ti,adc108s102";
+       reg = <0>;
+       vref-supply = <&vdd_supply>;
+       spi-max-frequency = <1000000>;
+};
index 3e0a34c88e07759bdd076e98d43a4c988e1de4cc..35f406dd86b6c191a9dd21cf7e1c3b5091d01dd4 100644 (file)
@@ -55,6 +55,7 @@ gmt,g751              G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire In
 infineon,slb9635tt     Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
 infineon,slb9645tt     Infineon SLB9645 I2C TPM (new protocol, max 400khz)
 isil,isl29028          Intersil ISL29028 Ambient Light and Proximity Sensor
+isil,isl29030          Intersil ISL29030 Ambient Light and Proximity Sensor
 maxim,ds1050           5 Bit Programmable, Pulse-Width Modulator
 maxim,max1237          Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
 maxim,max6625          9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
index efc67739c28f35d0cb6c8f354ac03de63e74d39e..17b7953f2502584483099a99cb532391dbc84e33 100644 (file)
@@ -14,6 +14,7 @@
  * BMA250: 7-bit I2C slave address 0x18 or 0x19
  */
 
+#include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
@@ -36,6 +37,7 @@
 enum chip_ids {
        BMA180,
        BMA250,
+       BMA250E,
 };
 
 struct bma180_data;
@@ -55,6 +57,7 @@ struct bma180_part_info {
        u8 power_reg, power_mask, lowpower_val;
        u8 int_enable_reg, int_enable_mask;
        u8 softreset_reg;
+       u8 chip_id;
 
        int (*chip_config)(struct bma180_data *data);
        void (*chip_disable)(struct bma180_data *data);
@@ -112,6 +115,8 @@ struct bma180_part_info {
 #define BMA250_INT1_DATA_MASK  BIT(0)
 #define BMA250_INT_RESET_MASK  BIT(7) /* Reset pending interrupts */
 
+#define BMA250E_CHIP_ID                0xf9
+
 struct bma180_data {
        struct i2c_client *client;
        struct iio_trigger *trig;
@@ -309,7 +314,7 @@ static int bma180_chip_init(struct bma180_data *data)
 
        if (ret < 0)
                return ret;
-       if (ret != BMA180_ID_REG_VAL)
+       if (ret != data->part_info->chip_id)
                return -ENODEV;
 
        ret = bma180_soft_reset(data);
@@ -632,6 +637,7 @@ static const struct bma180_part_info bma180_part_info[] = {
                BMA180_TCO_Z, BMA180_MODE_CONFIG, BMA180_LOW_POWER,
                BMA180_CTRL_REG3, BMA180_NEW_DATA_INT,
                BMA180_RESET,
+               BMA180_CHIP_ID,
                bma180_chip_config,
                bma180_chip_disable,
        },
@@ -646,6 +652,22 @@ static const struct bma180_part_info bma180_part_info[] = {
                BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1,
                BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK,
                BMA250_RESET_REG,
+               BMA180_CHIP_ID,
+               bma250_chip_config,
+               bma250_chip_disable,
+       },
+       [BMA250E] = {
+               bma250_channels, ARRAY_SIZE(bma250_channels),
+               bma250_scale_table, ARRAY_SIZE(bma250_scale_table),
+               bma250_bw_table, ARRAY_SIZE(bma250_bw_table),
+               BMA250_INT_RESET_REG, BMA250_INT_RESET_MASK,
+               BMA250_POWER_REG, BMA250_SUSPEND_MASK,
+               BMA250_BW_REG, BMA250_BW_MASK,
+               BMA250_RANGE_REG, BMA250_RANGE_MASK,
+               BMA250_POWER_REG, BMA250_LOWPOWER_MASK, 1,
+               BMA250_INT_ENABLE_REG, BMA250_DATA_INTEN_MASK,
+               BMA250_RESET_REG,
+               BMA250E_CHIP_ID,
                bma250_chip_config,
                bma250_chip_disable,
        },
@@ -706,6 +728,8 @@ static const struct iio_trigger_ops bma180_trigger_ops = {
 static int bma180_probe(struct i2c_client *client,
                const struct i2c_device_id *id)
 {
+       struct device *dev = &client->dev;
+       const struct acpi_device_id *acpi_id;
        struct bma180_data *data;
        struct iio_dev *indio_dev;
        enum chip_ids chip;
@@ -718,10 +742,17 @@ static int bma180_probe(struct i2c_client *client,
        data = iio_priv(indio_dev);
        i2c_set_clientdata(client, indio_dev);
        data->client = client;
-       if (client->dev.of_node)
+       if (dev->of_node) {
                chip = (enum chip_ids)of_device_get_match_data(&client->dev);
-       else
+       } else if (id) {
                chip = id->driver_data;
+       } else {
+               acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+               if (!acpi_id)
+                       return -ENODEV;
+
+               chip = acpi_id->driver_data;
+       }
        data->part_info = &bma180_part_info[chip];
 
        ret = data->part_info->chip_config(data);
@@ -842,9 +873,16 @@ static SIMPLE_DEV_PM_OPS(bma180_pm_ops, bma180_suspend, bma180_resume);
 #define BMA180_PM_OPS NULL
 #endif
 
+static const struct acpi_device_id bma180_acpi_match[] = {
+       { "BMA250E", BMA250E },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, bma180_acpi_match);
+
 static struct i2c_device_id bma180_ids[] = {
        { "bma180", BMA180 },
        { "bma250", BMA250 },
+       { "bma250e", BMA250E },
        { }
 };
 
@@ -866,6 +904,7 @@ MODULE_DEVICE_TABLE(of, bma180_of_match);
 static struct i2c_driver bma180_driver = {
        .driver = {
                .name   = "bma180",
+               .acpi_match_table = ACPI_PTR(bma180_acpi_match),
                .pm     = BMA180_PM_OPS,
                .of_match_table = bma180_of_match,
        },
index 43a6cb07819363e8409ed0c28e9f91ae0d49d06d..2238a26aba637d0afd5adb14cd01ad3f729fc931 100644 (file)
@@ -347,7 +347,7 @@ static int accel_3d_parse_report(struct platform_device *pdev,
 static int hid_accel_3d_probe(struct platform_device *pdev)
 {
        int ret = 0;
-       static const char *name;
+       const char *name;
        struct iio_dev *indio_dev;
        struct accel_3d_state *accel_state;
        const struct iio_chan_spec *channel_spec;
index 784670e2736b4fbbc540382afc1aefe66ccc1e5c..07d1489cd457a6b5445b8b3ba35dad95b1792acc 100644 (file)
@@ -710,6 +710,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
 int st_accel_common_probe(struct iio_dev *indio_dev)
 {
        struct st_sensor_data *adata = iio_priv(indio_dev);
+       struct st_sensors_platform_data *pdata =
+               (struct st_sensors_platform_data *)adata->dev->platform_data;
        int irq = adata->get_irq_data_ready(indio_dev);
        int err;
 
@@ -736,9 +738,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
                                        &adata->sensor_settings->fs.fs_avl[0];
        adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
 
-       if (!adata->dev->platform_data)
-               adata->dev->platform_data =
-                       (struct st_sensors_platform_data *)&default_accel_pdata;
+       if (!pdata)
+               pdata = (struct st_sensors_platform_data *)&default_accel_pdata;
 
        err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
        if (err < 0)
index 401f47b51d83a394c919e13b5e8684116ea22446..614fa41559b13059e715095efb99e0ffecc76578 100644 (file)
@@ -679,6 +679,18 @@ config TI_ADC0832
          This driver can also be built as a module. If so, the module will be
          called ti-adc0832.
 
+config TI_ADC084S021
+       tristate "Texas Instruments ADC084S021"
+       depends on SPI
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       help
+         If you say yes here you get support for Texas Instruments ADC084S021
+         chips.
+
+         This driver can also be built as a module. If so, the module will be
+         called ti-adc084s021.
+
 config TI_ADC12138
        tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
        depends on SPI
@@ -691,6 +703,18 @@ config TI_ADC12138
          This driver can also be built as a module. If so, the module will be
          called ti-adc12138.
 
+config TI_ADC108S102
+       tristate "Texas Instruments ADC108S102 and ADC128S102 driver"
+       depends on SPI
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       help
+         Say yes here to build support for Texas Instruments ADC108S102 and
+         ADC128S102 ADC.
+
+         To compile this driver as a module, choose M here: the module will
+         be called ti-adc108s102.
+
 config TI_ADC128S052
        tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
        depends on SPI
index 9339bec4babe95d650a3131192c6e42354340626..b546736a55413a1848098b6ad6a778130baf9af7 100644 (file)
@@ -62,7 +62,9 @@ obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
 obj-$(CONFIG_STM32_ADC) += stm32-adc.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
+obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o
 obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
+obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
 obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
 obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
index 678e8c7ea7633afb0dacbdca89863fb009a8847c..ab59969b7c497b0fd846fb5b02461bbfc352b4ed 100644 (file)
@@ -105,6 +105,26 @@ static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val)
        return spi_write(priv->spi, priv->reg_buffer, 3);
 }
 
+static int hi8435_read_raw(struct iio_dev *idev,
+                          const struct iio_chan_spec *chan,
+                          int *val, int *val2, long mask)
+{
+       struct hi8435_priv *priv = iio_priv(idev);
+       u32 tmp;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
+               if (ret < 0)
+                       return ret;
+               *val = !!(tmp & BIT(chan->channel));
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int hi8435_read_event_config(struct iio_dev *idev,
                                    const struct iio_chan_spec *chan,
                                    enum iio_event_type type,
@@ -121,10 +141,21 @@ static int hi8435_write_event_config(struct iio_dev *idev,
                                     enum iio_event_direction dir, int state)
 {
        struct hi8435_priv *priv = iio_priv(idev);
+       int ret;
+       u32 tmp;
+
+       if (state) {
+               ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
+               if (ret < 0)
+                       return ret;
+               if (tmp & BIT(chan->channel))
+                       priv->event_prev_val |= BIT(chan->channel);
+               else
+                       priv->event_prev_val &= ~BIT(chan->channel);
 
-       priv->event_scan_mask &= ~BIT(chan->channel);
-       if (state)
                priv->event_scan_mask |= BIT(chan->channel);
+       } else
+               priv->event_scan_mask &= ~BIT(chan->channel);
 
        return 0;
 }
@@ -325,6 +356,7 @@ static const struct iio_enum hi8435_sensing_mode = {
 
 static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
        IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
+       IIO_ENUM_AVAILABLE("sensing_mode", &hi8435_sensing_mode),
        {},
 };
 
@@ -333,6 +365,7 @@ static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
        .type = IIO_VOLTAGE,                            \
        .indexed = 1,                                   \
        .channel = num,                                 \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
        .event_spec = hi8435_events,                    \
        .num_event_specs = ARRAY_SIZE(hi8435_events),   \
        .ext_info = hi8435_ext_info,                    \
@@ -376,6 +409,7 @@ static const struct iio_chan_spec hi8435_channels[] = {
 
 static const struct iio_info hi8435_info = {
        .driver_module = THIS_MODULE,
+       .read_raw = hi8435_read_raw,
        .read_event_config = &hi8435_read_event_config,
        .write_event_config = hi8435_write_event_config,
        .read_event_value = &hi8435_read_event_value,
@@ -442,13 +476,15 @@ static int hi8435_probe(struct spi_device *spi)
        priv->spi = spi;
 
        reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
-       if (IS_ERR(reset_gpio)) {
-               /* chip s/w reset if h/w reset failed */
+       if (!IS_ERR(reset_gpio)) {
+               /* need >=100ns low pulse to reset chip */
+               gpiod_set_raw_value_cansleep(reset_gpio, 0);
+               udelay(1);
+               gpiod_set_raw_value_cansleep(reset_gpio, 1);
+       } else {
+               /* s/w reset chip if h/w reset is not available */
                hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
                hi8435_writeb(priv, HI8435_CTRL_REG, 0);
-       } else {
-               udelay(5);
-               gpiod_set_value(reset_gpio, 1);
        }
 
        spi_set_drvdata(spi, idev);
index db983823025775534141c076cb9355e4992a3f79..6b588ac3130c18b5e6f2ca369cc0d6a5417d48cb 100644 (file)
@@ -42,8 +42,8 @@
 #define INA2XX_CURRENT                  0x04   /* readonly */
 #define INA2XX_CALIBRATION              0x05
 
-#define INA226_ALERT_MASK              GENMASK(2, 1)
-#define INA266_CVRF                    BIT(3)
+#define INA226_MASK_ENABLE             0x06
+#define INA226_CVRF                    BIT(3)
 
 #define INA2XX_MAX_REGISTERS            8
 
@@ -417,8 +417,8 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
        .address = (_address), \
        .indexed = 1, \
        .channel = (_index), \
-       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
-       | BIT(IIO_CHAN_INFO_SCALE), \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \
+                             BIT(IIO_CHAN_INFO_SCALE), \
        .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
                                   BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
        .scan_index = (_index), \
@@ -481,12 +481,12 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
         */
        if (!chip->allow_async_readout)
                do {
-                       ret = regmap_read(chip->regmap, INA226_ALERT_MASK,
+                       ret = regmap_read(chip->regmap, INA226_MASK_ENABLE,
                                          &alert);
                        if (ret < 0)
                                return ret;
 
-                       alert &= INA266_CVRF;
+                       alert &= INA226_CVRF;
                } while (!alert);
 
        /*
index dd4190b50df6a71a43d0fb22175ddb3f1e7d64c7..81cd39a57fe36bc091da84c9304ddddca6bcc0ab 100644 (file)
@@ -220,6 +220,7 @@ enum meson_sar_adc_chan7_mux_sel {
 };
 
 struct meson_sar_adc_data {
+       bool                                    has_bl30_integration;
        unsigned int                            resolution;
        const char                              *name;
 };
@@ -437,19 +438,24 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
 
        mutex_lock(&indio_dev->mlock);
 
-       /* prevent BL30 from using the SAR ADC while we are using it */
-       regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
-                          MESON_SAR_ADC_DELAY_KERNEL_BUSY,
-                          MESON_SAR_ADC_DELAY_KERNEL_BUSY);
-
-       /* wait until BL30 releases it's lock (so we can use the SAR ADC) */
-       do {
-               udelay(1);
-               regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
-       } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
-
-       if (timeout < 0)
-               return -ETIMEDOUT;
+       if (priv->data->has_bl30_integration) {
+               /* prevent BL30 from using the SAR ADC while we are using it */
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+                               MESON_SAR_ADC_DELAY_KERNEL_BUSY,
+                               MESON_SAR_ADC_DELAY_KERNEL_BUSY);
+
+               /*
+                * wait until BL30 releases it's lock (so we can use the SAR
+                * ADC)
+                */
+               do {
+                       udelay(1);
+                       regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
+               } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
+
+               if (timeout < 0)
+                       return -ETIMEDOUT;
+       }
 
        return 0;
 }
@@ -458,9 +464,10 @@ static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
 {
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
 
-       /* allow BL30 to use the SAR ADC again */
-       regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
-                          MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
+       if (priv->data->has_bl30_integration)
+               /* allow BL30 to use the SAR ADC again */
+               regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+                               MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
 
        mutex_unlock(&indio_dev->mlock);
 }
@@ -614,14 +621,16 @@ static int meson_sar_adc_init(struct iio_dev *indio_dev)
         */
        meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
 
-       /*
-        * leave sampling delay and the input clocks as configured by BL30 to
-        * make sure BL30 gets the values it expects when reading the
-        * temperature sensor.
-        */
-       regmap_read(priv->regmap, MESON_SAR_ADC_REG3, &regval);
-       if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED)
-               return 0;
+       if (priv->data->has_bl30_integration) {
+               /*
+                * leave sampling delay and the input clocks as configured by
+                * BL30 to make sure BL30 gets the values it expects when
+                * reading the temperature sensor.
+                */
+               regmap_read(priv->regmap, MESON_SAR_ADC_REG3, &regval);
+               if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED)
+                       return 0;
+       }
 
        meson_sar_adc_stop_sample_engine(indio_dev);
 
@@ -834,22 +843,45 @@ static const struct iio_info meson_sar_adc_iio_info = {
        .driver_module = THIS_MODULE,
 };
 
-struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
+static const struct meson_sar_adc_data meson_sar_adc_meson8_data = {
+       .has_bl30_integration = false,
+       .resolution = 10,
+       .name = "meson-meson8-saradc",
+};
+
+static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = {
+       .has_bl30_integration = false,
+       .resolution = 10,
+       .name = "meson-meson8b-saradc",
+};
+
+static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
+       .has_bl30_integration = true,
        .resolution = 10,
        .name = "meson-gxbb-saradc",
 };
 
-struct meson_sar_adc_data meson_sar_adc_gxl_data = {
+static const struct meson_sar_adc_data meson_sar_adc_gxl_data = {
+       .has_bl30_integration = true,
        .resolution = 12,
        .name = "meson-gxl-saradc",
 };
 
-struct meson_sar_adc_data meson_sar_adc_gxm_data = {
+static const struct meson_sar_adc_data meson_sar_adc_gxm_data = {
+       .has_bl30_integration = true,
        .resolution = 12,
        .name = "meson-gxm-saradc",
 };
 
 static const struct of_device_id meson_sar_adc_of_match[] = {
+       {
+               .compatible = "amlogic,meson8-saradc",
+               .data = &meson_sar_adc_meson8_data,
+       },
+       {
+               .compatible = "amlogic,meson8b-saradc",
+               .data = &meson_sar_adc_meson8b_data,
+       },
        {
                .compatible = "amlogic,meson-gxbb-saradc",
                .data = &meson_sar_adc_gxbb_data,
index 018ed360e717cd619e89844225db1f374e1c2536..27a3181646191aa1171ffec7923a823a6155bf33 100644 (file)
@@ -73,7 +73,7 @@ enum rcar_gyroadc_model {
 struct rcar_gyroadc {
        struct device                   *dev;
        void __iomem                    *regs;
-       struct clk                      *iclk;
+       struct clk                      *clk;
        struct regulator                *vref[8];
        unsigned int                    num_channels;
        enum rcar_gyroadc_model         model;
@@ -83,7 +83,7 @@ struct rcar_gyroadc {
 
 static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv)
 {
-       const unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000;
+       const unsigned long clk_mhz = clk_get_rate(priv->clk) / 1000000;
        const unsigned long clk_mul =
                (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5;
        unsigned long clk_len = clk_mhz * clk_mul;
@@ -510,9 +510,9 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
        if (IS_ERR(priv->regs))
                return PTR_ERR(priv->regs);
 
-       priv->iclk = devm_clk_get(dev, "if");
-       if (IS_ERR(priv->iclk)) {
-               ret = PTR_ERR(priv->iclk);
+       priv->clk = devm_clk_get(dev, "fck");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
                if (ret != -EPROBE_DEFER)
                        dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret);
                return ret;
@@ -536,7 +536,7 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
        indio_dev->info = &rcar_gyroadc_iio_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
 
-       ret = clk_prepare_enable(priv->iclk);
+       ret = clk_prepare_enable(priv->clk);
        if (ret) {
                dev_err(dev, "Could not prepare or enable the IF clock.\n");
                goto err_clk_if_enable;
@@ -565,7 +565,7 @@ err_iio_device_register:
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
-       clk_disable_unprepare(priv->iclk);
+       clk_disable_unprepare(priv->clk);
 err_clk_if_enable:
        rcar_gyroadc_deinit_supplies(indio_dev);
 
@@ -584,7 +584,7 @@ static int rcar_gyroadc_remove(struct platform_device *pdev)
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
-       clk_disable_unprepare(priv->iclk);
+       clk_disable_unprepare(priv->clk);
        rcar_gyroadc_deinit_supplies(indio_dev);
 
        return 0;
diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c
new file mode 100644 (file)
index 0000000..a355121
--- /dev/null
@@ -0,0 +1,275 @@
+/**
+ * Copyright (C) 2017 Axis Communications AB
+ *
+ * Driver for Texas Instruments' ADC084S021 ADC chip.
+ * Datasheets can be found here:
+ * http://www.ti.com/lit/ds/symlink/adc084s021.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/regulator/consumer.h>
+
+#define ADC084S021_DRIVER_NAME "adc084s021"
+
+struct adc084s021 {
+       struct spi_device *spi;
+       struct spi_message message;
+       struct spi_transfer spi_trans;
+       struct regulator *reg;
+       struct mutex lock;
+       /*
+        * DMA (thus cache coherency maintenance) requires the
+        * transfer buffers to live in their own cache line.
+        */
+       u16 tx_buf[4] ____cacheline_aligned;
+       __be16 rx_buf[5]; /* First 16-bits are trash */
+};
+
+#define ADC084S021_VOLTAGE_CHANNEL(num)                  \
+       {                                                      \
+               .type = IIO_VOLTAGE,                                 \
+               .channel = (num),                                    \
+               .indexed = 1,                                        \
+               .scan_index = (num),                                 \
+               .scan_type = {                                       \
+                       .sign = 'u',                                       \
+                       .realbits = 8,                                     \
+                       .storagebits = 16,                                 \
+                       .shift = 4,                                        \
+                       .endianness = IIO_BE,                              \
+               },                                                   \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),        \
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
+       }
+
+static const struct iio_chan_spec adc084s021_channels[] = {
+       ADC084S021_VOLTAGE_CHANNEL(0),
+       ADC084S021_VOLTAGE_CHANNEL(1),
+       ADC084S021_VOLTAGE_CHANNEL(2),
+       ADC084S021_VOLTAGE_CHANNEL(3),
+       IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+/**
+ * Read an ADC channel and return its value.
+ *
+ * @adc: The ADC SPI data.
+ * @data: Buffer for converted data.
+ */
+static int adc084s021_adc_conversion(struct adc084s021 *adc, void *data)
+{
+       int n_words = (adc->spi_trans.len >> 1) - 1; /* Discard first word */
+       int ret, i = 0;
+       u16 *p = data;
+
+       /* Do the transfer */
+       ret = spi_sync(adc->spi, &adc->message);
+       if (ret < 0)
+               return ret;
+
+       for (; i < n_words; i++)
+               *(p + i) = adc->rx_buf[i + 1];
+
+       return ret;
+}
+
+static int adc084s021_read_raw(struct iio_dev *indio_dev,
+                          struct iio_chan_spec const *channel, int *val,
+                          int *val2, long mask)
+{
+       struct adc084s021 *adc = iio_priv(indio_dev);
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret < 0)
+                       return ret;
+
+               ret = regulator_enable(adc->reg);
+               if (ret) {
+                       iio_device_release_direct_mode(indio_dev);
+                       return ret;
+               }
+
+               adc->tx_buf[0] = channel->channel << 3;
+               ret = adc084s021_adc_conversion(adc, val);
+               iio_device_release_direct_mode(indio_dev);
+               regulator_disable(adc->reg);
+               if (ret < 0)
+                       return ret;
+
+               *val = be16_to_cpu(*val);
+               *val = (*val >> channel->scan_type.shift) & 0xff;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               ret = regulator_enable(adc->reg);
+               if (ret)
+                       return ret;
+
+               ret = regulator_get_voltage(adc->reg);
+               regulator_disable(adc->reg);
+               if (ret < 0)
+                       return ret;
+
+               *val = ret / 1000;
+
+               return IIO_VAL_INT;
+       default:
+               return -EINVAL;
+       }
+}
+
+/**
+ * Read enabled ADC channels and push data to the buffer.
+ *
+ * @irq: The interrupt number (not used).
+ * @pollfunc: Pointer to the poll func.
+ */
+static irqreturn_t adc084s021_buffer_trigger_handler(int irq, void *pollfunc)
+{
+       struct iio_poll_func *pf = pollfunc;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct adc084s021 *adc = iio_priv(indio_dev);
+       __be16 data[8] = {0}; /* 4 * 16-bit words of data + 8 bytes timestamp */
+
+       mutex_lock(&adc->lock);
+
+       if (adc084s021_adc_conversion(adc, &data) < 0)
+               dev_err(&adc->spi->dev, "Failed to read data\n");
+
+       iio_push_to_buffers_with_timestamp(indio_dev, data,
+                                          iio_get_time_ns(indio_dev));
+       mutex_unlock(&adc->lock);
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int adc084s021_buffer_preenable(struct iio_dev *indio_dev)
+{
+       struct adc084s021 *adc = iio_priv(indio_dev);
+       int scan_index;
+       int i = 0;
+
+       for_each_set_bit(scan_index, indio_dev->active_scan_mask,
+                        indio_dev->masklength) {
+               const struct iio_chan_spec *channel =
+                       &indio_dev->channels[scan_index];
+               adc->tx_buf[i++] = channel->channel << 3;
+       }
+       adc->spi_trans.len = 2 + (i * sizeof(__be16)); /* Trash + channels */
+
+       return regulator_enable(adc->reg);
+}
+
+static int adc084s021_buffer_postdisable(struct iio_dev *indio_dev)
+{
+       struct adc084s021 *adc = iio_priv(indio_dev);
+
+       adc->spi_trans.len = 4; /* Trash + single channel */
+
+       return regulator_disable(adc->reg);
+}
+
+static const struct iio_info adc084s021_info = {
+       .read_raw = adc084s021_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+static const struct iio_buffer_setup_ops adc084s021_buffer_setup_ops = {
+       .preenable = adc084s021_buffer_preenable,
+       .postenable = iio_triggered_buffer_postenable,
+       .predisable = iio_triggered_buffer_predisable,
+       .postdisable = adc084s021_buffer_postdisable,
+};
+
+static int adc084s021_probe(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev;
+       struct adc084s021 *adc;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
+       if (!indio_dev) {
+               dev_err(&spi->dev, "Failed to allocate IIO device\n");
+               return -ENOMEM;
+       }
+
+       adc = iio_priv(indio_dev);
+       adc->spi = spi;
+
+       /* Connect the SPI device and the iio dev */
+       spi_set_drvdata(spi, indio_dev);
+
+       /* Initiate the Industrial I/O device */
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->dev.of_node = spi->dev.of_node;
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &adc084s021_info;
+       indio_dev->channels = adc084s021_channels;
+       indio_dev->num_channels = ARRAY_SIZE(adc084s021_channels);
+
+       /* Create SPI transfer for channel reads */
+       adc->spi_trans.tx_buf = adc->tx_buf;
+       adc->spi_trans.rx_buf = adc->rx_buf;
+       adc->spi_trans.len = 4; /* Trash + single channel */
+       spi_message_init_with_transfers(&adc->message, &adc->spi_trans, 1);
+
+       adc->reg = devm_regulator_get(&spi->dev, "vref");
+       if (IS_ERR(adc->reg))
+               return PTR_ERR(adc->reg);
+
+       mutex_init(&adc->lock);
+
+       /* Setup triggered buffer with pollfunction */
+       ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, NULL,
+                                           adc084s021_buffer_trigger_handler,
+                                           &adc084s021_buffer_setup_ops);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to setup triggered buffer\n");
+               return ret;
+       }
+
+       return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct of_device_id adc084s021_of_match[] = {
+       { .compatible = "ti,adc084s021", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, adc084s021_of_match);
+
+static const struct spi_device_id adc084s021_id[] = {
+       { ADC084S021_DRIVER_NAME, 0},
+       {}
+};
+MODULE_DEVICE_TABLE(spi, adc084s021_id);
+
+static struct spi_driver adc084s021_driver = {
+       .driver = {
+               .name = ADC084S021_DRIVER_NAME,
+               .of_match_table = of_match_ptr(adc084s021_of_match),
+       },
+       .probe = adc084s021_probe,
+       .id_table = adc084s021_id,
+};
+module_spi_driver(adc084s021_driver);
+
+MODULE_AUTHOR("MÃ¥rten Lindahl <martenli@axis.com>");
+MODULE_DESCRIPTION("Texas Instruments ADC084S021");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("1.0");
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
new file mode 100644 (file)
index 0000000..de4e5ac
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * TI ADC108S102 SPI ADC driver
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ * Copyright (c) 2017 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * This IIO device driver is designed to work with the following
+ * analog to digital converters from Texas Instruments:
+ *  ADC108S102
+ *  ADC128S102
+ * The communication with ADC chip is via the SPI bus (mode 3).
+ */
+
+#include <linux/acpi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/types.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+/*
+ * In case of ACPI, we use the hard-wired 5000 mV of the Galileo and IOT2000
+ * boards as default for the reference pin VA. Device tree users encode that
+ * via the vref-supply regulator.
+ */
+#define ADC108S102_VA_MV_ACPI_DEFAULT  5000
+
+/*
+ * Defining the ADC resolution being 12 bits, we can use the same driver for
+ * both ADC108S102 (10 bits resolution) and ADC128S102 (12 bits resolution)
+ * chips. The ADC108S102 effectively returns a 12-bit result with the 2
+ * least-significant bits unset.
+ */
+#define ADC108S102_BITS                12
+#define ADC108S102_MAX_CHANNELS        8
+
+/*
+ * 16-bit SPI command format:
+ *   [15:14] Ignored
+ *   [13:11] 3-bit channel address
+ *   [10:0]  Ignored
+ */
+#define ADC108S102_CMD(ch)             ((u16)(ch) << 11)
+
+/*
+ * 16-bit SPI response format:
+ *   [15:12] Zeros
+ *   [11:0]  12-bit ADC sample (for ADC108S102, [1:0] will always be 0).
+ */
+#define ADC108S102_RES_DATA(res)       ((u16)res & GENMASK(11, 0))
+
+struct adc108s102_state {
+       struct spi_device               *spi;
+       struct regulator                *reg;
+       u32                             va_millivolt;
+       /* SPI transfer used by triggered buffer handler*/
+       struct spi_transfer             ring_xfer;
+       /* SPI transfer used by direct scan */
+       struct spi_transfer             scan_single_xfer;
+       /* SPI message used by ring_xfer SPI transfer */
+       struct spi_message              ring_msg;
+       /* SPI message used by scan_single_xfer SPI transfer */
+       struct spi_message              scan_single_msg;
+
+       /*
+        * SPI message buffers:
+        *  tx_buf: |C0|C1|C2|C3|C4|C5|C6|C7|XX|
+        *  rx_buf: |XX|R0|R1|R2|R3|R4|R5|R6|R7|tt|tt|tt|tt|
+        *
+        *  tx_buf: 8 channel read commands, plus 1 dummy command
+        *  rx_buf: 1 dummy response, 8 channel responses, plus 64-bit timestamp
+        */
+       __be16                          rx_buf[13] ____cacheline_aligned;
+       __be16                          tx_buf[9] ____cacheline_aligned;
+};
+
+#define ADC108S102_V_CHAN(index)                                       \
+       {                                                               \
+               .type = IIO_VOLTAGE,                                    \
+               .indexed = 1,                                           \
+               .channel = index,                                       \
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |          \
+                       BIT(IIO_CHAN_INFO_SCALE),                       \
+               .address = index,                                       \
+               .scan_index = index,                                    \
+               .scan_type = {                                          \
+                       .sign = 'u',                                    \
+                       .realbits = ADC108S102_BITS,                    \
+                       .storagebits = 16,                              \
+                       .endianness = IIO_BE,                           \
+               },                                                      \
+       }
+
+static const struct iio_chan_spec adc108s102_channels[] = {
+       ADC108S102_V_CHAN(0),
+       ADC108S102_V_CHAN(1),
+       ADC108S102_V_CHAN(2),
+       ADC108S102_V_CHAN(3),
+       ADC108S102_V_CHAN(4),
+       ADC108S102_V_CHAN(5),
+       ADC108S102_V_CHAN(6),
+       ADC108S102_V_CHAN(7),
+       IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static int adc108s102_update_scan_mode(struct iio_dev *indio_dev,
+               unsigned long const *active_scan_mask)
+{
+       struct adc108s102_state *st = iio_priv(indio_dev);
+       unsigned int bit, cmds;
+
+       /*
+        * Fill in the first x shorts of tx_buf with the number of channels
+        * enabled for sampling by the triggered buffer.
+        */
+       cmds = 0;
+       for_each_set_bit(bit, active_scan_mask, ADC108S102_MAX_CHANNELS)
+               st->tx_buf[cmds++] = cpu_to_be16(ADC108S102_CMD(bit));
+
+       /* One dummy command added, to clock in the last response */
+       st->tx_buf[cmds++] = 0x00;
+
+       /* build SPI ring message */
+       st->ring_xfer.tx_buf = &st->tx_buf[0];
+       st->ring_xfer.rx_buf = &st->rx_buf[0];
+       st->ring_xfer.len = cmds * sizeof(st->tx_buf[0]);
+
+       spi_message_init_with_transfers(&st->ring_msg, &st->ring_xfer, 1);
+
+       return 0;
+}
+
+static irqreturn_t adc108s102_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct adc108s102_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = spi_sync(st->spi, &st->ring_msg);
+       if (ret < 0)
+               goto out_notify;
+
+       /* Skip the dummy response in the first slot */
+       iio_push_to_buffers_with_timestamp(indio_dev,
+                                          (u8 *)&st->rx_buf[1],
+                                          iio_get_time_ns(indio_dev));
+
+out_notify:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int adc108s102_scan_direct(struct adc108s102_state *st, unsigned int ch)
+{
+       int ret;
+
+       st->tx_buf[0] = cpu_to_be16(ADC108S102_CMD(ch));
+       ret = spi_sync(st->spi, &st->scan_single_msg);
+       if (ret)
+               return ret;
+
+       /* Skip the dummy response in the first slot */
+       return be16_to_cpu(st->rx_buf[1]);
+}
+
+static int adc108s102_read_raw(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              int *val, int *val2, long m)
+{
+       struct adc108s102_state *st = iio_priv(indio_dev);
+       int ret;
+
+       switch (m) {
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               ret = adc108s102_scan_direct(st, chan->address);
+
+               iio_device_release_direct_mode(indio_dev);
+
+               if (ret < 0)
+                       return ret;
+
+               *val = ADC108S102_RES_DATA(ret);
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type != IIO_VOLTAGE)
+                       break;
+
+               *val = st->va_millivolt;
+               *val2 = chan->scan_type.realbits;
+
+               return IIO_VAL_FRACTIONAL_LOG2;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_info adc108s102_info = {
+       .read_raw               = &adc108s102_read_raw,
+       .update_scan_mode       = &adc108s102_update_scan_mode,
+       .driver_module          = THIS_MODULE,
+};
+
+static int adc108s102_probe(struct spi_device *spi)
+{
+       struct adc108s102_state *st;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+
+       if (ACPI_COMPANION(&spi->dev)) {
+               st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT;
+       } else {
+               st->reg = devm_regulator_get(&spi->dev, "vref");
+               if (IS_ERR(st->reg))
+                       return PTR_ERR(st->reg);
+
+               ret = regulator_enable(st->reg);
+               if (ret < 0) {
+                       dev_err(&spi->dev, "Cannot enable vref regulator\n");
+                       return ret;
+               }
+
+               ret = regulator_get_voltage(st->reg);
+               if (ret < 0) {
+                       dev_err(&spi->dev, "vref get voltage failed\n");
+                       return ret;
+               }
+
+               st->va_millivolt = ret / 1000;
+       }
+
+       spi_set_drvdata(spi, indio_dev);
+       st->spi = spi;
+
+       indio_dev->name = spi->modalias;
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = adc108s102_channels;
+       indio_dev->num_channels = ARRAY_SIZE(adc108s102_channels);
+       indio_dev->info = &adc108s102_info;
+
+       /* Setup default message */
+       st->scan_single_xfer.tx_buf = st->tx_buf;
+       st->scan_single_xfer.rx_buf = st->rx_buf;
+       st->scan_single_xfer.len = 2 * sizeof(st->tx_buf[0]);
+
+       spi_message_init_with_transfers(&st->scan_single_msg,
+                                       &st->scan_single_xfer, 1);
+
+       ret = iio_triggered_buffer_setup(indio_dev, NULL,
+                                        &adc108s102_trigger_handler, NULL);
+       if (ret)
+               goto error_disable_reg;
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(&spi->dev, "Failed to register IIO device\n");
+               goto error_cleanup_triggered_buffer;
+       }
+       return 0;
+
+error_cleanup_triggered_buffer:
+       iio_triggered_buffer_cleanup(indio_dev);
+
+error_disable_reg:
+       regulator_disable(st->reg);
+
+       return ret;
+}
+
+static int adc108s102_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct adc108s102_state *st = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       iio_triggered_buffer_cleanup(indio_dev);
+
+       regulator_disable(st->reg);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id adc108s102_of_match[] = {
+       { .compatible = "ti,adc108s102" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, adc108s102_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id adc108s102_acpi_ids[] = {
+       { "INT3495", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids);
+#endif
+
+static const struct spi_device_id adc108s102_id[] = {
+       { "adc108s102", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, adc108s102_id);
+
+static struct spi_driver adc108s102_driver = {
+       .driver = {
+               .name   = "adc108s102",
+               .of_match_table = of_match_ptr(adc108s102_of_match),
+               .acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
+       },
+       .probe          = adc108s102_probe,
+       .remove         = adc108s102_remove,
+       .id_table       = adc108s102_id,
+};
+module_spi_driver(adc108s102_driver);
+
+MODULE_AUTHOR("Bogdan Pricop <bogdan.pricop@emutex.com>");
+MODULE_DESCRIPTION("Texas Instruments ADC108S102 and ADC128S102 driver");
+MODULE_LICENSE("GPL v2");
index 1c0874cdf665c8b3928fc1b725edf86a9441c2a3..f5d4d786e1932f93576e75e23468e694a24e827a 100644 (file)
@@ -69,6 +69,12 @@ static struct {
        {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND,
                1000000, 0},
 
+       {HID_USAGE_SENSOR_DEVICE_ORIENTATION, 0, 1, 0},
+
+       {HID_USAGE_SENSOR_RELATIVE_ORIENTATION, 0, 1, 0},
+
+       {HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION, 0, 1, 0},
+
        {HID_USAGE_SENSOR_TEMPERATURE, 0, 1000, 0},
        {HID_USAGE_SENSOR_TEMPERATURE, HID_USAGE_SENSOR_UNITS_DEGREES, 1000, 0},
 
@@ -230,7 +236,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
        ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id,
                                     st->poll.index, sizeof(value), &value);
        if (ret < 0 || value < 0)
-               ret = -EINVAL;
+               return -EINVAL;
 
        ret = sensor_hub_get_feature(st->hsdev,
                                     st->poll.report_id,
@@ -283,7 +289,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st,
                                     st->sensitivity.index, sizeof(value),
                                     &value);
        if (ret < 0 || value < 0)
-               ret = -EINVAL;
+               return -EINVAL;
 
        ret = sensor_hub_get_feature(st->hsdev,
                                     st->sensitivity.report_id,
@@ -404,6 +410,48 @@ int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
 
 }
 
+static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device *hsdev,
+                                              u32 usage_id,
+                                              struct hid_sensor_common *st)
+{
+       sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT,
+                                           usage_id,
+                                           HID_USAGE_SENSOR_PROP_REPORT_LATENCY,
+                                           &st->report_latency);
+
+       hid_dbg(hsdev->hdev, "Report latency attributes: %x:%x\n",
+               st->report_latency.index, st->report_latency.report_id);
+}
+
+int hid_sensor_get_report_latency(struct hid_sensor_common *st)
+{
+       int ret;
+       int value;
+
+       ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id,
+                                    st->report_latency.index, sizeof(value),
+                                    &value);
+       if (ret < 0)
+               return ret;
+
+       return value;
+}
+EXPORT_SYMBOL(hid_sensor_get_report_latency);
+
+int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms)
+{
+       return sensor_hub_set_feature(st->hsdev, st->report_latency.report_id,
+                                     st->report_latency.index,
+                                     sizeof(latency_ms), &latency_ms);
+}
+EXPORT_SYMBOL(hid_sensor_set_report_latency);
+
+bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st)
+{
+       return st->report_latency.index > 0 && st->report_latency.report_id > 0;
+}
+EXPORT_SYMBOL(hid_sensor_batch_mode_supported);
+
 int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
                                        u32 usage_id,
                                        struct hid_sensor_common *st)
@@ -445,6 +493,8 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev,
        } else
                st->timestamp_ns_scale = 1000000000;
 
+       hid_sensor_get_report_latency_info(hsdev, usage_id, st);
+
        hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n",
                st->poll.index, st->poll.report_id,
                st->report_state.index, st->report_state.report_id,
index 0b5dea0502398b767d45bd36f37c8530f0f287ac..16ade0a0327bafbe478db6a3714549c455582a97 100644 (file)
 #include <linux/hid-sensor-hub.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
 #include <linux/iio/sysfs.h>
 #include "hid-sensor-trigger.h"
 
+static ssize_t _hid_sensor_set_report_latency(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t len)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+       int integer, fract, ret;
+       int latency;
+
+       ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract);
+       if (ret)
+               return ret;
+
+       latency = integer * 1000 + fract / 1000;
+       ret = hid_sensor_set_report_latency(attrb, latency);
+       if (ret < 0)
+               return len;
+
+       attrb->latency_ms = hid_sensor_get_report_latency(attrb);
+
+       return len;
+}
+
+static ssize_t _hid_sensor_get_report_latency(struct device *dev,
+                                             struct device_attribute *attr,
+                                             char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+       int latency;
+
+       latency = hid_sensor_get_report_latency(attrb);
+       if (latency < 0)
+               return latency;
+
+       return sprintf(buf, "%d.%06u\n", latency / 1000, (latency % 1000) * 1000);
+}
+
+static ssize_t _hid_sensor_get_fifo_state(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+       int latency;
+
+       latency = hid_sensor_get_report_latency(attrb);
+       if (latency < 0)
+               return latency;
+
+       return sprintf(buf, "%d\n", !!latency);
+}
+
+static IIO_DEVICE_ATTR(hwfifo_timeout, 0644,
+                      _hid_sensor_get_report_latency,
+                      _hid_sensor_set_report_latency, 0);
+static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
+                      _hid_sensor_get_fifo_state, NULL, 0);
+
+static const struct attribute *hid_sensor_fifo_attributes[] = {
+       &iio_dev_attr_hwfifo_timeout.dev_attr.attr,
+       &iio_dev_attr_hwfifo_enabled.dev_attr.attr,
+       NULL,
+};
+
+static void hid_sensor_setup_batch_mode(struct iio_dev *indio_dev,
+                                       struct hid_sensor_common *st)
+{
+       if (!hid_sensor_batch_mode_supported(st))
+               return;
+
+       iio_buffer_set_attrs(indio_dev->buffer, hid_sensor_fifo_attributes);
+}
+
 static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
 {
        int state_val;
@@ -141,6 +216,9 @@ static void hid_sensor_set_power_work(struct work_struct *work)
                                       sizeof(attrb->raw_hystersis),
                                       &attrb->raw_hystersis);
 
+       if (attrb->latency_ms > 0)
+               hid_sensor_set_report_latency(attrb, attrb->latency_ms);
+
        _hid_sensor_power_state(attrb, true);
 }
 
@@ -192,6 +270,8 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
        attrb->trigger = trig;
        indio_dev->trig = iio_trigger_get(trig);
 
+       hid_sensor_setup_batch_mode(indio_dev, attrb);
+
        ret = pm_runtime_set_active(&indio_dev->dev);
        if (ret)
                goto error_unreg_trigger;
index df5abc46cd3f509d16926aa865bfb83a156681c3..25bed2d7d2b99f394e7cb0c995a4572d96121210 100644 (file)
@@ -13,7 +13,8 @@ config AD5064
          AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, AD5627, AD5627R,
          AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, AD5666,
          AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616,
-         LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to Analog Converter.
+         LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635
+         Digital to Analog Converter.
 
          To compile this driver as a module, choose M here: the
          module will be called ad5064.
index 6803e4a137cd86554bd2ccc090ff2c1086c8ed99..3f9399c278691ab8348a1ab195f5fd154b0a9a7b 100644 (file)
@@ -2,8 +2,8 @@
  * AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R,
  * AD5627, AD5627R, AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R,
  * AD5666, AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616,
- * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to analog converters
- * driver
+ * LTC2617, LTC2619, LTC2626, LTC2627, LTC2629, LTC2631, LTC2633, LTC2635
+ * Digital to analog converters driver
  *
  * Copyright 2011 Analog Devices Inc.
  *
@@ -168,6 +168,24 @@ enum ad5064_type {
        ID_LTC2626,
        ID_LTC2627,
        ID_LTC2629,
+       ID_LTC2631_L12,
+       ID_LTC2631_H12,
+       ID_LTC2631_L10,
+       ID_LTC2631_H10,
+       ID_LTC2631_L8,
+       ID_LTC2631_H8,
+       ID_LTC2633_L12,
+       ID_LTC2633_H12,
+       ID_LTC2633_L10,
+       ID_LTC2633_H10,
+       ID_LTC2633_L8,
+       ID_LTC2633_H8,
+       ID_LTC2635_L12,
+       ID_LTC2635_H12,
+       ID_LTC2635_L10,
+       ID_LTC2635_H10,
+       ID_LTC2635_L8,
+       ID_LTC2635_H8,
 };
 
 static int ad5064_write(struct ad5064_state *st, unsigned int cmd,
@@ -425,6 +443,19 @@ static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0, ad5064_ext_info);
 static DECLARE_AD5064_CHANNELS(ltc2607_channels, 16, 0, ltc2617_ext_info);
 static DECLARE_AD5064_CHANNELS(ltc2617_channels, 14, 2, ltc2617_ext_info);
 static DECLARE_AD5064_CHANNELS(ltc2627_channels, 12, 4, ltc2617_ext_info);
+#define ltc2631_12_channels ltc2627_channels
+static DECLARE_AD5064_CHANNELS(ltc2631_10_channels, 10, 6, ltc2617_ext_info);
+static DECLARE_AD5064_CHANNELS(ltc2631_8_channels, 8, 8, ltc2617_ext_info);
+
+#define LTC2631_INFO(vref, pchannels, nchannels)       \
+       {                                               \
+               .shared_vref = true,                    \
+               .internal_vref = vref,                  \
+               .channels = pchannels,                  \
+               .num_channels = nchannels,              \
+               .regmap_type = AD5064_REGMAP_LTC,       \
+       }
+
 
 static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
        [ID_AD5024] = {
@@ -724,6 +755,24 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
                .num_channels = 4,
                .regmap_type = AD5064_REGMAP_LTC,
        },
+       [ID_LTC2631_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 1),
+       [ID_LTC2631_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 1),
+       [ID_LTC2631_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 1),
+       [ID_LTC2631_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 1),
+       [ID_LTC2631_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 1),
+       [ID_LTC2631_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 1),
+       [ID_LTC2633_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 2),
+       [ID_LTC2633_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 2),
+       [ID_LTC2633_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 2),
+       [ID_LTC2633_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 2),
+       [ID_LTC2633_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 2),
+       [ID_LTC2633_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 2),
+       [ID_LTC2635_L12] = LTC2631_INFO(2500000, ltc2631_12_channels, 4),
+       [ID_LTC2635_H12] = LTC2631_INFO(4096000, ltc2631_12_channels, 4),
+       [ID_LTC2635_L10] = LTC2631_INFO(2500000, ltc2631_10_channels, 4),
+       [ID_LTC2635_H10] = LTC2631_INFO(4096000, ltc2631_10_channels, 4),
+       [ID_LTC2635_L8] = LTC2631_INFO(2500000, ltc2631_8_channels, 4),
+       [ID_LTC2635_H8] = LTC2631_INFO(4096000, ltc2631_8_channels, 4),
 };
 
 static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
@@ -982,6 +1031,24 @@ static const struct i2c_device_id ad5064_i2c_ids[] = {
        {"ltc2626", ID_LTC2626},
        {"ltc2627", ID_LTC2627},
        {"ltc2629", ID_LTC2629},
+       {"ltc2631-l12", ID_LTC2631_L12},
+       {"ltc2631-h12", ID_LTC2631_H12},
+       {"ltc2631-l10", ID_LTC2631_L10},
+       {"ltc2631-h10", ID_LTC2631_H10},
+       {"ltc2631-l8", ID_LTC2631_L8},
+       {"ltc2631-h8", ID_LTC2631_H8},
+       {"ltc2633-l12", ID_LTC2633_L12},
+       {"ltc2633-h12", ID_LTC2633_H12},
+       {"ltc2633-l10", ID_LTC2633_L10},
+       {"ltc2633-h10", ID_LTC2633_H10},
+       {"ltc2633-l8", ID_LTC2633_L8},
+       {"ltc2633-h8", ID_LTC2633_H8},
+       {"ltc2635-l12", ID_LTC2635_L12},
+       {"ltc2635-h12", ID_LTC2635_H12},
+       {"ltc2635-l10", ID_LTC2635_L10},
+       {"ltc2635-h10", ID_LTC2635_H10},
+       {"ltc2635-l8", ID_LTC2635_L8},
+       {"ltc2635-h8", ID_LTC2635_H8},
        {}
 };
 MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
index c7154665512eed1a98ac76dccbc763b77ad260a3..94510266e0a51e5844a7ca25528e2b7a3564292a 100644 (file)
@@ -57,12 +57,15 @@ struct hts221_hw {
 
        struct hts221_sensor sensors[HTS221_SENSOR_MAX];
 
+       bool enabled;
        u8 odr;
 
        const struct hts221_transfer_function *tf;
        struct hts221_transfer_buffer tb;
 };
 
+extern const struct dev_pm_ops hts221_pm_ops;
+
 int hts221_config_drdy(struct hts221_hw *hw, bool enable);
 int hts221_probe(struct iio_dev *iio_dev);
 int hts221_power_on(struct hts221_hw *hw);
index 3f3ef4a1a4746b81a4cf5ab028db763ef1600a96..a56da3999e00a89b82001bb0a8c8aabb671e8ea2 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/iio/sysfs.h>
 #include <linux/delay.h>
+#include <linux/pm.h>
 #include <asm/unaligned.h>
 
 #include "hts221.h"
@@ -307,15 +308,30 @@ hts221_sysfs_temp_oversampling_avail(struct device *dev,
 
 int hts221_power_on(struct hts221_hw *hw)
 {
-       return hts221_update_odr(hw, hw->odr);
+       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)
 {
-       u8 data[] = {0x00, 0x00};
+       __le16 data = 0;
+       int err;
 
-       return hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
-                            data);
+       err = hw->tf->write(hw->dev, HTS221_REG_CNTRL1_ADDR, sizeof(data),
+                           (u8 *)&data);
+       if (err < 0)
+               return err;
+
+       hw->enabled = false;
+
+       return 0;
 }
 
 static int hts221_parse_temp_caldata(struct hts221_hw *hw)
@@ -682,6 +698,36 @@ int hts221_probe(struct iio_dev *iio_dev)
 }
 EXPORT_SYMBOL(hts221_probe);
 
+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);
+
+       return err < 0 ? err : 0;
+}
+
+static int __maybe_unused hts221_resume(struct device *dev)
+{
+       struct iio_dev *iio_dev = dev_get_drvdata(dev);
+       struct hts221_hw *hw = iio_priv(iio_dev);
+       int err = 0;
+
+       if (hw->enabled)
+               err = hts221_update_odr(hw, hw->odr);
+
+       return err;
+}
+
+const struct dev_pm_ops hts221_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(hts221_suspend, hts221_resume)
+};
+EXPORT_SYMBOL(hts221_pm_ops);
+
 MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics hts221 sensor driver");
 MODULE_LICENSE("GPL v2");
index 8333c0296c0e63fea93896dda8aa13b834cd9636..f38e4b7e0160746ee2bbe094c9dddb712a3834f1 100644 (file)
@@ -105,6 +105,7 @@ MODULE_DEVICE_TABLE(i2c, hts221_i2c_id_table);
 static struct i2c_driver hts221_driver = {
        .driver = {
                .name = "hts221_i2c",
+               .pm = &hts221_pm_ops,
                .of_match_table = of_match_ptr(hts221_i2c_of_match),
                .acpi_match_table = ACPI_PTR(hts221_acpi_match),
        },
index 70df5e7150c1b541d449a28864f37b8176af0a9c..57cbc256771bce39ebab42475b420f1ac535ce2f 100644 (file)
@@ -113,6 +113,7 @@ MODULE_DEVICE_TABLE(spi, hts221_spi_id_table);
 static struct spi_driver hts221_driver = {
        .driver = {
                .name = "hts221_spi",
+               .pm = &hts221_pm_ops,
                .of_match_table = of_match_ptr(hts221_spi_of_match),
        },
        .probe = hts221_spi_probe,
index 4839db7b9690ca60c365acb9a79ade5bbb2c242f..46352c7bff4309d7a5c4636cb7517e926a6d11fb 100644 (file)
@@ -135,6 +135,8 @@ struct st_lsm6dsx_hw {
 #endif /* CONFIG_SPI_MASTER */
 };
 
+extern const struct dev_pm_ops st_lsm6dsx_pm_ops;
+
 int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
                     const struct st_lsm6dsx_transfer_function *tf_ops);
 int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
@@ -144,5 +146,8 @@ int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
                               u8 val);
 int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
                                u16 watermark);
+int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
+                            enum st_lsm6dsx_fifo_mode fifo_mode);
 
 #endif /* ST_LSM6DSX_H */
index c8e5cfd0ef0bb8d81b413cb8bb0663bf0fdd897a..b19a62d8c884d326c834ba06b72037911d084a5c 100644 (file)
@@ -130,8 +130,8 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
        return 0;
 }
 
-static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
-                                   enum st_lsm6dsx_fifo_mode fifo_mode)
+int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
+                            enum st_lsm6dsx_fifo_mode fifo_mode)
 {
        u8 data;
        int err;
@@ -303,7 +303,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
        return read_len;
 }
 
-static int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
+int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
 {
        int err;
 
index 462a27b70453348c1a2599cbbfc25bbb3f3e0e76..b485540da89e3c9b8fb8541d6469851e277e68e3 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/delay.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/pm.h>
 
 #include <linux/platform_data/st_sensors_pdata.h>
 
@@ -731,6 +732,57 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
 }
 EXPORT_SYMBOL(st_lsm6dsx_probe);
 
+static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
+{
+       struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
+       struct st_lsm6dsx_sensor *sensor;
+       int i, err = 0;
+
+       for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               sensor = iio_priv(hw->iio_devs[i]);
+               if (!(hw->enable_mask & BIT(sensor->id)))
+                       continue;
+
+               err = st_lsm6dsx_write_with_mask(hw,
+                               st_lsm6dsx_odr_table[sensor->id].reg.addr,
+                               st_lsm6dsx_odr_table[sensor->id].reg.mask, 0);
+               if (err < 0)
+                       return err;
+       }
+
+       if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS)
+               err = st_lsm6dsx_flush_fifo(hw);
+
+       return err;
+}
+
+static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
+{
+       struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
+       struct st_lsm6dsx_sensor *sensor;
+       int i, err = 0;
+
+       for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+               sensor = iio_priv(hw->iio_devs[i]);
+               if (!(hw->enable_mask & BIT(sensor->id)))
+                       continue;
+
+               err = st_lsm6dsx_set_odr(sensor, sensor->odr);
+               if (err < 0)
+                       return err;
+       }
+
+       if (hw->enable_mask)
+               err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+
+       return err;
+}
+
+const struct dev_pm_ops st_lsm6dsx_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume)
+};
+EXPORT_SYMBOL(st_lsm6dsx_pm_ops);
+
 MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
 MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
 MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
index 09a51cfb9b5e4bc75d98e3110e197e47b730efdf..305fec712ab043669619a6a0bbcff692d1ca804e 100644 (file)
@@ -98,6 +98,7 @@ MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
 static struct i2c_driver st_lsm6dsx_driver = {
        .driver = {
                .name = "st_lsm6dsx_i2c",
+               .pm = &st_lsm6dsx_pm_ops,
                .of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
        },
        .probe = st_lsm6dsx_i2c_probe,
index f765a5058488ccbdf12b8f76eb0d814c0304eba9..95472f153ad2f181f2139a9a4f0f26a6f18e881c 100644 (file)
@@ -115,6 +115,7 @@ MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
 static struct spi_driver st_lsm6dsx_driver = {
        .driver = {
                .name = "st_lsm6dsx_spi",
+               .pm = &st_lsm6dsx_pm_ops,
                .of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
        },
        .probe = st_lsm6dsx_spi_probe,
index 57c14da5708fd5f5f1713689321e7dd5abb1d9e8..4a1de59d153aacedcd7e5519ebc241fe02c643f3 100644 (file)
@@ -1089,7 +1089,7 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
 {
        int i, ret, attrcount = 0;
 
-       for_each_set_bit(i, infomask, sizeof(infomask)*8) {
+       for_each_set_bit(i, infomask, sizeof(*infomask)*8) {
                if (i >= ARRAY_SIZE(iio_chan_info_postfix))
                        return -EINVAL;
                ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
@@ -1118,7 +1118,7 @@ static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
        int i, ret, attrcount = 0;
        char *avail_postfix;
 
-       for_each_set_bit(i, infomask, sizeof(infomask) * 8) {
+       for_each_set_bit(i, infomask, sizeof(*infomask) * 8) {
                avail_postfix = kasprintf(GFP_KERNEL,
                                          "%s_available",
                                          iio_chan_info_postfix[i]);
index 7a13535dc3e99b016c546f48a91009d458ea5b72..a3941bade6a7503c3aa60c00a97f814cf26ba632 100644 (file)
@@ -750,11 +750,9 @@ int iio_read_avail_channel_raw(struct iio_channel *chan,
 err_unlock:
        mutex_unlock(&chan->indio_dev->info_exist_lock);
 
-       if (ret >= 0 && type != IIO_VAL_INT) {
+       if (ret >= 0 && type != IIO_VAL_INT)
                /* raw values are assumed to be IIO_VAL_INT */
                ret = -EINVAL;
-               goto err_unlock;
-       }
 
        return ret;
 }
index 33e755d8d825cee5b9884e4d3f3a8cbcdce25825..2356ed9285df6c5796a114083f188b6a8c072267 100644 (file)
@@ -172,6 +172,16 @@ config SENSORS_ISL29018
         in lux, proximity infrared sensing and normal infrared sensing.
         Data from sensor is accessible via sysfs.
 
+config SENSORS_ISL29028
+       tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
+       depends on I2C
+       select REGMAP_I2C
+       help
+        Provides driver for the Intersil's ISL29028 device.
+        This driver supports the sysfs interface to get the ALS, IR intensity,
+        Proximity value via iio. The ISL29028 provides the concurrent sensing
+        of ambient light and proximity.
+
 config ISL29125
        tristate "Intersil ISL29125 digital color light sensor"
        depends on I2C
index 681363c2b2983daf80c1097bdbb0a68543315f55..fa32fa459e2e4164943141c4fc427c66e0283b67 100644 (file)
@@ -20,6 +20,7 @@ obj-$(CONFIG_GP2AP020A00F)    += gp2ap020a00f.o
 obj-$(CONFIG_HID_SENSOR_ALS)   += hid-sensor-als.o
 obj-$(CONFIG_HID_SENSOR_PROX)  += hid-sensor-prox.o
 obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
+obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
 obj-$(CONFIG_ISL29125)         += isl29125.o
 obj-$(CONFIG_JSA1212)          += jsa1212.o
 obj-$(CONFIG_SENSORS_LM3533)   += lm3533-als.o
index 917dd8b43e72d590d3d60a87403c17371ed3acb1..61f5924b472d9651e1f84c84156e3281be549fdb 100644 (file)
@@ -807,6 +807,7 @@ static SIMPLE_DEV_PM_OPS(isl29018_pm_ops, isl29018_suspend, isl29018_resume);
 #define ISL29018_PM_OPS NULL
 #endif
 
+#ifdef CONFIG_ACPI
 static const struct acpi_device_id isl29018_acpi_match[] = {
        {"ISL29018", isl29018},
        {"ISL29023", isl29023},
@@ -814,6 +815,7 @@ static const struct acpi_device_id isl29018_acpi_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(acpi, isl29018_acpi_match);
+#endif
 
 static const struct i2c_device_id isl29018_id[] = {
        {"isl29018", isl29018},
diff --git a/drivers/iio/light/isl29028.c b/drivers/iio/light/isl29028.c
new file mode 100644 (file)
index 0000000..3d09c1f
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * IIO driver for the light sensor ISL29028.
+ * ISL29028 is Concurrent Ambient Light and Proximity Sensor
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2016-2017 Brian Masney <masneyb@onstation.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Datasheets:
+ *  - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29028.pdf
+ *  - http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29030.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/pm_runtime.h>
+
+#define ISL29028_CONV_TIME_MS                  100
+
+#define ISL29028_REG_CONFIGURE                 0x01
+
+#define ISL29028_CONF_ALS_IR_MODE_ALS          0
+#define ISL29028_CONF_ALS_IR_MODE_IR           BIT(0)
+#define ISL29028_CONF_ALS_IR_MODE_MASK         BIT(0)
+
+#define ISL29028_CONF_ALS_RANGE_LOW_LUX                0
+#define ISL29028_CONF_ALS_RANGE_HIGH_LUX       BIT(1)
+#define ISL29028_CONF_ALS_RANGE_MASK           BIT(1)
+
+#define ISL29028_CONF_ALS_DIS                  0
+#define ISL29028_CONF_ALS_EN                   BIT(2)
+#define ISL29028_CONF_ALS_EN_MASK              BIT(2)
+
+#define ISL29028_CONF_PROX_SLP_SH              4
+#define ISL29028_CONF_PROX_SLP_MASK            (7 << ISL29028_CONF_PROX_SLP_SH)
+
+#define ISL29028_CONF_PROX_EN                  BIT(7)
+#define ISL29028_CONF_PROX_EN_MASK             BIT(7)
+
+#define ISL29028_REG_INTERRUPT                 0x02
+
+#define ISL29028_REG_PROX_DATA                 0x08
+#define ISL29028_REG_ALSIR_L                   0x09
+#define ISL29028_REG_ALSIR_U                   0x0A
+
+#define ISL29028_REG_TEST1_MODE                        0x0E
+#define ISL29028_REG_TEST2_MODE                        0x0F
+
+#define ISL29028_NUM_REGS                      (ISL29028_REG_TEST2_MODE + 1)
+
+#define ISL29028_POWER_OFF_DELAY_MS            2000
+
+struct isl29028_prox_data {
+       int sampling_int;
+       int sampling_fract;
+       int sleep_time;
+};
+
+static const struct isl29028_prox_data isl29028_prox_data[] = {
+       {   1, 250000, 800 },
+       {   2, 500000, 400 },
+       {   5,      0, 200 },
+       {  10,      0, 100 },
+       {  13, 300000,  75 },
+       {  20,      0,  50 },
+       {  80,      0,  13 }, /*
+                              * Note: Data sheet lists 12.5 ms sleep time.
+                              * Round up a half millisecond for msleep().
+                              */
+       { 100,  0,   0 }
+};
+
+enum isl29028_als_ir_mode {
+       ISL29028_MODE_NONE = 0,
+       ISL29028_MODE_ALS,
+       ISL29028_MODE_IR,
+};
+
+struct isl29028_chip {
+       struct mutex                    lock;
+       struct regmap                   *regmap;
+       int                             prox_sampling_int;
+       int                             prox_sampling_frac;
+       bool                            enable_prox;
+       int                             lux_scale;
+       enum isl29028_als_ir_mode       als_ir_mode;
+};
+
+static int isl29028_find_prox_sleep_index(int sampling_int, int sampling_fract)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(isl29028_prox_data); ++i) {
+               if (isl29028_prox_data[i].sampling_int == sampling_int &&
+                   isl29028_prox_data[i].sampling_fract == sampling_fract)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
+                                       int sampling_int, int sampling_fract)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       int sleep_index, ret;
+
+       sleep_index = isl29028_find_prox_sleep_index(sampling_int,
+                                                    sampling_fract);
+       if (sleep_index < 0)
+               return sleep_index;
+
+       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                ISL29028_CONF_PROX_SLP_MASK,
+                                sleep_index << ISL29028_CONF_PROX_SLP_SH);
+
+       if (ret < 0) {
+               dev_err(dev, "%s(): Error %d setting the proximity sampling\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       chip->prox_sampling_int = sampling_int;
+       chip->prox_sampling_frac = sampling_fract;
+
+       return ret;
+}
+
+static int isl29028_enable_proximity(struct isl29028_chip *chip)
+{
+       int prox_index, ret;
+
+       ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling_int,
+                                          chip->prox_sampling_frac);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                ISL29028_CONF_PROX_EN_MASK,
+                                ISL29028_CONF_PROX_EN);
+       if (ret < 0)
+               return ret;
+
+       /* Wait for conversion to be complete for first sample */
+       prox_index = isl29028_find_prox_sleep_index(chip->prox_sampling_int,
+                                                   chip->prox_sampling_frac);
+       if (prox_index < 0)
+               return prox_index;
+
+       msleep(isl29028_prox_data[prox_index].sleep_time);
+
+       return 0;
+}
+
+static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX :
+                                       ISL29028_CONF_ALS_RANGE_LOW_LUX;
+       int ret;
+
+       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                ISL29028_CONF_ALS_RANGE_MASK, val);
+       if (ret < 0) {
+               dev_err(dev, "%s(): Error %d setting the ALS scale\n", __func__,
+                       ret);
+               return ret;
+       }
+
+       chip->lux_scale = lux_scale;
+
+       return ret;
+}
+
+static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
+                                   enum isl29028_als_ir_mode mode)
+{
+       int ret;
+
+       if (chip->als_ir_mode == mode)
+               return 0;
+
+       ret = isl29028_set_als_scale(chip, chip->lux_scale);
+       if (ret < 0)
+               return ret;
+
+       switch (mode) {
+       case ISL29028_MODE_ALS:
+               ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                        ISL29028_CONF_ALS_IR_MODE_MASK,
+                                        ISL29028_CONF_ALS_IR_MODE_ALS);
+               if (ret < 0)
+                       return ret;
+
+               ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                        ISL29028_CONF_ALS_RANGE_MASK,
+                                        ISL29028_CONF_ALS_RANGE_HIGH_LUX);
+               break;
+       case ISL29028_MODE_IR:
+               ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                        ISL29028_CONF_ALS_IR_MODE_MASK,
+                                        ISL29028_CONF_ALS_IR_MODE_IR);
+               break;
+       case ISL29028_MODE_NONE:
+               return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                         ISL29028_CONF_ALS_EN_MASK,
+                                         ISL29028_CONF_ALS_DIS);
+       }
+
+       if (ret < 0)
+               return ret;
+
+       /* Enable the ALS/IR */
+       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+                                ISL29028_CONF_ALS_EN_MASK,
+                                ISL29028_CONF_ALS_EN);
+       if (ret < 0)
+               return ret;
+
+       /* Need to wait for conversion time if ALS/IR mode enabled */
+       msleep(ISL29028_CONV_TIME_MS);
+
+       chip->als_ir_mode = mode;
+
+       return 0;
+}
+
+static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       unsigned int lsb;
+       unsigned int msb;
+       int ret;
+
+       ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
+       if (ret < 0) {
+               dev_err(dev,
+                       "%s(): Error %d reading register ALSIR_L\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
+       if (ret < 0) {
+               dev_err(dev,
+                       "%s(): Error %d reading register ALSIR_U\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
+
+       return 0;
+}
+
+static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       unsigned int data;
+       int ret;
+
+       if (!chip->enable_prox) {
+               ret = isl29028_enable_proximity(chip);
+               if (ret < 0)
+                       return ret;
+
+               chip->enable_prox = true;
+       }
+
+       ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
+       if (ret < 0) {
+               dev_err(dev, "%s(): Error %d reading register PROX_DATA\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       *prox = data;
+
+       return 0;
+}
+
+static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       int ret;
+       int als_ir_data;
+
+       ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS);
+       if (ret < 0) {
+               dev_err(dev, "%s(): Error %d enabling ALS mode\n", __func__,
+                       ret);
+               return ret;
+       }
+
+       ret = isl29028_read_als_ir(chip, &als_ir_data);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * convert als data count to lux.
+        * if lux_scale = 125,  lux = count * 0.031
+        * if lux_scale = 2000, lux = count * 0.49
+        */
+       if (chip->lux_scale == 125)
+               als_ir_data = (als_ir_data * 31) / 1000;
+       else
+               als_ir_data = (als_ir_data * 49) / 100;
+
+       *als_data = als_ir_data;
+
+       return 0;
+}
+
+static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       int ret;
+
+       ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR);
+       if (ret < 0) {
+               dev_err(dev, "%s(): Error %d enabling IR mode\n", __func__,
+                       ret);
+               return ret;
+       }
+
+       return isl29028_read_als_ir(chip, ir_data);
+}
+
+static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       int ret;
+
+       if (on) {
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0)
+                       pm_runtime_put_noidle(dev);
+       } else {
+               pm_runtime_mark_last_busy(dev);
+               ret = pm_runtime_put_autosuspend(dev);
+       }
+
+       return ret;
+}
+
+/* Channel IO */
+static int isl29028_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long mask)
+{
+       struct isl29028_chip *chip = iio_priv(indio_dev);
+       struct device *dev = regmap_get_device(chip->regmap);
+       int ret;
+
+       ret = isl29028_set_pm_runtime_busy(chip, true);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = -EINVAL;
+       switch (chan->type) {
+       case IIO_PROXIMITY:
+               if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
+                       dev_err(dev,
+                               "%s(): proximity: Mask value 0x%08lx is not supported\n",
+                               __func__, mask);
+                       break;
+               }
+
+               if (val < 1 || val > 100) {
+                       dev_err(dev,
+                               "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n",
+                               __func__, val);
+                       break;
+               }
+
+               ret = isl29028_set_proxim_sampling(chip, val, val2);
+               break;
+       case IIO_LIGHT:
+               if (mask != IIO_CHAN_INFO_SCALE) {
+                       dev_err(dev,
+                               "%s(): light: Mask value 0x%08lx is not supported\n",
+                               __func__, mask);
+                       break;
+               }
+
+               if (val != 125 && val != 2000) {
+                       dev_err(dev,
+                               "%s(): light: Lux scale %d is not in the set {125, 2000}\n",
+                               __func__, val);
+                       break;
+               }
+
+               ret = isl29028_set_als_scale(chip, val);
+               break;
+       default:
+               dev_err(dev, "%s(): Unsupported channel type %x\n",
+                       __func__, chan->type);
+               break;
+       }
+
+       mutex_unlock(&chip->lock);
+
+       if (ret < 0)
+               return ret;
+
+       ret = isl29028_set_pm_runtime_busy(chip, false);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int isl29028_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val, int *val2, long mask)
+{
+       struct isl29028_chip *chip = iio_priv(indio_dev);
+       struct device *dev = regmap_get_device(chip->regmap);
+       int ret, pm_ret;
+
+       ret = isl29028_set_pm_runtime_busy(chip, true);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = -EINVAL;
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+       case IIO_CHAN_INFO_PROCESSED:
+               switch (chan->type) {
+               case IIO_LIGHT:
+                       ret = isl29028_als_get(chip, val);
+                       break;
+               case IIO_INTENSITY:
+                       ret = isl29028_ir_get(chip, val);
+                       break;
+               case IIO_PROXIMITY:
+                       ret = isl29028_read_proxim(chip, val);
+                       break;
+               default:
+                       break;
+               }
+
+               if (ret < 0)
+                       break;
+
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (chan->type != IIO_PROXIMITY)
+                       break;
+
+               *val = chip->prox_sampling_int;
+               *val2 = chip->prox_sampling_frac;
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_SCALE:
+               if (chan->type != IIO_LIGHT)
+                       break;
+               *val = chip->lux_scale;
+               ret = IIO_VAL_INT;
+               break;
+       default:
+               dev_err(dev, "%s(): mask value 0x%08lx is not supported\n",
+                       __func__, mask);
+               break;
+       }
+
+       mutex_unlock(&chip->lock);
+
+       if (ret < 0)
+               return ret;
+
+       /**
+        * Preserve the ret variable if the call to
+        * isl29028_set_pm_runtime_busy() is successful so the reading
+        * (if applicable) is returned to user space.
+        */
+       pm_ret = isl29028_set_pm_runtime_busy(chip, false);
+       if (pm_ret < 0)
+               return pm_ret;
+
+       return ret;
+}
+
+static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
+                               "1.25 2.5 5 10 13.3 20 80 100");
+static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000");
+
+#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
+static struct attribute *isl29028_attributes[] = {
+       ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
+       ISL29028_CONST_ATTR(in_illuminance_scale_available),
+       NULL,
+};
+
+static const struct attribute_group isl29108_group = {
+       .attrs = isl29028_attributes,
+};
+
+static const struct iio_chan_spec isl29028_channels[] = {
+       {
+               .type = IIO_LIGHT,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+               BIT(IIO_CHAN_INFO_SCALE),
+       }, {
+               .type = IIO_INTENSITY,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+       }, {
+               .type = IIO_PROXIMITY,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+               BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       }
+};
+
+static const struct iio_info isl29028_info = {
+       .attrs = &isl29108_group,
+       .driver_module = THIS_MODULE,
+       .read_raw = isl29028_read_raw,
+       .write_raw = isl29028_write_raw,
+};
+
+static int isl29028_clear_configure_reg(struct isl29028_chip *chip)
+{
+       struct device *dev = regmap_get_device(chip->regmap);
+       int ret;
+
+       ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
+       if (ret < 0)
+               dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n",
+                       __func__, ret);
+
+       chip->als_ir_mode = ISL29028_MODE_NONE;
+       chip->enable_prox = false;
+
+       return ret;
+}
+
+static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case ISL29028_REG_INTERRUPT:
+       case ISL29028_REG_PROX_DATA:
+       case ISL29028_REG_ALSIR_L:
+       case ISL29028_REG_ALSIR_U:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config isl29028_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .volatile_reg = isl29028_is_volatile_reg,
+       .max_register = ISL29028_NUM_REGS - 1,
+       .num_reg_defaults_raw = ISL29028_NUM_REGS,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static int isl29028_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct isl29028_chip *chip;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       chip = iio_priv(indio_dev);
+
+       i2c_set_clientdata(client, indio_dev);
+       mutex_init(&chip->lock);
+
+       chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
+       if (IS_ERR(chip->regmap)) {
+               ret = PTR_ERR(chip->regmap);
+               dev_err(&client->dev, "%s: Error %d initializing regmap\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       chip->enable_prox  = false;
+       chip->prox_sampling_int = 20;
+       chip->prox_sampling_frac = 0;
+       chip->lux_scale = 2000;
+
+       ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "%s(): Error %d writing to TEST1_MODE register\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "%s(): Error %d writing to TEST2_MODE register\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       ret = isl29028_clear_configure_reg(chip);
+       if (ret < 0)
+               return ret;
+
+       indio_dev->info = &isl29028_info;
+       indio_dev->channels = isl29028_channels;
+       indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
+       indio_dev->name = id->name;
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev,
+                                        ISL29028_POWER_OFF_DELAY_MS);
+       pm_runtime_use_autosuspend(&client->dev);
+
+       ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "%s(): iio registration failed with error %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int isl29028_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct isl29028_chip *chip = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
+
+       return isl29028_clear_configure_reg(chip);
+}
+
+static int __maybe_unused isl29028_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct isl29028_chip *chip = iio_priv(indio_dev);
+       int ret;
+
+       mutex_lock(&chip->lock);
+
+       ret = isl29028_clear_configure_reg(chip);
+
+       mutex_unlock(&chip->lock);
+
+       return ret;
+}
+
+static int __maybe_unused isl29028_resume(struct device *dev)
+{
+       /**
+        * The specific component (ALS/IR or proximity) will enable itself as
+        * needed the next time that the user requests a reading. This is done
+        * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity().
+        */
+       return 0;
+}
+
+static const struct dev_pm_ops isl29028_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL)
+};
+
+static const struct i2c_device_id isl29028_id[] = {
+       {"isl29028", 0},
+       {"isl29030", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29028_id);
+
+static const struct of_device_id isl29028_of_match[] = {
+       { .compatible = "isl,isl29028", }, /* for backward compat., don't use */
+       { .compatible = "isil,isl29028", },
+       { .compatible = "isil,isl29030", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, isl29028_of_match);
+
+static struct i2c_driver isl29028_driver = {
+       .driver  = {
+               .name = "isl29028",
+               .pm = &isl29028_pm_ops,
+               .of_match_table = isl29028_of_match,
+       },
+       .probe   = isl29028_probe,
+       .remove  = isl29028_remove,
+       .id_table = isl29028_id,
+};
+
+module_i2c_driver(isl29028_driver);
+
+MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
index 7de0f397194b0b858bfe229cb88d47a45d87b979..9d0c2e859bb2935a81966d4fadd9c6b94f194f32 100644 (file)
@@ -9,7 +9,7 @@
  *
  * IIO driver for RPR-0521RS (7-bit I2C slave address 0x38).
  *
- * TODO: illuminance channel, PM support, buffer
+ * TODO: illuminance channel, buffer
  */
 
 #include <linux/module.h>
@@ -30,6 +30,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_PS_OFFSET_LSB      0x53
 #define RPR0521_REG_ID                 0x92
 
 #define RPR0521_MODE_ALS_MASK          BIT(7)
@@ -77,9 +78,9 @@ static const struct rpr0521_gain rpr0521_pxs_gain[3] = {
 };
 
 enum rpr0521_channel {
+       RPR0521_CHAN_PXS,
        RPR0521_CHAN_ALS_DATA0,
        RPR0521_CHAN_ALS_DATA1,
-       RPR0521_CHAN_PXS,
 };
 
 struct rpr0521_reg_desc {
@@ -88,6 +89,10 @@ struct rpr0521_reg_desc {
 };
 
 static const struct rpr0521_reg_desc rpr0521_data_reg[] = {
+       [RPR0521_CHAN_PXS]      = {
+               .address        = RPR0521_REG_PXS_DATA,
+               .device_mask    = RPR0521_MODE_PXS_MASK,
+       },
        [RPR0521_CHAN_ALS_DATA0] = {
                .address        = RPR0521_REG_ALS_DATA0,
                .device_mask    = RPR0521_MODE_ALS_MASK,
@@ -96,10 +101,6 @@ static const struct rpr0521_reg_desc rpr0521_data_reg[] = {
                .address        = RPR0521_REG_ALS_DATA1,
                .device_mask    = RPR0521_MODE_ALS_MASK,
        },
-       [RPR0521_CHAN_PXS]      = {
-               .address        = RPR0521_REG_PXS_DATA,
-               .device_mask    = RPR0521_MODE_PXS_MASK,
-       },
 };
 
 static const struct rpr0521_gain_info {
@@ -109,6 +110,13 @@ static const struct rpr0521_gain_info {
        const struct rpr0521_gain *gain;
        int size;
 } rpr0521_gain[] = {
+       [RPR0521_CHAN_PXS] = {
+               .reg    = RPR0521_REG_PXS_CTRL,
+               .mask   = RPR0521_PXS_GAIN_MASK,
+               .shift  = RPR0521_PXS_GAIN_SHIFT,
+               .gain   = rpr0521_pxs_gain,
+               .size   = ARRAY_SIZE(rpr0521_pxs_gain),
+       },
        [RPR0521_CHAN_ALS_DATA0] = {
                .reg    = RPR0521_REG_ALS_CTRL,
                .mask   = RPR0521_ALS_DATA0_GAIN_MASK,
@@ -123,13 +131,30 @@ static const struct rpr0521_gain_info {
                .gain   = rpr0521_als_gain,
                .size   = ARRAY_SIZE(rpr0521_als_gain),
        },
-       [RPR0521_CHAN_PXS] = {
-               .reg    = RPR0521_REG_PXS_CTRL,
-               .mask   = RPR0521_PXS_GAIN_MASK,
-               .shift  = RPR0521_PXS_GAIN_SHIFT,
-               .gain   = rpr0521_pxs_gain,
-               .size   = ARRAY_SIZE(rpr0521_pxs_gain),
-       },
+};
+
+struct rpr0521_samp_freq {
+       int     als_hz;
+       int     als_uhz;
+       int     pxs_hz;
+       int     pxs_uhz;
+};
+
+static const struct rpr0521_samp_freq rpr0521_samp_freq_i[13] = {
+/*     {ALS, PXS},                W==currently writable option */
+       {0, 0, 0, 0},           /* W0000, 0=standby */
+       {0, 0, 100, 0},         /*  0001 */
+       {0, 0, 25, 0},          /*  0010 */
+       {0, 0, 10, 0},          /*  0011 */
+       {0, 0, 2, 500000},      /*  0100 */
+       {10, 0, 20, 0},         /*  0101 */
+       {10, 0, 10, 0},         /* W0110 */
+       {10, 0, 2, 500000},     /*  0111 */
+       {2, 500000, 20, 0},     /*  1000, measurement 100ms, sleep 300ms */
+       {2, 500000, 10, 0},     /*  1001, measurement 100ms, sleep 300ms */
+       {2, 500000, 0, 0},      /*  1010, high sensitivity mode */
+       {2, 500000, 2, 500000}, /* W1011, high sensitivity mode */
+       {20, 0, 20, 0}  /* 1100, ALS_data x 0.5, see specification P.18 */
 };
 
 struct rpr0521_data {
@@ -142,9 +167,11 @@ struct rpr0521_data {
        bool als_dev_en;
        bool pxs_dev_en;
 
-       /* optimize runtime pm ops - enable device only if needed */
+       /* optimize runtime pm ops - enable/disable device only if needed */
        bool als_ps_need_en;
        bool pxs_ps_need_en;
+       bool als_need_dis;
+       bool pxs_need_dis;
 
        struct regmap *regmap;
 };
@@ -152,9 +179,16 @@ struct rpr0521_data {
 static IIO_CONST_ATTR(in_intensity_scale_available, RPR0521_ALS_SCALE_AVAIL);
 static IIO_CONST_ATTR(in_proximity_scale_available, RPR0521_PXS_SCALE_AVAIL);
 
+/*
+ * Start with easy freq first, whole table of freq combinations is more
+ * complicated.
+ */
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("2.5 10");
+
 static struct attribute *rpr0521_attributes[] = {
        &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
        &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
        NULL,
 };
 
@@ -163,6 +197,14 @@ static const struct attribute_group rpr0521_attribute_group = {
 };
 
 static const struct iio_chan_spec rpr0521_channels[] = {
+       {
+               .type = IIO_PROXIMITY,
+               .address = RPR0521_CHAN_PXS,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                       BIT(IIO_CHAN_INFO_OFFSET) |
+                       BIT(IIO_CHAN_INFO_SCALE),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       },
        {
                .type = IIO_INTENSITY,
                .modified = 1,
@@ -170,6 +212,7 @@ static const struct iio_chan_spec rpr0521_channels[] = {
                .channel2 = IIO_MOD_LIGHT_BOTH,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                        BIT(IIO_CHAN_INFO_SCALE),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
        {
                .type = IIO_INTENSITY,
@@ -178,13 +221,8 @@ static const struct iio_chan_spec rpr0521_channels[] = {
                .channel2 = IIO_MOD_LIGHT_IR,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                        BIT(IIO_CHAN_INFO_SCALE),
+               .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
-       {
-               .type = IIO_PROXIMITY,
-               .address = RPR0521_CHAN_PXS,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                       BIT(IIO_CHAN_INFO_SCALE),
-       }
 };
 
 static int rpr0521_als_enable(struct rpr0521_data *data, u8 status)
@@ -197,7 +235,10 @@ static int rpr0521_als_enable(struct rpr0521_data *data, u8 status)
        if (ret < 0)
                return ret;
 
-       data->als_dev_en = true;
+       if (status & RPR0521_MODE_ALS_MASK)
+               data->als_dev_en = true;
+       else
+               data->als_dev_en = false;
 
        return 0;
 }
@@ -212,7 +253,10 @@ static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status)
        if (ret < 0)
                return ret;
 
-       data->pxs_dev_en = true;
+       if (status & RPR0521_MODE_PXS_MASK)
+               data->pxs_dev_en = true;
+       else
+               data->pxs_dev_en = false;
 
        return 0;
 }
@@ -224,40 +268,32 @@ static int rpr0521_pxs_enable(struct rpr0521_data *data, u8 status)
  * @on: state to be set for devices in @device_mask
  * @device_mask: bitmask specifying for which device we need to update @on state
  *
- * We rely on rpr0521_runtime_resume to enable our @device_mask devices, but
- * if (for example) PXS was enabled (pxs_dev_en = true) by a previous call to
- * rpr0521_runtime_resume and we want to enable ALS we MUST set ALS enable
- * bit of RPR0521_REG_MODE_CTRL here because rpr0521_runtime_resume will not
- * be called twice.
+ * Calls for this function must be balanced so that each ON should have matching
+ * OFF. Otherwise pm usage_count gets out of sync.
  */
 static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
                                   u8 device_mask)
 {
 #ifdef CONFIG_PM
        int ret;
-       u8 update_mask = 0;
 
        if (device_mask & RPR0521_MODE_ALS_MASK) {
-               if (on && !data->als_ps_need_en && data->pxs_dev_en)
-                       update_mask |= RPR0521_MODE_ALS_MASK;
-               else
-                       data->als_ps_need_en = on;
+               data->als_ps_need_en = on;
+               data->als_need_dis = !on;
        }
 
        if (device_mask & RPR0521_MODE_PXS_MASK) {
-               if (on && !data->pxs_ps_need_en && data->als_dev_en)
-                       update_mask |= RPR0521_MODE_PXS_MASK;
-               else
-                       data->pxs_ps_need_en = on;
-       }
-
-       if (update_mask) {
-               ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
-                                        update_mask, update_mask);
-               if (ret < 0)
-                       return ret;
+               data->pxs_ps_need_en = on;
+               data->pxs_need_dis = !on;
        }
 
+       /*
+        * On: _resume() is called only when we are suspended
+        * Off: _suspend() is called after delay if _resume() is not
+        * called before that.
+        * Note: If either measurement is re-enabled before _suspend(),
+        * both stay enabled until _suspend().
+        */
        if (on) {
                ret = pm_runtime_get_sync(&data->client->dev);
        } else {
@@ -273,6 +309,23 @@ static int rpr0521_set_power_state(struct rpr0521_data *data, bool on,
 
                return ret;
        }
+
+       if (on) {
+               /* If _resume() was not called, enable measurement now. */
+               if (data->als_ps_need_en) {
+                       ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
+                       if (ret)
+                               return ret;
+                       data->als_ps_need_en = false;
+               }
+
+               if (data->pxs_ps_need_en) {
+                       ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
+                       if (ret)
+                               return ret;
+                       data->pxs_ps_need_en = false;
+               }
+       }
 #endif
        return 0;
 }
@@ -314,6 +367,106 @@ static int rpr0521_set_gain(struct rpr0521_data *data, int chan,
                                  idx << rpr0521_gain[chan].shift);
 }
 
+static int rpr0521_read_samp_freq(struct rpr0521_data *data,
+                               enum iio_chan_type chan_type,
+                           int *val, int *val2)
+{
+       int reg, ret;
+
+       ret = regmap_read(data->regmap, RPR0521_REG_MODE_CTRL, &reg);
+       if (ret < 0)
+               return ret;
+
+       reg &= RPR0521_MODE_MEAS_TIME_MASK;
+       if (reg >= ARRAY_SIZE(rpr0521_samp_freq_i))
+               return -EINVAL;
+
+       switch (chan_type) {
+       case IIO_INTENSITY:
+               *val = rpr0521_samp_freq_i[reg].als_hz;
+               *val2 = rpr0521_samp_freq_i[reg].als_uhz;
+               return 0;
+
+       case IIO_PROXIMITY:
+               *val = rpr0521_samp_freq_i[reg].pxs_hz;
+               *val2 = rpr0521_samp_freq_i[reg].pxs_uhz;
+               return 0;
+
+       default:
+               return -EINVAL;
+       }
+}
+
+static int rpr0521_write_samp_freq_common(struct rpr0521_data *data,
+                               enum iio_chan_type chan_type,
+                               int val, int val2)
+{
+       int i;
+
+       /*
+        * Ignore channel
+        * both pxs and als are setup only to same freq because of simplicity
+        */
+       switch (val) {
+       case 0:
+               i = 0;
+               break;
+
+       case 2:
+               if (val2 != 500000)
+                       return -EINVAL;
+
+               i = 11;
+               break;
+
+       case 10:
+               i = 6;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return regmap_update_bits(data->regmap,
+               RPR0521_REG_MODE_CTRL,
+               RPR0521_MODE_MEAS_TIME_MASK,
+               i);
+}
+
+static int rpr0521_read_ps_offset(struct rpr0521_data *data, int *offset)
+{
+       int ret;
+       __le16 buffer;
+
+       ret = regmap_bulk_read(data->regmap,
+               RPR0521_REG_PS_OFFSET_LSB, &buffer, sizeof(buffer));
+
+       if (ret < 0) {
+               dev_err(&data->client->dev, "Failed to read PS OFFSET register\n");
+               return ret;
+       }
+       *offset = le16_to_cpu(buffer);
+
+       return ret;
+}
+
+static int rpr0521_write_ps_offset(struct rpr0521_data *data, int offset)
+{
+       int ret;
+       __le16 buffer;
+
+       buffer = cpu_to_le16(offset & 0x3ff);
+       ret = regmap_raw_write(data->regmap,
+               RPR0521_REG_PS_OFFSET_LSB, &buffer, sizeof(buffer));
+
+       if (ret < 0) {
+               dev_err(&data->client->dev, "Failed to write PS OFFSET register\n");
+               return ret;
+       }
+
+       return ret;
+}
+
 static int rpr0521_read_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan, int *val,
                            int *val2, long mask)
@@ -339,7 +492,7 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev,
 
                ret = regmap_bulk_read(data->regmap,
                                       rpr0521_data_reg[chan->address].address,
-                                      &raw_data, 2);
+                                      &raw_data, sizeof(raw_data));
                if (ret < 0) {
                        rpr0521_set_power_state(data, false, device_mask);
                        mutex_unlock(&data->lock);
@@ -354,6 +507,7 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev,
                *val = le16_to_cpu(raw_data);
 
                return IIO_VAL_INT;
+
        case IIO_CHAN_INFO_SCALE:
                mutex_lock(&data->lock);
                ret = rpr0521_get_gain(data, chan->address, val, val2);
@@ -362,6 +516,25 @@ static int rpr0521_read_raw(struct iio_dev *indio_dev,
                        return ret;
 
                return IIO_VAL_INT_PLUS_MICRO;
+
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               mutex_lock(&data->lock);
+               ret = rpr0521_read_samp_freq(data, chan->type, val, val2);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       return ret;
+
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       case IIO_CHAN_INFO_OFFSET:
+               mutex_lock(&data->lock);
+               ret = rpr0521_read_ps_offset(data, val);
+               mutex_unlock(&data->lock);
+               if (ret < 0)
+                       return ret;
+
+               return IIO_VAL_INT;
+
        default:
                return -EINVAL;
        }
@@ -381,6 +554,22 @@ static int rpr0521_write_raw(struct iio_dev *indio_dev,
                mutex_unlock(&data->lock);
 
                return ret;
+
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               mutex_lock(&data->lock);
+               ret = rpr0521_write_samp_freq_common(data, chan->type,
+                                                    val, val2);
+               mutex_unlock(&data->lock);
+
+               return ret;
+
+       case IIO_CHAN_INFO_OFFSET:
+               mutex_lock(&data->lock);
+               ret = rpr0521_write_ps_offset(data, val);
+               mutex_unlock(&data->lock);
+
+               return ret;
+
        default:
                return -EINVAL;
        }
@@ -419,12 +608,14 @@ static int rpr0521_init(struct rpr0521_data *data)
                return ret;
        }
 
+#ifndef CONFIG_PM
        ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
        if (ret < 0)
                return ret;
        ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE);
        if (ret < 0)
                return ret;
+#endif
 
        return 0;
 }
@@ -510,13 +701,26 @@ static int rpr0521_probe(struct i2c_client *client,
 
        ret = pm_runtime_set_active(&client->dev);
        if (ret < 0)
-               return ret;
+               goto err_poweroff;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
-       return iio_device_register(indio_dev);
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto err_pm_disable;
+
+       return 0;
+
+err_pm_disable:
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
+err_poweroff:
+       rpr0521_poweroff(data);
+
+       return ret;
 }
 
 static int rpr0521_remove(struct i2c_client *client)
@@ -541,9 +745,16 @@ static int rpr0521_runtime_suspend(struct device *dev)
        struct rpr0521_data *data = iio_priv(indio_dev);
        int ret;
 
-       /* disable channels and sets {als,pxs}_dev_en to false */
        mutex_lock(&data->lock);
+       /* If measurements are enabled, enable them on resume */
+       if (!data->als_need_dis)
+               data->als_ps_need_en = data->als_dev_en;
+       if (!data->pxs_need_dis)
+               data->pxs_ps_need_en = data->pxs_dev_en;
+
+       /* disable channels and sets {als,pxs}_dev_en to false */
        ret = rpr0521_poweroff(data);
+       regcache_mark_dirty(data->regmap);
        mutex_unlock(&data->lock);
 
        return ret;
@@ -555,6 +766,7 @@ static int rpr0521_runtime_resume(struct device *dev)
        struct rpr0521_data *data = iio_priv(indio_dev);
        int ret;
 
+       regcache_sync(data->regmap);
        if (data->als_ps_need_en) {
                ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE);
                if (ret < 0)
@@ -568,6 +780,7 @@ static int rpr0521_runtime_resume(struct device *dev)
                        return ret;
                data->pxs_ps_need_en = false;
        }
+       msleep(100);    //wait for first measurement result
 
        return 0;
 }
index a78b6025c465217d78e0bfdde930b35418ffbc0e..1679181d2bdd2ff8c87edb3f6389e51f7f0569c3 100644 (file)
@@ -3,7 +3,7 @@
  * within the TAOS tsl258x family of devices (tsl2580, tsl2581, tsl2583).
  *
  * Copyright (c) 2011, TAOS Corporation.
- * Copyright (c) 2016 Brian Masney <masneyb@onstation.org>
+ * Copyright (c) 2016-2017 Brian Masney <masneyb@onstation.org>
  *
  * 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
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/pm_runtime.h>
 
 /* Device Registers and Masks */
 #define TSL2583_CNTRL                  0x00
@@ -64,6 +65,8 @@
 #define TSL2583_CHIP_ID                        0x90
 #define TSL2583_CHIP_ID_MASK           0xf0
 
+#define TSL2583_POWER_OFF_DELAY_MS     2000
+
 /* Per-device data */
 struct tsl2583_als_info {
        u16 als_ch0;
@@ -108,7 +111,6 @@ struct tsl2583_chip {
        struct tsl2583_settings als_settings;
        int als_time_scale;
        int als_saturation;
-       bool suspended;
 };
 
 struct gainadj {
@@ -460,8 +462,6 @@ static int tsl2583_chip_init_and_power_on(struct iio_dev *indio_dev)
        if (ret < 0)
                return ret;
 
-       chip->suspended = false;
-
        return ret;
 }
 
@@ -513,11 +513,6 @@ static ssize_t in_illuminance_calibrate_store(struct device *dev,
 
        mutex_lock(&chip->als_mutex);
 
-       if (chip->suspended) {
-               ret = -EBUSY;
-               goto done;
-       }
-
        ret = tsl2583_als_calibrate(indio_dev);
        if (ret < 0)
                goto done;
@@ -645,20 +640,36 @@ static const struct iio_chan_spec tsl2583_channels[] = {
        },
 };
 
+static int tsl2583_set_pm_runtime_busy(struct tsl2583_chip *chip, bool on)
+{
+       int ret;
+
+       if (on) {
+               ret = pm_runtime_get_sync(&chip->client->dev);
+               if (ret < 0)
+                       pm_runtime_put_noidle(&chip->client->dev);
+       } else {
+               pm_runtime_mark_last_busy(&chip->client->dev);
+               ret = pm_runtime_put_autosuspend(&chip->client->dev);
+       }
+
+       return ret;
+}
+
 static int tsl2583_read_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int *val, int *val2, long mask)
 {
        struct tsl2583_chip *chip = iio_priv(indio_dev);
-       int ret = -EINVAL;
+       int ret, pm_ret;
 
-       mutex_lock(&chip->als_mutex);
+       ret = tsl2583_set_pm_runtime_busy(chip, true);
+       if (ret < 0)
+               return ret;
 
-       if (chip->suspended) {
-               ret = -EBUSY;
-               goto read_done;
-       }
+       mutex_lock(&chip->als_mutex);
 
+       ret = -EINVAL;
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
                if (chan->type == IIO_LIGHT) {
@@ -719,6 +730,18 @@ static int tsl2583_read_raw(struct iio_dev *indio_dev,
 read_done:
        mutex_unlock(&chip->als_mutex);
 
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Preserve the ret variable if the call to
+        * tsl2583_set_pm_runtime_busy() is successful so the reading
+        * (if applicable) is returned to user space.
+        */
+       pm_ret = tsl2583_set_pm_runtime_busy(chip, false);
+       if (pm_ret < 0)
+               return pm_ret;
+
        return ret;
 }
 
@@ -727,15 +750,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
                             int val, int val2, long mask)
 {
        struct tsl2583_chip *chip = iio_priv(indio_dev);
-       int ret = -EINVAL;
+       int ret;
 
-       mutex_lock(&chip->als_mutex);
+       ret = tsl2583_set_pm_runtime_busy(chip, true);
+       if (ret < 0)
+               return ret;
 
-       if (chip->suspended) {
-               ret = -EBUSY;
-               goto write_done;
-       }
+       mutex_lock(&chip->als_mutex);
 
+       ret = -EINVAL;
        switch (mask) {
        case IIO_CHAN_INFO_CALIBBIAS:
                if (chan->type == IIO_LIGHT) {
@@ -767,9 +790,15 @@ static int tsl2583_write_raw(struct iio_dev *indio_dev,
                break;
        }
 
-write_done:
        mutex_unlock(&chip->als_mutex);
 
+       if (ret < 0)
+               return ret;
+
+       ret = tsl2583_set_pm_runtime_busy(chip, false);
+       if (ret < 0)
+               return ret;
+
        return ret;
 }
 
@@ -803,7 +832,6 @@ static int tsl2583_probe(struct i2c_client *clientp,
        i2c_set_clientdata(clientp, indio_dev);
 
        mutex_init(&chip->als_mutex);
-       chip->suspended = true;
 
        ret = i2c_smbus_read_byte_data(clientp,
                                       TSL2583_CMD_REG | TSL2583_CHIPID);
@@ -826,6 +854,11 @@ static int tsl2583_probe(struct i2c_client *clientp,
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->name = chip->client->name;
 
+       pm_runtime_enable(&clientp->dev);
+       pm_runtime_set_autosuspend_delay(&clientp->dev,
+                                        TSL2583_POWER_OFF_DELAY_MS);
+       pm_runtime_use_autosuspend(&clientp->dev);
+
        ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
        if (ret) {
                dev_err(&clientp->dev, "%s: iio registration failed\n",
@@ -836,16 +869,25 @@ static int tsl2583_probe(struct i2c_client *clientp,
        /* Load up the V2 defaults (these are hard coded defaults for now) */
        tsl2583_defaults(chip);
 
-       /* Make sure the chip is on */
-       ret = tsl2583_chip_init_and_power_on(indio_dev);
-       if (ret < 0)
-               return ret;
-
        dev_info(&clientp->dev, "Light sensor found.\n");
 
        return 0;
 }
 
+static int tsl2583_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct tsl2583_chip *chip = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+       pm_runtime_put_noidle(&client->dev);
+
+       return tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF);
+}
+
 static int __maybe_unused tsl2583_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
@@ -855,7 +897,6 @@ static int __maybe_unused tsl2583_suspend(struct device *dev)
        mutex_lock(&chip->als_mutex);
 
        ret = tsl2583_set_power_state(chip, TSL2583_CNTL_PWR_OFF);
-       chip->suspended = true;
 
        mutex_unlock(&chip->als_mutex);
 
@@ -877,7 +918,11 @@ static int __maybe_unused tsl2583_resume(struct device *dev)
        return ret;
 }
 
-static SIMPLE_DEV_PM_OPS(tsl2583_pm_ops, tsl2583_suspend, tsl2583_resume);
+static const struct dev_pm_ops tsl2583_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(tsl2583_suspend, tsl2583_resume, NULL)
+};
 
 static struct i2c_device_id tsl2583_idtable[] = {
        { "tsl2580", 0 },
@@ -904,6 +949,7 @@ static struct i2c_driver tsl2583_driver = {
        },
        .id_table = tsl2583_idtable,
        .probe = tsl2583_probe,
+       .remove = tsl2583_remove,
 };
 module_i2c_driver(tsl2583_driver);
 
index a97e802ca523138227e9930a585357fd2f873e94..e9fa86c87db5c0e3cd64354495c1ec3d7b1ea774 100644 (file)
@@ -31,6 +31,10 @@ struct dev_rot_state {
        struct hid_sensor_common common_attributes;
        struct hid_sensor_hub_attribute_info quaternion;
        u32 sampled_vals[4];
+       int scale_pre_decml;
+       int scale_post_decml;
+       int scale_precision;
+       int value_offset;
 };
 
 /* Channel definitions */
@@ -41,6 +45,8 @@ static const struct iio_chan_spec dev_rot_channels[] = {
                .channel2 = IIO_MOD_QUATERNION,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
                .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+                                       BIT(IIO_CHAN_INFO_OFFSET) |
+                                       BIT(IIO_CHAN_INFO_SCALE) |
                                        BIT(IIO_CHAN_INFO_HYSTERESIS)
        }
 };
@@ -80,6 +86,15 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
                } else
                        ret_type = -EINVAL;
                break;
+       case IIO_CHAN_INFO_SCALE:
+               vals[0] = rot_state->scale_pre_decml;
+               vals[1] = rot_state->scale_post_decml;
+               return rot_state->scale_precision;
+
+       case IIO_CHAN_INFO_OFFSET:
+               *vals = rot_state->value_offset;
+               return IIO_VAL_INT;
+
        case IIO_CHAN_INFO_SAMP_FREQ:
                ret_type = hid_sensor_read_samp_freq_value(
                        &rot_state->common_attributes, &vals[0], &vals[1]);
@@ -199,6 +214,11 @@ static int dev_rot_parse_report(struct platform_device *pdev,
        dev_dbg(&pdev->dev, "dev_rot: attrib size %d\n",
                                st->quaternion.size);
 
+       st->scale_precision = hid_sensor_format_scale(
+                               hsdev->usage,
+                               &st->quaternion,
+                               &st->scale_pre_decml, &st->scale_post_decml);
+
        /* Set Sensitivity field ids, when there is no individual modifier */
        if (st->common_attributes.sensitivity.index < 0) {
                sensor_hub_input_get_attribute_info(hsdev,
@@ -218,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 = "dev_rotation";
+       static char *name;
        struct iio_dev *indio_dev;
        struct dev_rot_state *rot_state;
        struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
@@ -234,8 +254,21 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
        rot_state->common_attributes.hsdev = hsdev;
        rot_state->common_attributes.pdev = pdev;
 
-       ret = hid_sensor_parse_common_attributes(hsdev,
-                               HID_USAGE_SENSOR_DEVICE_ORIENTATION,
+       switch (hsdev->usage) {
+       case HID_USAGE_SENSOR_DEVICE_ORIENTATION:
+               name = "dev_rotation";
+               break;
+       case HID_USAGE_SENSOR_RELATIVE_ORIENTATION:
+               name = "relative_orientation";
+               break;
+       case HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION:
+               name = "geomagnetic_orientation";
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
                                &rot_state->common_attributes);
        if (ret) {
                dev_err(&pdev->dev, "failed to setup common attributes\n");
@@ -252,8 +285,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
 
        ret = dev_rot_parse_report(pdev, hsdev,
                                   (struct iio_chan_spec *)indio_dev->channels,
-                                  HID_USAGE_SENSOR_DEVICE_ORIENTATION,
-                                  rot_state);
+                                       hsdev->usage, rot_state);
        if (ret) {
                dev_err(&pdev->dev, "failed to setup attributes\n");
                return ret;
@@ -288,8 +320,7 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
        rot_state->callbacks.send_event = dev_rot_proc_event;
        rot_state->callbacks.capture_sample = dev_rot_capture_sample;
        rot_state->callbacks.pdev = pdev;
-       ret = sensor_hub_register_callback(hsdev,
-                                       HID_USAGE_SENSOR_DEVICE_ORIENTATION,
+       ret = sensor_hub_register_callback(hsdev, hsdev->usage,
                                        &rot_state->callbacks);
        if (ret) {
                dev_err(&pdev->dev, "callback reg failed\n");
@@ -314,7 +345,7 @@ static int hid_dev_rot_remove(struct platform_device *pdev)
        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
        struct dev_rot_state *rot_state = iio_priv(indio_dev);
 
-       sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_DEVICE_ORIENTATION);
+       sensor_hub_remove_callback(hsdev, hsdev->usage);
        iio_device_unregister(indio_dev);
        hid_sensor_remove_trigger(&rot_state->common_attributes);
        iio_triggered_buffer_cleanup(indio_dev);
@@ -327,6 +358,14 @@ static const struct platform_device_id hid_dev_rot_ids[] = {
                /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
                .name = "HID-SENSOR-20008a",
        },
+       {
+               /* Relative orientation(AG) sensor */
+               .name = "HID-SENSOR-20008e",
+       },
+       {
+               /* Geomagnetic orientation(AM) sensor */
+               .name = "HID-SENSOR-2000c1",
+       },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids);
index 5d16b252ab6b70ee901430dc87f874f041971886..eaa7cfcb4c2aa611448cb6cc8c47c167dae44b19 100644 (file)
@@ -23,7 +23,7 @@ config BMP280
        select BMP280_SPI if (SPI_MASTER)
        help
          Say yes here to build support for Bosch Sensortec BMP180 and BMP280
-         pressure and temperature sensors. Also supports the BE280 with
+         pressure and temperature sensors. Also supports the BME280 with
          an additional humidity sensor channel.
 
          To compile this driver as a module, choose M here: the core module
index fd0edca0e656001b6b4487dc754695da4a81297f..aa61ec15c1396ca3925ecf1a099fbf91a302dae7 100644 (file)
@@ -568,6 +568,8 @@ static const struct iio_trigger_ops st_press_trigger_ops = {
 int st_press_common_probe(struct iio_dev *indio_dev)
 {
        struct st_sensor_data *press_data = iio_priv(indio_dev);
+       struct st_sensors_platform_data *pdata =
+               (struct st_sensors_platform_data *)press_data->dev->platform_data;
        int irq = press_data->get_irq_data_ready(indio_dev);
        int err;
 
@@ -603,10 +605,8 @@ int st_press_common_probe(struct iio_dev *indio_dev)
        press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
 
        /* Some devices don't support a data ready pin. */
-       if (!press_data->dev->platform_data &&
-                               press_data->sensor_settings->drdy_irq.addr)
-               press_data->dev->platform_data =
-                       (struct st_sensors_platform_data *)&default_press_pdata;
+       if (!pdata && press_data->sensor_settings->drdy_irq.addr)
+               pdata = (struct st_sensors_platform_data *)&default_press_pdata;
 
        err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
        if (err < 0)
index e58a0ad07477159ed5f9bc455135370d10092a16..c92a95f9f52c21410ea9f372c3254530008914bd 100644 (file)
@@ -867,12 +867,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev   *indio_dev,
 {
        int          ret;
        unsigned int val;
+       long     timeout;
 
        zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt");
 
-       ret = wait_for_completion_interruptible_timeout(
+       timeout = wait_for_completion_interruptible_timeout(
                &private->data_ready, ZPA2326_CONVERSION_JIFFIES);
-       if (ret > 0)
+       if (timeout > 0)
                /*
                 * Interrupt handler completed before timeout: return operation
                 * status.
@@ -882,13 +883,16 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev   *indio_dev,
        /* Clear all interrupts just to be sure. */
        regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val);
 
-       if (!ret)
+       if (!timeout) {
                /* Timed out. */
+               zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)",
+                            timeout);
                ret = -ETIME;
-
-       if (ret != -ERESTARTSYS)
-               zpa2326_warn(indio_dev, "no one shot interrupt occurred (%d)",
-                            ret);
+       } else if (timeout < 0) {
+               zpa2326_warn(indio_dev,
+                            "wait for one shot interrupt cancelled");
+               ret = -ERESTARTSYS;
+       }
 
        return ret;
 }
index ddf9bee89f777872ec27db426a46c18dd5da2fc3..aa0d0be1a6087ea653e2386ec95b56daf0ff468d 100644 (file)
@@ -176,13 +176,13 @@ static int as3935_read_raw(struct iio_dev *indio_dev,
                if (ret)
                        return ret;
 
-               if (m == IIO_CHAN_INFO_RAW)
-                       return IIO_VAL_INT;
-
                /* storm out of range */
                if (*val == AS3935_DATA_MASK)
                        return -EINVAL;
 
+               if (m == IIO_CHAN_INFO_RAW)
+                       return IIO_VAL_INT;
+
                if (m == IIO_CHAN_INFO_PROCESSED)
                        *val *= 1000;
                break;
index 557214202eff35dd870ea085a81161de2982c147..d70e2e53d6a78cc5ab8ee073a7e01e5f635483d1 100644 (file)
@@ -267,6 +267,7 @@ static int maxim_thermocouple_remove(struct spi_device *spi)
 static const struct spi_device_id maxim_thermocouple_id[] = {
        {"max6675", MAX6675},
        {"max31855", MAX31855},
+       {"max31856", MAX31855},
        {},
 };
 MODULE_DEVICE_TABLE(spi, maxim_thermocouple_id);
index 25248d644e7cb2aafaa212b52be163679d4cfc31..0797f2fe584f7345cf75156e39b96b3cda61afdb 100644 (file)
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-#define MAX_TRIGGERS 6
+#define MAX_TRIGGERS 7
 #define MAX_VALIDS 5
 
 /* List the triggers created by each timer */
 static const void *triggers_table[][MAX_TRIGGERS] = {
-       { TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,},
+       { TIM1_TRGO, TIM1_TRGO2, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,},
        { TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,},
        { TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,},
        { TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,},
        { TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,},
        { TIM6_TRGO,},
        { TIM7_TRGO,},
-       { TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},
+       { TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},
        { TIM9_TRGO, TIM9_CH1, TIM9_CH2,},
        { }, /* timer 10 */
        { }, /* timer 11 */
@@ -56,9 +56,16 @@ struct stm32_timer_trigger {
        u32 max_arr;
        const void *triggers;
        const void *valids;
+       bool has_trgo2;
 };
 
+static bool stm32_timer_is_trgo2_name(const char *name)
+{
+       return !!strstr(name, "trgo2");
+}
+
 static int stm32_timer_start(struct stm32_timer_trigger *priv,
+                            struct iio_trigger *trig,
                             unsigned int frequency)
 {
        unsigned long long prd, div;
@@ -102,7 +109,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv,
        regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
 
        /* Force master mode to update mode */
-       regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
+       if (stm32_timer_is_trgo2_name(trig->name))
+               regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2,
+                                  0x2 << TIM_CR2_MMS2_SHIFT);
+       else
+               regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS,
+                                  0x2 << TIM_CR2_MMS_SHIFT);
 
        /* Make sure that registers are updated */
        regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
@@ -150,7 +162,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev,
        if (freq == 0) {
                stm32_timer_stop(priv);
        } else {
-               ret = stm32_timer_start(priv, freq);
+               ret = stm32_timer_start(priv, trig, freq);
                if (ret)
                        return ret;
        }
@@ -183,6 +195,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(0660,
                              stm32_tt_read_frequency,
                              stm32_tt_store_frequency);
 
+#define MASTER_MODE_MAX                7
+#define MASTER_MODE2_MAX       15
+
 static char *master_mode_table[] = {
        "reset",
        "enable",
@@ -191,7 +206,16 @@ static char *master_mode_table[] = {
        "OC1REF",
        "OC2REF",
        "OC3REF",
-       "OC4REF"
+       "OC4REF",
+       /* Master mode selection 2 only */
+       "OC5REF",
+       "OC6REF",
+       "compare_pulse_OC4REF",
+       "compare_pulse_OC6REF",
+       "compare_pulse_OC4REF_r_or_OC6REF_r",
+       "compare_pulse_OC4REF_r_or_OC6REF_f",
+       "compare_pulse_OC5REF_r_or_OC6REF_r",
+       "compare_pulse_OC5REF_r_or_OC6REF_f",
 };
 
 static ssize_t stm32_tt_show_master_mode(struct device *dev,
@@ -199,10 +223,15 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev,
                                         char *buf)
 {
        struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
+       struct iio_trigger *trig = to_iio_trigger(dev);
        u32 cr2;
 
        regmap_read(priv->regmap, TIM_CR2, &cr2);
-       cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT;
+
+       if (stm32_timer_is_trgo2_name(trig->name))
+               cr2 = (cr2 & TIM_CR2_MMS2) >> TIM_CR2_MMS2_SHIFT;
+       else
+               cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT;
 
        return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);
 }
@@ -212,13 +241,25 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
                                          const char *buf, size_t len)
 {
        struct stm32_timer_trigger *priv = dev_get_drvdata(dev);
+       struct iio_trigger *trig = to_iio_trigger(dev);
+       u32 mask, shift, master_mode_max;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) {
+       if (stm32_timer_is_trgo2_name(trig->name)) {
+               mask = TIM_CR2_MMS2;
+               shift = TIM_CR2_MMS2_SHIFT;
+               master_mode_max = MASTER_MODE2_MAX;
+       } else {
+               mask = TIM_CR2_MMS;
+               shift = TIM_CR2_MMS_SHIFT;
+               master_mode_max = MASTER_MODE_MAX;
+       }
+
+       for (i = 0; i <= master_mode_max; i++) {
                if (!strncmp(master_mode_table[i], buf,
                             strlen(master_mode_table[i]))) {
-                       regmap_update_bits(priv->regmap, TIM_CR2,
-                                          TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT);
+                       regmap_update_bits(priv->regmap, TIM_CR2, mask,
+                                          i << shift);
                        /* Make sure that registers are updated */
                        regmap_update_bits(priv->regmap, TIM_EGR,
                                           TIM_EGR_UG, TIM_EGR_UG);
@@ -229,8 +270,31 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev,
        return -EINVAL;
 }
 
-static IIO_CONST_ATTR(master_mode_available,
-       "reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF");
+static ssize_t stm32_tt_show_master_mode_avail(struct device *dev,
+                                              struct device_attribute *attr,
+                                              char *buf)
+{
+       struct iio_trigger *trig = to_iio_trigger(dev);
+       unsigned int i, master_mode_max;
+       size_t len = 0;
+
+       if (stm32_timer_is_trgo2_name(trig->name))
+               master_mode_max = MASTER_MODE2_MAX;
+       else
+               master_mode_max = MASTER_MODE_MAX;
+
+       for (i = 0; i <= master_mode_max; i++)
+               len += scnprintf(buf + len, PAGE_SIZE - len,
+                       "%s ", master_mode_table[i]);
+
+       /* replace trailing space by newline */
+       buf[len - 1] = '\n';
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(master_mode_available, 0444,
+                      stm32_tt_show_master_mode_avail, NULL, 0);
 
 static IIO_DEVICE_ATTR(master_mode, 0660,
                       stm32_tt_show_master_mode,
@@ -240,7 +304,7 @@ static IIO_DEVICE_ATTR(master_mode, 0660,
 static struct attribute *stm32_trigger_attrs[] = {
        &iio_dev_attr_sampling_frequency.dev_attr.attr,
        &iio_dev_attr_master_mode.dev_attr.attr,
-       &iio_const_attr_master_mode_available.dev_attr.attr,
+       &iio_dev_attr_master_mode_available.dev_attr.attr,
        NULL,
 };
 
@@ -264,6 +328,12 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
 
        while (cur && *cur) {
                struct iio_trigger *trig;
+               bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur);
+
+               if (cur_is_trgo2 && !priv->has_trgo2) {
+                       cur++;
+                       continue;
+               }
 
                trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
                if  (!trig)
@@ -277,7 +347,7 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
                 * should only be available on trgo trigger which
                 * is always the first in the list.
                 */
-               if (cur == priv->triggers)
+               if (cur == priv->triggers || cur_is_trgo2)
                        trig->dev.groups = stm32_trigger_attr_groups;
 
                iio_trigger_set_drvdata(trig, priv);
@@ -584,6 +654,20 @@ bool is_stm32_timer_trigger(struct iio_trigger *trig)
 }
 EXPORT_SYMBOL(is_stm32_timer_trigger);
 
+static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv)
+{
+       u32 val;
+
+       /*
+        * Master mode selection 2 bits can only be written and read back when
+        * timer supports it.
+        */
+       regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2);
+       regmap_read(priv->regmap, TIM_CR2, &val);
+       regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0);
+       priv->has_trgo2 = !!val;
+}
+
 static int stm32_timer_trigger_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -614,6 +698,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev)
        priv->max_arr = ddata->max_arr;
        priv->triggers = triggers_table[index];
        priv->valids = valids_table[index];
+       stm32_timer_detect_trgo2(priv);
 
        ret = stm32_setup_iio_triggers(priv);
        if (ret)
index af108e96b3ecbc43b26b04193def4f6de07f1b41..995acdd7c942612172a55232bae5378a0ca50509 100644 (file)
@@ -292,7 +292,7 @@ ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
        return sprintf(buf, "%s\n", str);
 }
 
-static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, S_IRUGO,
+static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, 0444,
                       ad9834_show_out0_wavetype_available, NULL, 0);
 
 static
@@ -312,27 +312,27 @@ ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
        return sprintf(buf, "%s\n", str);
 }
 
-static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, S_IRUGO,
+static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, 0444,
                       ad9834_show_out1_wavetype_available, NULL, 0);
 
 /**
  * see dds.h for further information
  */
 
-static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0);
-static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1);
-static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL);
+static IIO_DEV_ATTR_FREQ(0, 0, 0200, NULL, ad9834_write, AD9834_REG_FREQ0);
+static IIO_DEV_ATTR_FREQ(0, 1, 0200, NULL, ad9834_write, AD9834_REG_FREQ1);
+static IIO_DEV_ATTR_FREQSYMBOL(0, 0200, NULL, ad9834_write, AD9834_FSEL);
 static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */
 
-static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0);
-static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1);
-static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL);
+static IIO_DEV_ATTR_PHASE(0, 0, 0200, NULL, ad9834_write, AD9834_REG_PHASE0);
+static IIO_DEV_ATTR_PHASE(0, 1, 0200, NULL, ad9834_write, AD9834_REG_PHASE1);
+static IIO_DEV_ATTR_PHASESYMBOL(0, 0200, NULL, ad9834_write, AD9834_PSEL);
 static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/
 
-static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL,
+static IIO_DEV_ATTR_PINCONTROL_EN(0, 0200, NULL,
        ad9834_write, AD9834_PIN_SW);
-static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET);
-static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL,
+static IIO_DEV_ATTR_OUT_ENABLE(0, 0200, NULL, ad9834_write, AD9834_RESET);
+static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, 0200, NULL,
        ad9834_write, AD9834_OPBITEN);
 static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
 static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
index fe53e7324c9458fb64d69b85b80e0d18b85474c0..d6ccd99c14d78ff3b55b0d738a34d2df48b4d2b1 100644 (file)
 
 #define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr)    \
        IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\
-                       S_IWUSR, NULL, _store, _addr)
+                       0200, NULL, _store, _addr)
 
 /**
  * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
index 4fbf6298c0f34e1011483df5ec24ccbad9bc1db9..aacb0ae58c0ef6097b40a7afd2e463a450bcd661 100644 (file)
@@ -3,16 +3,6 @@
 #
 menu "Light sensors"
 
-config SENSORS_ISL29028
-       tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
-       depends on I2C
-       select REGMAP_I2C
-       help
-        Provides driver for the Intersil's ISL29028 device.
-        This driver supports the sysfs interface to get the ALS, IR intensity,
-        Proximity value via iio. The ISL29028 provides the concurrent sensing
-        of ambient light and proximity.
-
 config TSL2x7x
        tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
        depends on I2C
index f8693e9fdc94437843f2593066440c43564e5896..ab8dc3a3d10be0ccaf29e1a959e8b3364ee87515 100644 (file)
@@ -2,5 +2,4 @@
 # Makefile for industrial I/O Light sensors
 #
 
-obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
-obj-$(CONFIG_TSL2x7x)  += tsl2x7x_core.o
+obj-$(CONFIG_TSL2x7x)  += tsl2x7x.o
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
deleted file mode 100644 (file)
index 5375e7a..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-/*
- * IIO driver for the light sensor ISL29028.
- * ISL29028 is Concurrent Ambient Light and Proximity Sensor
- *
- * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
- * Copyright (c) 2016-2017 Brian Masney <masneyb@onstation.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/regmap.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/pm_runtime.h>
-
-#define ISL29028_CONV_TIME_MS                  100
-
-#define ISL29028_REG_CONFIGURE                 0x01
-
-#define ISL29028_CONF_ALS_IR_MODE_ALS          0
-#define ISL29028_CONF_ALS_IR_MODE_IR           BIT(0)
-#define ISL29028_CONF_ALS_IR_MODE_MASK         BIT(0)
-
-#define ISL29028_CONF_ALS_RANGE_LOW_LUX                0
-#define ISL29028_CONF_ALS_RANGE_HIGH_LUX       BIT(1)
-#define ISL29028_CONF_ALS_RANGE_MASK           BIT(1)
-
-#define ISL29028_CONF_ALS_DIS                  0
-#define ISL29028_CONF_ALS_EN                   BIT(2)
-#define ISL29028_CONF_ALS_EN_MASK              BIT(2)
-
-#define ISL29028_CONF_PROX_SLP_SH              4
-#define ISL29028_CONF_PROX_SLP_MASK            (7 << ISL29028_CONF_PROX_SLP_SH)
-
-#define ISL29028_CONF_PROX_EN                  BIT(7)
-#define ISL29028_CONF_PROX_EN_MASK             BIT(7)
-
-#define ISL29028_REG_INTERRUPT                 0x02
-
-#define ISL29028_REG_PROX_DATA                 0x08
-#define ISL29028_REG_ALSIR_L                   0x09
-#define ISL29028_REG_ALSIR_U                   0x0A
-
-#define ISL29028_REG_TEST1_MODE                        0x0E
-#define ISL29028_REG_TEST2_MODE                        0x0F
-
-#define ISL29028_NUM_REGS                      (ISL29028_REG_TEST2_MODE + 1)
-
-#define ISL29028_POWER_OFF_DELAY_MS            2000
-
-static const unsigned int isl29028_prox_sleep_time[] = {800, 400, 200, 100, 75,
-                                                       50, 12, 0};
-
-enum isl29028_als_ir_mode {
-       ISL29028_MODE_NONE = 0,
-       ISL29028_MODE_ALS,
-       ISL29028_MODE_IR,
-};
-
-struct isl29028_chip {
-       struct mutex                    lock;
-       struct regmap                   *regmap;
-       unsigned int                    prox_sampling;
-       bool                            enable_prox;
-       int                             lux_scale;
-       enum isl29028_als_ir_mode       als_ir_mode;
-};
-
-static int isl29028_find_prox_sleep_time_index(int sampling)
-{
-       unsigned int period = DIV_ROUND_UP(1000, sampling);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(isl29028_prox_sleep_time); ++i) {
-               if (period >= isl29028_prox_sleep_time[i])
-                       break;
-       }
-
-       return i;
-}
-
-static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
-                                       unsigned int sampling)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       int sleep_index, ret;
-
-       sleep_index = isl29028_find_prox_sleep_time_index(sampling);
-       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                ISL29028_CONF_PROX_SLP_MASK,
-                                sleep_index << ISL29028_CONF_PROX_SLP_SH);
-
-       if (ret < 0) {
-               dev_err(dev, "%s(): Error %d setting the proximity sampling\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       chip->prox_sampling = sampling;
-
-       return ret;
-}
-
-static int isl29028_enable_proximity(struct isl29028_chip *chip)
-{
-       int sleep_index, ret;
-
-       ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
-       if (ret < 0)
-               return ret;
-
-       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                ISL29028_CONF_PROX_EN_MASK,
-                                ISL29028_CONF_PROX_EN);
-       if (ret < 0)
-               return ret;
-
-       /* Wait for conversion to be complete for first sample */
-       sleep_index = isl29028_find_prox_sleep_time_index(chip->prox_sampling);
-       msleep(isl29028_prox_sleep_time[sleep_index]);
-
-       return 0;
-}
-
-static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX :
-                                       ISL29028_CONF_ALS_RANGE_LOW_LUX;
-       int ret;
-
-       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                ISL29028_CONF_ALS_RANGE_MASK, val);
-       if (ret < 0) {
-               dev_err(dev, "%s(): Error %d setting the ALS scale\n", __func__,
-                       ret);
-               return ret;
-       }
-
-       chip->lux_scale = lux_scale;
-
-       return ret;
-}
-
-static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
-                                   enum isl29028_als_ir_mode mode)
-{
-       int ret;
-
-       if (chip->als_ir_mode == mode)
-               return 0;
-
-       ret = isl29028_set_als_scale(chip, chip->lux_scale);
-       if (ret < 0)
-               return ret;
-
-       switch (mode) {
-       case ISL29028_MODE_ALS:
-               ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                        ISL29028_CONF_ALS_IR_MODE_MASK,
-                                        ISL29028_CONF_ALS_IR_MODE_ALS);
-               if (ret < 0)
-                       return ret;
-
-               ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                        ISL29028_CONF_ALS_RANGE_MASK,
-                                        ISL29028_CONF_ALS_RANGE_HIGH_LUX);
-               break;
-       case ISL29028_MODE_IR:
-               ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                        ISL29028_CONF_ALS_IR_MODE_MASK,
-                                        ISL29028_CONF_ALS_IR_MODE_IR);
-               break;
-       case ISL29028_MODE_NONE:
-               return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                         ISL29028_CONF_ALS_EN_MASK,
-                                         ISL29028_CONF_ALS_DIS);
-       }
-
-       if (ret < 0)
-               return ret;
-
-       /* Enable the ALS/IR */
-       ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
-                                ISL29028_CONF_ALS_EN_MASK,
-                                ISL29028_CONF_ALS_EN);
-       if (ret < 0)
-               return ret;
-
-       /* Need to wait for conversion time if ALS/IR mode enabled */
-       msleep(ISL29028_CONV_TIME_MS);
-
-       chip->als_ir_mode = mode;
-
-       return 0;
-}
-
-static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       unsigned int lsb;
-       unsigned int msb;
-       int ret;
-
-       ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
-       if (ret < 0) {
-               dev_err(dev,
-                       "%s(): Error %d reading register ALSIR_L\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
-       if (ret < 0) {
-               dev_err(dev,
-                       "%s(): Error %d reading register ALSIR_U\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
-
-       return 0;
-}
-
-static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       unsigned int data;
-       int ret;
-
-       if (!chip->enable_prox) {
-               ret = isl29028_enable_proximity(chip);
-               if (ret < 0)
-                       return ret;
-
-               chip->enable_prox = true;
-       }
-
-       ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
-       if (ret < 0) {
-               dev_err(dev, "%s(): Error %d reading register PROX_DATA\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       *prox = data;
-
-       return 0;
-}
-
-static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       int ret;
-       int als_ir_data;
-
-       ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS);
-       if (ret < 0) {
-               dev_err(dev, "%s(): Error %d enabling ALS mode\n", __func__,
-                       ret);
-               return ret;
-       }
-
-       ret = isl29028_read_als_ir(chip, &als_ir_data);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * convert als data count to lux.
-        * if lux_scale = 125,  lux = count * 0.031
-        * if lux_scale = 2000, lux = count * 0.49
-        */
-       if (chip->lux_scale == 125)
-               als_ir_data = (als_ir_data * 31) / 1000;
-       else
-               als_ir_data = (als_ir_data * 49) / 100;
-
-       *als_data = als_ir_data;
-
-       return 0;
-}
-
-static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       int ret;
-
-       ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR);
-       if (ret < 0) {
-               dev_err(dev, "%s(): Error %d enabling IR mode\n", __func__,
-                       ret);
-               return ret;
-       }
-
-       return isl29028_read_als_ir(chip, ir_data);
-}
-
-static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       int ret;
-
-       if (on) {
-               ret = pm_runtime_get_sync(dev);
-               if (ret < 0)
-                       pm_runtime_put_noidle(dev);
-       } else {
-               pm_runtime_mark_last_busy(dev);
-               ret = pm_runtime_put_autosuspend(dev);
-       }
-
-       return ret;
-}
-
-/* Channel IO */
-static int isl29028_write_raw(struct iio_dev *indio_dev,
-                             struct iio_chan_spec const *chan,
-                             int val, int val2, long mask)
-{
-       struct isl29028_chip *chip = iio_priv(indio_dev);
-       struct device *dev = regmap_get_device(chip->regmap);
-       int ret;
-
-       ret = isl29028_set_pm_runtime_busy(chip, true);
-       if (ret < 0)
-               return ret;
-
-       mutex_lock(&chip->lock);
-
-       ret = -EINVAL;
-       switch (chan->type) {
-       case IIO_PROXIMITY:
-               if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
-                       dev_err(dev,
-                               "%s(): proximity: Mask value 0x%08lx is not supported\n",
-                               __func__, mask);
-                       break;
-               }
-
-               if (val < 1 || val > 100) {
-                       dev_err(dev,
-                               "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n",
-                               __func__, val);
-                       break;
-               }
-
-               ret = isl29028_set_proxim_sampling(chip, val);
-               break;
-       case IIO_LIGHT:
-               if (mask != IIO_CHAN_INFO_SCALE) {
-                       dev_err(dev,
-                               "%s(): light: Mask value 0x%08lx is not supported\n",
-                               __func__, mask);
-                       break;
-               }
-
-               if (val != 125 && val != 2000) {
-                       dev_err(dev,
-                               "%s(): light: Lux scale %d is not in the set {125, 2000}\n",
-                               __func__, val);
-                       break;
-               }
-
-               ret = isl29028_set_als_scale(chip, val);
-               break;
-       default:
-               dev_err(dev, "%s(): Unsupported channel type %x\n",
-                       __func__, chan->type);
-               break;
-       }
-
-       mutex_unlock(&chip->lock);
-
-       if (ret < 0)
-               return ret;
-
-       ret = isl29028_set_pm_runtime_busy(chip, false);
-       if (ret < 0)
-               return ret;
-
-       return ret;
-}
-
-static int isl29028_read_raw(struct iio_dev *indio_dev,
-                            struct iio_chan_spec const *chan,
-                            int *val, int *val2, long mask)
-{
-       struct isl29028_chip *chip = iio_priv(indio_dev);
-       struct device *dev = regmap_get_device(chip->regmap);
-       int ret, pm_ret;
-
-       ret = isl29028_set_pm_runtime_busy(chip, true);
-       if (ret < 0)
-               return ret;
-
-       mutex_lock(&chip->lock);
-
-       ret = -EINVAL;
-       switch (mask) {
-       case IIO_CHAN_INFO_RAW:
-       case IIO_CHAN_INFO_PROCESSED:
-               switch (chan->type) {
-               case IIO_LIGHT:
-                       ret = isl29028_als_get(chip, val);
-                       break;
-               case IIO_INTENSITY:
-                       ret = isl29028_ir_get(chip, val);
-                       break;
-               case IIO_PROXIMITY:
-                       ret = isl29028_read_proxim(chip, val);
-                       break;
-               default:
-                       break;
-               }
-
-               if (ret < 0)
-                       break;
-
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_SAMP_FREQ:
-               if (chan->type != IIO_PROXIMITY)
-                       break;
-
-               *val = chip->prox_sampling;
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_SCALE:
-               if (chan->type != IIO_LIGHT)
-                       break;
-               *val = chip->lux_scale;
-               ret = IIO_VAL_INT;
-               break;
-       default:
-               dev_err(dev, "%s(): mask value 0x%08lx is not supported\n",
-                       __func__, mask);
-               break;
-       }
-
-       mutex_unlock(&chip->lock);
-
-       if (ret < 0)
-               return ret;
-
-       /**
-        * Preserve the ret variable if the call to
-        * isl29028_set_pm_runtime_busy() is successful so the reading
-        * (if applicable) is returned to user space.
-        */
-       pm_ret = isl29028_set_pm_runtime_busy(chip, false);
-       if (pm_ret < 0)
-               return pm_ret;
-
-       return ret;
-}
-
-static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
-                               "1 3 5 10 13 20 83 100");
-static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000");
-
-#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
-static struct attribute *isl29028_attributes[] = {
-       ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
-       ISL29028_CONST_ATTR(in_illuminance_scale_available),
-       NULL,
-};
-
-static const struct attribute_group isl29108_group = {
-       .attrs = isl29028_attributes,
-};
-
-static const struct iio_chan_spec isl29028_channels[] = {
-       {
-               .type = IIO_LIGHT,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
-               BIT(IIO_CHAN_INFO_SCALE),
-       }, {
-               .type = IIO_INTENSITY,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-       }, {
-               .type = IIO_PROXIMITY,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-               BIT(IIO_CHAN_INFO_SAMP_FREQ),
-       }
-};
-
-static const struct iio_info isl29028_info = {
-       .attrs = &isl29108_group,
-       .driver_module = THIS_MODULE,
-       .read_raw = isl29028_read_raw,
-       .write_raw = isl29028_write_raw,
-};
-
-static int isl29028_clear_configure_reg(struct isl29028_chip *chip)
-{
-       struct device *dev = regmap_get_device(chip->regmap);
-       int ret;
-
-       ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
-       if (ret < 0)
-               dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n",
-                       __func__, ret);
-
-       chip->als_ir_mode = ISL29028_MODE_NONE;
-       chip->enable_prox = false;
-
-       return ret;
-}
-
-static bool isl29028_is_volatile_reg(struct device *dev, unsigned int reg)
-{
-       switch (reg) {
-       case ISL29028_REG_INTERRUPT:
-       case ISL29028_REG_PROX_DATA:
-       case ISL29028_REG_ALSIR_L:
-       case ISL29028_REG_ALSIR_U:
-               return true;
-       default:
-               return false;
-       }
-}
-
-static const struct regmap_config isl29028_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .volatile_reg = isl29028_is_volatile_reg,
-       .max_register = ISL29028_NUM_REGS - 1,
-       .num_reg_defaults_raw = ISL29028_NUM_REGS,
-       .cache_type = REGCACHE_RBTREE,
-};
-
-static int isl29028_probe(struct i2c_client *client,
-                         const struct i2c_device_id *id)
-{
-       struct isl29028_chip *chip;
-       struct iio_dev *indio_dev;
-       int ret;
-
-       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
-       if (!indio_dev)
-               return -ENOMEM;
-
-       chip = iio_priv(indio_dev);
-
-       i2c_set_clientdata(client, indio_dev);
-       mutex_init(&chip->lock);
-
-       chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
-       if (IS_ERR(chip->regmap)) {
-               ret = PTR_ERR(chip->regmap);
-               dev_err(&client->dev, "%s: Error %d initializing regmap\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       chip->enable_prox  = false;
-       chip->prox_sampling = 20;
-       chip->lux_scale = 2000;
-
-       ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
-       if (ret < 0) {
-               dev_err(&client->dev,
-                       "%s(): Error %d writing to TEST1_MODE register\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
-       if (ret < 0) {
-               dev_err(&client->dev,
-                       "%s(): Error %d writing to TEST2_MODE register\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       ret = isl29028_clear_configure_reg(chip);
-       if (ret < 0)
-               return ret;
-
-       indio_dev->info = &isl29028_info;
-       indio_dev->channels = isl29028_channels;
-       indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
-       indio_dev->name = id->name;
-       indio_dev->dev.parent = &client->dev;
-       indio_dev->modes = INDIO_DIRECT_MODE;
-
-       pm_runtime_enable(&client->dev);
-       pm_runtime_set_autosuspend_delay(&client->dev,
-                                        ISL29028_POWER_OFF_DELAY_MS);
-       pm_runtime_use_autosuspend(&client->dev);
-
-       ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev,
-                       "%s(): iio registration failed with error %d\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int isl29028_remove(struct i2c_client *client)
-{
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
-       struct isl29028_chip *chip = iio_priv(indio_dev);
-
-       iio_device_unregister(indio_dev);
-
-       pm_runtime_disable(&client->dev);
-       pm_runtime_set_suspended(&client->dev);
-       pm_runtime_put_noidle(&client->dev);
-
-       return isl29028_clear_configure_reg(chip);
-}
-
-static int __maybe_unused isl29028_suspend(struct device *dev)
-{
-       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
-       struct isl29028_chip *chip = iio_priv(indio_dev);
-       int ret;
-
-       mutex_lock(&chip->lock);
-
-       ret = isl29028_clear_configure_reg(chip);
-
-       mutex_unlock(&chip->lock);
-
-       return ret;
-}
-
-static int __maybe_unused isl29028_resume(struct device *dev)
-{
-       /**
-        * The specific component (ALS/IR or proximity) will enable itself as
-        * needed the next time that the user requests a reading. This is done
-        * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity().
-        */
-       return 0;
-}
-
-static const struct dev_pm_ops isl29028_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                               pm_runtime_force_resume)
-       SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL)
-};
-
-static const struct i2c_device_id isl29028_id[] = {
-       {"isl29028", 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, isl29028_id);
-
-static const struct of_device_id isl29028_of_match[] = {
-       { .compatible = "isl,isl29028", }, /* for backward compat., don't use */
-       { .compatible = "isil,isl29028", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, isl29028_of_match);
-
-static struct i2c_driver isl29028_driver = {
-       .driver  = {
-               .name = "isl29028",
-               .pm = &isl29028_pm_ops,
-               .of_match_table = isl29028_of_match,
-       },
-       .probe   = isl29028_probe,
-       .remove  = isl29028_remove,
-       .id_table = isl29028_id,
-};
-
-module_i2c_driver(isl29028_driver);
-
-MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
diff --git a/drivers/staging/iio/light/tsl2x7x.c b/drivers/staging/iio/light/tsl2x7x.c
new file mode 100644 (file)
index 0000000..1467199
--- /dev/null
@@ -0,0 +1,2049 @@
+/*
+ * Device driver for monitoring ambient light intensity in (lux)
+ * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "tsl2x7x.h"
+
+/* Cal defs*/
+#define PROX_STAT_CAL        0
+#define PROX_STAT_SAMP       1
+#define MAX_SAMPLES_CAL      200
+
+/* TSL2X7X Device ID */
+#define TRITON_ID    0x00
+#define SWORDFISH_ID 0x30
+#define HALIBUT_ID   0x20
+
+/* Lux calculation constants */
+#define TSL2X7X_LUX_CALC_OVER_FLOW     65535
+
+/* TAOS Register definitions - note:
+ * depending on device, some of these register are not used and the
+ * register address is benign.
+ */
+/* 2X7X register offsets */
+#define TSL2X7X_MAX_CONFIG_REG         16
+
+/* Device Registers and Masks */
+#define TSL2X7X_CNTRL                  0x00
+#define TSL2X7X_ALS_TIME               0X01
+#define TSL2X7X_PRX_TIME               0x02
+#define TSL2X7X_WAIT_TIME              0x03
+#define TSL2X7X_ALS_MINTHRESHLO        0X04
+#define TSL2X7X_ALS_MINTHRESHHI        0X05
+#define TSL2X7X_ALS_MAXTHRESHLO        0X06
+#define TSL2X7X_ALS_MAXTHRESHHI        0X07
+#define TSL2X7X_PRX_MINTHRESHLO        0X08
+#define TSL2X7X_PRX_MINTHRESHHI        0X09
+#define TSL2X7X_PRX_MAXTHRESHLO        0X0A
+#define TSL2X7X_PRX_MAXTHRESHHI        0X0B
+#define TSL2X7X_PERSISTENCE            0x0C
+#define TSL2X7X_PRX_CONFIG             0x0D
+#define TSL2X7X_PRX_COUNT              0x0E
+#define TSL2X7X_GAIN                   0x0F
+#define TSL2X7X_NOTUSED                0x10
+#define TSL2X7X_REVID                  0x11
+#define TSL2X7X_CHIPID                 0x12
+#define TSL2X7X_STATUS                 0x13
+#define TSL2X7X_ALS_CHAN0LO            0x14
+#define TSL2X7X_ALS_CHAN0HI            0x15
+#define TSL2X7X_ALS_CHAN1LO            0x16
+#define TSL2X7X_ALS_CHAN1HI            0x17
+#define TSL2X7X_PRX_LO                 0x18
+#define TSL2X7X_PRX_HI                 0x19
+
+/* tsl2X7X cmd reg masks */
+#define TSL2X7X_CMD_REG                0x80
+#define TSL2X7X_CMD_SPL_FN             0x60
+
+#define TSL2X7X_CMD_PROX_INT_CLR       0X05
+#define TSL2X7X_CMD_ALS_INT_CLR        0x06
+#define TSL2X7X_CMD_PROXALS_INT_CLR    0X07
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_ADC_ENBL          0x02
+#define TSL2X7X_CNTL_PWR_ON            0x01
+
+/* tsl2X7X status reg masks */
+#define TSL2X7X_STA_ADC_VALID          0x01
+#define TSL2X7X_STA_PRX_VALID          0x02
+#define TSL2X7X_STA_ADC_PRX_VALID      (TSL2X7X_STA_ADC_VALID |\
+                                       TSL2X7X_STA_PRX_VALID)
+#define TSL2X7X_STA_ALS_INTR           0x10
+#define TSL2X7X_STA_PRX_INTR           0x20
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_REG_CLEAR         0x00
+#define TSL2X7X_CNTL_PROX_INT_ENBL     0X20
+#define TSL2X7X_CNTL_ALS_INT_ENBL      0X10
+#define TSL2X7X_CNTL_WAIT_TMR_ENBL     0X08
+#define TSL2X7X_CNTL_PROX_DET_ENBL     0X04
+#define TSL2X7X_CNTL_PWRON             0x01
+#define TSL2X7X_CNTL_ALSPON_ENBL       0x03
+#define TSL2X7X_CNTL_INTALSPON_ENBL    0x13
+#define TSL2X7X_CNTL_PROXPON_ENBL      0x0F
+#define TSL2X7X_CNTL_INTPROXPON_ENBL   0x2F
+
+/*Prox diode to use */
+#define TSL2X7X_DIODE0                 0x10
+#define TSL2X7X_DIODE1                 0x20
+#define TSL2X7X_DIODE_BOTH             0x30
+
+/* LED Power */
+#define TSL2X7X_mA100                  0x00
+#define TSL2X7X_mA50                   0x40
+#define TSL2X7X_mA25                   0x80
+#define TSL2X7X_mA13                   0xD0
+#define TSL2X7X_MAX_TIMER_CNT          (0xFF)
+
+#define TSL2X7X_MIN_ITIME 3
+
+/* TAOS txx2x7x Device family members */
+enum {
+       tsl2571,
+       tsl2671,
+       tmd2671,
+       tsl2771,
+       tmd2771,
+       tsl2572,
+       tsl2672,
+       tmd2672,
+       tsl2772,
+       tmd2772
+};
+
+enum {
+       TSL2X7X_CHIP_UNKNOWN = 0,
+       TSL2X7X_CHIP_WORKING = 1,
+       TSL2X7X_CHIP_SUSPENDED = 2
+};
+
+struct tsl2x7x_parse_result {
+       int integer;
+       int fract;
+};
+
+/* Per-device data */
+struct tsl2x7x_als_info {
+       u16 als_ch0;
+       u16 als_ch1;
+       u16 lux;
+};
+
+struct tsl2x7x_prox_stat {
+       int min;
+       int max;
+       int mean;
+       unsigned long stddev;
+};
+
+struct tsl2x7x_chip_info {
+       int chan_table_elements;
+       struct iio_chan_spec            channel[4];
+       const struct iio_info           *info;
+};
+
+struct tsl2X7X_chip {
+       kernel_ulong_t id;
+       struct mutex prox_mutex;
+       struct mutex als_mutex;
+       struct i2c_client *client;
+       u16 prox_data;
+       struct tsl2x7x_als_info als_cur_info;
+       struct tsl2x7x_settings tsl2x7x_settings;
+       struct tsl2X7X_platform_data *pdata;
+       int als_time_scale;
+       int als_saturation;
+       int tsl2x7x_chip_status;
+       u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
+       const struct tsl2x7x_chip_info  *chip_info;
+       const struct iio_info *info;
+       s64 event_timestamp;
+       /*
+        * This structure is intentionally large to accommodate
+        * updates via sysfs.
+        * Sized to 9 = max 8 segments + 1 termination segment
+        */
+       struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
+};
+
+/* Different devices require different coefficents */
+static const struct tsl2x7x_lux tsl2x71_lux_table[] = {
+       { 14461,   611,   1211 },
+       { 18540,   352,    623 },
+       {     0,     0,      0 },
+};
+
+static const struct tsl2x7x_lux tmd2x71_lux_table[] = {
+       { 11635,   115,    256 },
+       { 15536,    87,    179 },
+       {     0,     0,      0 },
+};
+
+static const struct tsl2x7x_lux tsl2x72_lux_table[] = {
+       { 14013,   466,   917 },
+       { 18222,   310,   552 },
+       {     0,     0,     0 },
+};
+
+static const struct tsl2x7x_lux tmd2x72_lux_table[] = {
+       { 13218,   130,   262 },
+       { 17592,   92,    169 },
+       {     0,     0,     0 },
+};
+
+static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
+       [tsl2571] =     tsl2x71_lux_table,
+       [tsl2671] =     tsl2x71_lux_table,
+       [tmd2671] =     tmd2x71_lux_table,
+       [tsl2771] =     tsl2x71_lux_table,
+       [tmd2771] =     tmd2x71_lux_table,
+       [tsl2572] =     tsl2x72_lux_table,
+       [tsl2672] =     tsl2x72_lux_table,
+       [tmd2672] =     tmd2x72_lux_table,
+       [tsl2772] =     tsl2x72_lux_table,
+       [tmd2772] =     tmd2x72_lux_table,
+};
+
+static const struct tsl2x7x_settings tsl2x7x_default_settings = {
+       .als_time = 219, /* 101 ms */
+       .als_gain = 0,
+       .prx_time = 254, /* 5.4 ms */
+       .prox_gain = 1,
+       .wait_time = 245,
+       .prox_config = 0,
+       .als_gain_trim = 1000,
+       .als_cal_target = 150,
+       .als_thresh_low = 200,
+       .als_thresh_high = 256,
+       .persistence = 255,
+       .interrupts_en = 0,
+       .prox_thres_low  = 0,
+       .prox_thres_high = 512,
+       .prox_max_samples_cal = 30,
+       .prox_pulse_count = 8
+};
+
+static const s16 tsl2X7X_als_gainadj[] = {
+       1,
+       8,
+       16,
+       120
+};
+
+static const s16 tsl2X7X_prx_gainadj[] = {
+       1,
+       2,
+       4,
+       8
+};
+
+/* Channel variations */
+enum {
+       ALS,
+       PRX,
+       ALSPRX,
+       PRX2,
+       ALSPRX2,
+};
+
+static const u8 device_channel_config[] = {
+       ALS,
+       PRX,
+       PRX,
+       ALSPRX,
+       ALSPRX,
+       ALS,
+       PRX2,
+       PRX2,
+       ALSPRX2,
+       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
+ *
+ * The raw ch0 and ch1 values of the ambient light sensed in the last
+ * integration cycle are read from the device.
+ * Time scale factor array values are adjusted based on the integration time.
+ * The raw values are multiplied by a scale factor, and device gain is obtained
+ * using gain index. Limit checks are done next, then the ratio of a multiple
+ * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
+ * is then scanned to find the first ratio value that is just above the ratio
+ * we just calculated. The ch0 and ch1 multiplier constants in the array are
+ * then used along with the time scale factor array values, to calculate the
+ * lux.
+ */
+static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
+{
+       u16 ch0, ch1; /* separated ch0/ch1 data from device */
+       u32 lux; /* raw lux calculated from device data */
+       u64 lux64;
+       u32 ratio;
+       u8 buf[4];
+       struct tsl2x7x_lux *p;
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int i, ret;
+       u32 ch0lux = 0;
+       u32 ch1lux = 0;
+
+       if (mutex_trylock(&chip->als_mutex) == 0)
+               return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
+
+       if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
+               /* device is not enabled */
+               dev_err(&chip->client->dev, "%s: device is not enabled\n",
+                       __func__);
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
+       ret = tsl2x7x_i2c_read(chip->client,
+                              (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
+       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)) {
+               dev_err(&chip->client->dev,
+                       "%s: data not valid yet\n", __func__);
+               ret = chip->als_cur_info.lux; /* return LAST VALUE */
+               goto out_unlock;
+       }
+
+       for (i = 0; i < 4; i++) {
+               ret = tsl2x7x_i2c_read(chip->client,
+                                      (TSL2X7X_CMD_REG |
+                                      (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]);
+               if (ret < 0) {
+                       dev_err(&chip->client->dev,
+                               "failed to read. err=%x\n", ret);
+                       goto out_unlock;
+               }
+       }
+
+       /* clear any existing interrupt status */
+       ret = i2c_smbus_write_byte(chip->client,
+                                  (TSL2X7X_CMD_REG |
+                                  TSL2X7X_CMD_SPL_FN |
+                                  TSL2X7X_CMD_ALS_INT_CLR));
+       if (ret < 0) {
+               dev_err(&chip->client->dev,
+                       "i2c_write_command failed - err = %d\n", ret);
+               goto out_unlock; /* have no data, so return failure */
+       }
+
+       /* extract ALS/lux data */
+       ch0 = le16_to_cpup((const __le16 *)&buf[0]);
+       ch1 = le16_to_cpup((const __le16 *)&buf[2]);
+
+       chip->als_cur_info.als_ch0 = ch0;
+       chip->als_cur_info.als_ch1 = ch1;
+
+       if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) {
+               lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+               goto return_max;
+       }
+
+       if (!ch0) {
+               /* have no data, so return LAST VALUE */
+               ret = chip->als_cur_info.lux;
+               goto out_unlock;
+       }
+       /* calculate ratio */
+       ratio = (ch1 << 15) / ch0;
+       /* convert to unscaled lux using the pointer to the table */
+       p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux;
+       while (p->ratio != 0 && p->ratio < ratio)
+               p++;
+
+       if (p->ratio == 0) {
+               lux = 0;
+       } else {
+               ch0lux = DIV_ROUND_UP(ch0 * p->ch0,
+                       tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+               ch1lux = DIV_ROUND_UP(ch1 * p->ch1,
+                       tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+               lux = ch0lux - ch1lux;
+       }
+
+       /* note: lux is 31 bit max at this point */
+       if (ch1lux > ch0lux) {
+               dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
+               ret = chip->als_cur_info.lux;
+               goto out_unlock;
+       }
+
+       /* adjust for active time scale */
+       if (chip->als_time_scale == 0)
+               lux = 0;
+       else
+               lux = (lux + (chip->als_time_scale >> 1)) /
+                       chip->als_time_scale;
+
+       /* adjust for active gain scale
+        * The tsl2x7x_device_lux tables have a factor of 256 built-in.
+        * User-specified gain provides a multiplier.
+        * Apply user-specified gain before shifting right to retain precision.
+        * Use 64 bits to avoid overflow on multiplication.
+        * Then go back to 32 bits before division to avoid using div_u64().
+        */
+
+       lux64 = lux;
+       lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
+       lux64 >>= 8;
+       lux = lux64;
+       lux = (lux + 500) / 1000;
+
+       if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
+               lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+
+       /* Update the structure with the latest lux. */
+return_max:
+       chip->als_cur_info.lux = lux;
+       ret = lux;
+
+out_unlock:
+       mutex_unlock(&chip->als_mutex);
+
+       return ret;
+}
+
+/**
+ * tsl2x7x_get_prox() - Reads proximity data registers and updates
+ *                      chip->prox_data.
+ *
+ * @indio_dev: pointer to IIO device
+ */
+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);
+
+       if (mutex_trylock(&chip->prox_mutex) == 0) {
+               dev_err(&chip->client->dev,
+                       "%s: Can't get prox mutex\n", __func__);
+               return -EBUSY;
+       }
+
+       ret = tsl2x7x_i2c_read(chip->client,
+                              (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
+       if (ret < 0) {
+               dev_err(&chip->client->dev, "i2c err=%d\n", ret);
+               goto prox_poll_err;
+       }
+
+       switch (chip->id) {
+       case tsl2571:
+       case tsl2671:
+       case tmd2671:
+       case tsl2771:
+       case tmd2771:
+               if (!(status & TSL2X7X_STA_ADC_VALID))
+                       goto prox_poll_err;
+       break;
+       case tsl2572:
+       case tsl2672:
+       case tmd2672:
+       case tsl2772:
+       case tmd2772:
+               if (!(status & 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]);
+               if (ret < 0)
+                       goto prox_poll_err;
+       }
+
+       chip->prox_data =
+                       le16_to_cpup((const __le16 *)&chdata[0]);
+
+prox_poll_err:
+
+       mutex_unlock(&chip->prox_mutex);
+
+       return chip->prox_data;
+}
+
+/**
+ * tsl2x7x_defaults() - Populates the device nominal operating parameters
+ *                      with those provided by a 'platform' data struct or
+ *                      with prefined defaults.
+ *
+ * @chip:               pointer to device structure.
+ */
+static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
+{
+       /* If Operational settings defined elsewhere.. */
+       if (chip->pdata && chip->pdata->platform_default_settings)
+               memcpy(&chip->tsl2x7x_settings,
+                      chip->pdata->platform_default_settings,
+                      sizeof(tsl2x7x_default_settings));
+       else
+               memcpy(&chip->tsl2x7x_settings,
+                      &tsl2x7x_default_settings,
+                      sizeof(tsl2x7x_default_settings));
+
+       /* Load up the proper lux table. */
+       if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
+               memcpy(chip->tsl2x7x_device_lux,
+                      chip->pdata->platform_lux_table,
+                      sizeof(chip->pdata->platform_lux_table));
+       else
+               memcpy(chip->tsl2x7x_device_lux,
+               (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
+                               MAX_DEFAULT_TABLE_BYTES);
+}
+
+/**
+ * tsl2x7x_als_calibrate() -   Obtain single reading and calculate
+ *                              the als_gain_trim.
+ *
+ * @indio_dev: pointer to IIO device
+ */
+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));
+       if (ret < 0) {
+               dev_err(&chip->client->dev,
+                       "failed to write CNTRL register, ret=%d\n", ret);
+               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) {
+               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) {
+               dev_err(&chip->client->dev,
+                       "%s: failed: STATUS - ADC not valid.\n", __func__);
+               return -ENODATA;
+       }
+
+       lux_val = tsl2x7x_get_lux(indio_dev);
+       if (lux_val < 0) {
+               dev_err(&chip->client->dev,
+                       "%s: failed to get lux\n", __func__);
+               return lux_val;
+       }
+
+       gain_trim_val =  ((chip->tsl2x7x_settings.als_cal_target)
+                       * chip->tsl2x7x_settings.als_gain_trim) / lux_val;
+       if ((gain_trim_val < 250) || (gain_trim_val > 4000))
+               return -ERANGE;
+
+       chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
+       dev_info(&chip->client->dev,
+                "%s als_calibrate completed\n", chip->client->name);
+
+       return (int)gain_trim_val;
+}
+
+static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
+{
+       int i;
+       int ret = 0;
+       u8 *dev_reg;
+       u8 utmp;
+       int als_count;
+       int als_time;
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       u8 reg_val = 0;
+
+       if (chip->pdata && chip->pdata->power_on)
+               chip->pdata->power_on(indio_dev);
+
+       /* Non calculated parameters */
+       chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
+                       chip->tsl2x7x_settings.prx_time;
+       chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
+                       chip->tsl2x7x_settings.wait_time;
+       chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
+                       chip->tsl2x7x_settings.prox_config;
+
+       chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
+               (chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
+               (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
+               (chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
+               (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
+               chip->tsl2x7x_settings.persistence;
+
+       chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
+                       chip->tsl2x7x_settings.prox_pulse_count;
+       chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
+                       (chip->tsl2x7x_settings.prox_thres_low) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] =
+                       (chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
+                       (chip->tsl2x7x_settings.prox_thres_high) & 0xFF;
+       chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] =
+                       (chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF;
+
+       /* and make sure we're not already on */
+       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+               /* if forcing a register update - turn off, then on */
+               dev_info(&chip->client->dev, "device is already enabled\n");
+               return -EINVAL;
+       }
+
+       /* determine als integration register */
+       als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
+       if (!als_count)
+               als_count = 1; /* ensure at least one cycle */
+
+       /* convert back to time (encompasses overrides) */
+       als_time = (als_count * 27 + 5) / 10;
+       chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
+
+       /* Set the gain based on tsl2x7x_settings struct */
+       chip->tsl2x7x_config[TSL2X7X_GAIN] =
+               chip->tsl2x7x_settings.als_gain |
+                       (TSL2X7X_mA100 | TSL2X7X_DIODE1)
+                       | ((chip->tsl2x7x_settings.prox_gain) << 2);
+
+       /* set chip struct re scaling and saturation */
+       chip->als_saturation = als_count * 922; /* 90% of full scale */
+       chip->als_time_scale = (als_time + 25) / 50;
+
+       /*
+        * TSL2X7X Specific power-on / adc enable sequence
+        * Power on the device 1st.
+        */
+       utmp = TSL2X7X_CNTL_PWR_ON;
+       ret = i2c_smbus_write_byte_data(chip->client,
+                                       TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+       if (ret < 0) {
+               dev_err(&chip->client->dev,
+                       "%s: failed on CNTRL reg.\n", __func__);
+               return ret;
+       }
+
+       /*
+        * Use the following shadow copy for our delay before enabling ADC.
+        * Write all the registers.
+        */
+       for (i = 0, dev_reg = chip->tsl2x7x_config;
+                       i < TSL2X7X_MAX_CONFIG_REG; i++) {
+               ret = i2c_smbus_write_byte_data(chip->client,
+                                               TSL2X7X_CMD_REG + i,
+                                               *dev_reg++);
+               if (ret < 0) {
+                       dev_err(&chip->client->dev,
+                               "failed on write to reg %d.\n", i);
+                       return ret;
+               }
+       }
+
+       mdelay(3);      /* Power-on settling time */
+
+       /*
+        * NOW enable the ADC
+        * initialize the desired mode of operation
+        */
+       utmp = TSL2X7X_CNTL_PWR_ON |
+                       TSL2X7X_CNTL_ADC_ENBL |
+                       TSL2X7X_CNTL_PROX_DET_ENBL;
+       ret = i2c_smbus_write_byte_data(chip->client,
+                                       TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+       if (ret < 0) {
+               dev_err(&chip->client->dev,
+                       "%s: failed on 2nd CTRL reg.\n", __func__);
+               return ret;
+       }
+
+       chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
+
+       if (chip->tsl2x7x_settings.interrupts_en != 0) {
+               dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
+
+               reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
+               if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
+                   (chip->tsl2x7x_settings.interrupts_en == 0x30))
+                       reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
+
+               reg_val |= chip->tsl2x7x_settings.interrupts_en;
+               ret = i2c_smbus_write_byte_data(chip->client,
+                                               (TSL2X7X_CMD_REG |
+                                               TSL2X7X_CNTRL), reg_val);
+               if (ret < 0)
+                       dev_err(&chip->client->dev,
+                               "%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
+                               __func__);
+
+               /* Clear out any initial interrupts  */
+               ret = i2c_smbus_write_byte(chip->client,
+                                          TSL2X7X_CMD_REG |
+                                          TSL2X7X_CMD_SPL_FN |
+                                          TSL2X7X_CMD_PROXALS_INT_CLR);
+               if (ret < 0) {
+                       dev_err(&chip->client->dev,
+                               "%s: Failed to clear Int status\n",
+                               __func__);
+               return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+       /* turn device off */
+       chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+
+       ret = i2c_smbus_write_byte_data(chip->client,
+                                       TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
+
+       if (chip->pdata && chip->pdata->power_off)
+               chip->pdata->power_off(chip->client);
+
+       return ret;
+}
+
+/**
+ * tsl2x7x_invoke_change
+ * @indio_dev: pointer to IIO device
+ *
+ * Obtain and lock both ALS and PROX resources,
+ * determine and save device state (On/Off),
+ * cycle device to implement updated parameter,
+ * put device back into proper state, and unlock
+ * resource.
+ */
+static
+int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
+{
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int device_status = chip->tsl2x7x_chip_status;
+
+       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)
+               tsl2x7x_chip_off(indio_dev);
+
+       mutex_unlock(&chip->prox_mutex);
+       mutex_unlock(&chip->als_mutex);
+
+       return 0;
+}
+
+static
+void tsl2x7x_prox_calculate(int *data, int length,
+                           struct tsl2x7x_prox_stat *statP)
+{
+       int i;
+       int sample_sum;
+       int tmp;
+
+       if (!length)
+               length = 1;
+
+       sample_sum = 0;
+       statP->min = INT_MAX;
+       statP->max = INT_MIN;
+       for (i = 0; i < length; i++) {
+               sample_sum += data[i];
+               statP->min = min(statP->min, data[i]);
+               statP->max = max(statP->max, data[i]);
+       }
+
+       statP->mean = sample_sum / length;
+       sample_sum = 0;
+       for (i = 0; i < length; i++) {
+               tmp = data[i] - statP->mean;
+               sample_sum += tmp * tmp;
+       }
+       statP->stddev = int_sqrt((long)sample_sum / length);
+}
+
+/**
+ * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
+ * @indio_dev: pointer to IIO device
+ *
+ * Calculates a standard deviation based on the samples,
+ * and sets the threshold accordingly.
+ */
+static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
+{
+       int prox_history[MAX_SAMPLES_CAL + 1];
+       int i;
+       struct tsl2x7x_prox_stat prox_stat_data[2];
+       struct tsl2x7x_prox_stat *calP;
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       u8 tmp_irq_settings;
+       u8 current_state = chip->tsl2x7x_chip_status;
+
+       if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
+               dev_err(&chip->client->dev,
+                       "max prox samples cal is too big: %d\n",
+                       chip->tsl2x7x_settings.prox_max_samples_cal);
+               chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
+       }
+
+       /* have to stop to change settings */
+       tsl2x7x_chip_off(indio_dev);
+
+       /* Enable proximity detection save just in case prox not wanted yet*/
+       tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
+       chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
+
+       /*turn on device if not already on*/
+       tsl2x7x_chip_on(indio_dev);
+
+       /*gather the samples*/
+       for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
+               mdelay(15);
+               tsl2x7x_get_prox(indio_dev);
+               prox_history[i] = chip->prox_data;
+               dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
+                        i, chip->prox_data);
+       }
+
+       tsl2x7x_chip_off(indio_dev);
+       calP = &prox_stat_data[PROX_STAT_CAL];
+       tsl2x7x_prox_calculate(prox_history,
+                              chip->tsl2x7x_settings.prox_max_samples_cal,
+                              calP);
+       chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
+
+       dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
+                calP->min, calP->mean, calP->max);
+       dev_info(&chip->client->dev,
+                "%s proximity threshold set to %d\n",
+                chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
+
+       /* back to the way they were */
+       chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
+       if (current_state == TSL2X7X_CHIP_WORKING)
+               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)
+{
+       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+       switch (chip->id) {
+       case tsl2571:
+       case tsl2671:
+       case tmd2671:
+       case tsl2771:
+       case tmd2771:
+               return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
+       }
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
+}
+
+static ssize_t in_proximity0_calibscale_available_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+               return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
+}
+
+static ssize_t in_illuminance0_integration_time_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+       int y, z;
+
+       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+       z = y * TSL2X7X_MIN_ITIME;
+       y /= 1000;
+       z %= 1000;
+
+       return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t in_illuminance0_integration_time_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t len)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       struct tsl2x7x_parse_result result;
+       int ret;
+
+       ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
+       if (ret)
+               return ret;
+
+       result.fract /= 3;
+       chip->tsl2x7x_settings.als_time =
+                       TSL2X7X_MAX_TIMER_CNT - (u8)result.fract;
+
+       dev_info(&chip->client->dev, "%s: als time = %d",
+                __func__, chip->tsl2x7x_settings.als_time);
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
+               ".00272 - .696");
+
+static ssize_t in_illuminance0_target_input_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_settings.als_cal_target);
+}
+
+static ssize_t in_illuminance0_target_input_store(struct device *dev,
+                                           struct device_attribute *attr,
+                                           const char *buf, size_t len)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       unsigned long value;
+
+       if (kstrtoul(buf, 0, &value))
+               return -EINVAL;
+
+       if (value)
+               chip->tsl2x7x_settings.als_cal_target = value;
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return len;
+}
+
+/* persistence settings */
+static ssize_t in_intensity0_thresh_period_show(struct device *dev,
+                                           struct device_attribute *attr,
+                                           char *buf)
+{
+       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+       int y, z, filter_delay;
+
+       /* Determine integration time */
+       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+       z = y * TSL2X7X_MIN_ITIME;
+       filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
+       y = filter_delay / 1000;
+       z = filter_delay % 1000;
+
+       return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t in_intensity0_thresh_period_store(struct device *dev,
+                                            struct device_attribute *attr,
+                                            const char *buf, size_t len)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       struct tsl2x7x_parse_result result;
+       int y, z, filter_delay;
+       int ret;
+
+       ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
+       if (ret)
+               return ret;
+
+       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+       z = y * TSL2X7X_MIN_ITIME;
+
+       filter_delay =
+               DIV_ROUND_UP((result.integer * 1000) + result.fract, z);
+
+       chip->tsl2x7x_settings.persistence &= 0xF0;
+       chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
+
+       dev_info(&chip->client->dev, "%s: als persistence = %d",
+                __func__, filter_delay);
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t in_proximity0_thresh_period_show(struct device *dev,
+                                            struct device_attribute *attr,
+                                            char *buf)
+{
+       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+       int y, z, filter_delay;
+
+       /* Determine integration time */
+       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+       z = y * TSL2X7X_MIN_ITIME;
+       filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
+       y = filter_delay / 1000;
+       z = filter_delay % 1000;
+
+       return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t in_proximity0_thresh_period_store(struct device *dev,
+                                             struct device_attribute *attr,
+                                             const char *buf, size_t len)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       struct tsl2x7x_parse_result result;
+       int y, z, filter_delay;
+       int ret;
+
+       ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
+       if (ret)
+               return ret;
+
+       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+       z = y * TSL2X7X_MIN_ITIME;
+
+       filter_delay =
+               DIV_ROUND_UP((result.integer * 1000) + result.fract, z);
+
+       chip->tsl2x7x_settings.persistence &= 0x0F;
+       chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
+
+       dev_info(&chip->client->dev, "%s: prox persistence = %d",
+                __func__, filter_delay);
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t in_illuminance0_calibrate_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_als_calibrate(indio_dev);
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return len;
+}
+
+static ssize_t in_illuminance0_lux_table_show(struct device *dev,
+                                    struct device_attribute *attr,
+                                    char *buf)
+{
+       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+       int i = 0;
+       int offset = 0;
+
+       while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
+               offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
+                       chip->tsl2x7x_device_lux[i].ratio,
+                       chip->tsl2x7x_device_lux[i].ch0,
+                       chip->tsl2x7x_device_lux[i].ch1);
+               if (chip->tsl2x7x_device_lux[i].ratio == 0) {
+                       /*
+                        * We just printed the first "0" entry.
+                        * Now get rid of the extra "," and break.
+                        */
+                       offset--;
+                       break;
+               }
+               i++;
+       }
+
+       offset += snprintf(buf + offset, PAGE_SIZE, "\n");
+       return offset;
+}
+
+static ssize_t in_illuminance0_lux_table_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t len)
+{
+       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;
+
+       get_options(buf, ARRAY_SIZE(value), value);
+
+       /* We now have an array of ints starting at value[1], and
+        * enumerated by value[0].
+        * We expect each group of three ints is one table entry,
+        * and the last table entry is all 0.
+        */
+       n = value[0];
+       if ((n % 3) || n < 6 ||
+           n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
+               dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
+               return -EINVAL;
+       }
+
+       if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
+               dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
+               return -EINVAL;
+       }
+
+       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
+               tsl2x7x_chip_off(indio_dev);
+
+       /* Zero out the table */
+       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);
+
+       return len;
+}
+
+static ssize_t in_proximity0_calibrate_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_prox_cal(indio_dev);
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return len;
+}
+
+static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
+                                        const struct iio_chan_spec *chan,
+                                        enum iio_event_type type,
+                                        enum iio_event_direction dir)
+{
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int ret;
+
+       if (chan->type == IIO_INTENSITY)
+               ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
+       else
+               ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
+
+       return ret;
+}
+
+static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
+                                         const struct iio_chan_spec *chan,
+                                         enum iio_event_type type,
+                                         enum iio_event_direction dir,
+                                         int val)
+{
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+       if (chan->type == IIO_INTENSITY) {
+               if (val)
+                       chip->tsl2x7x_settings.interrupts_en |= 0x10;
+               else
+                       chip->tsl2x7x_settings.interrupts_en &= 0x20;
+       } else {
+               if (val)
+                       chip->tsl2x7x_settings.interrupts_en |= 0x20;
+               else
+                       chip->tsl2x7x_settings.interrupts_en &= 0x10;
+       }
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       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)
+{
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+       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;
+               }
+       }
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return 0;
+}
+
+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)
+{
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+       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;
+               }
+       }
+
+       return IIO_VAL_INT;
+}
+
+static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val,
+                           int *val2,
+                           long mask)
+{
+       int ret = -EINVAL;
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_PROCESSED:
+               switch (chan->type) {
+               case IIO_LIGHT:
+                       tsl2x7x_get_lux(indio_dev);
+                       *val = chip->als_cur_info.lux;
+                       ret = IIO_VAL_INT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_CHAN_INFO_RAW:
+               switch (chan->type) {
+               case IIO_INTENSITY:
+                       tsl2x7x_get_lux(indio_dev);
+                       if (chan->channel == 0)
+                               *val = chip->als_cur_info.als_ch0;
+                       else
+                               *val = chip->als_cur_info.als_ch1;
+                       ret = IIO_VAL_INT;
+                       break;
+               case IIO_PROXIMITY:
+                       tsl2x7x_get_prox(indio_dev);
+                       *val = chip->prox_data;
+                       ret = IIO_VAL_INT;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBSCALE:
+               if (chan->type == IIO_LIGHT)
+                       *val =
+                       tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
+               else
+                       *val =
+                       tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               *val = chip->tsl2x7x_settings.als_gain_trim;
+               ret = IIO_VAL_INT;
+               break;
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val,
+                            int val2,
+                            long mask)
+{
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_CALIBSCALE:
+               if (chan->type == IIO_INTENSITY) {
+                       switch (val) {
+                       case 1:
+                               chip->tsl2x7x_settings.als_gain = 0;
+                               break;
+                       case 8:
+                               chip->tsl2x7x_settings.als_gain = 1;
+                               break;
+                       case 16:
+                               chip->tsl2x7x_settings.als_gain = 2;
+                               break;
+                       case 120:
+                               switch (chip->id) {
+                               case tsl2572:
+                               case tsl2672:
+                               case tmd2672:
+                               case tsl2772:
+                               case tmd2772:
+                                       return -EINVAL;
+                               }
+                               chip->tsl2x7x_settings.als_gain = 3;
+                               break;
+                       case 128:
+                               switch (chip->id) {
+                               case tsl2571:
+                               case tsl2671:
+                               case tmd2671:
+                               case tsl2771:
+                               case tmd2771:
+                                       return -EINVAL;
+                               }
+                               chip->tsl2x7x_settings.als_gain = 3;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               } else {
+                       switch (val) {
+                       case 1:
+                               chip->tsl2x7x_settings.prox_gain = 0;
+                               break;
+                       case 2:
+                               chip->tsl2x7x_settings.prox_gain = 1;
+                               break;
+                       case 4:
+                               chip->tsl2x7x_settings.prox_gain = 2;
+                               break;
+                       case 8:
+                               chip->tsl2x7x_settings.prox_gain = 3;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               chip->tsl2x7x_settings.als_gain_trim = val;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       tsl2x7x_invoke_change(indio_dev);
+
+       return 0;
+}
+
+static DEVICE_ATTR_RW(power_state);
+
+static DEVICE_ATTR_RO(in_proximity0_calibscale_available);
+
+static DEVICE_ATTR_RO(in_illuminance0_calibscale_available);
+
+static DEVICE_ATTR_RW(in_illuminance0_integration_time);
+
+static DEVICE_ATTR_RW(in_illuminance0_target_input);
+
+static DEVICE_ATTR_WO(in_illuminance0_calibrate);
+
+static DEVICE_ATTR_WO(in_proximity0_calibrate);
+
+static DEVICE_ATTR_RW(in_illuminance0_lux_table);
+
+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)
+{
+       switch (target) {
+       case tsl2571:
+       case tsl2671:
+       case tsl2771:
+               return (*id & 0xf0) == TRITON_ID;
+       case tmd2671:
+       case tmd2771:
+               return (*id & 0xf0) == HALIBUT_ID;
+       case tsl2572:
+       case tsl2672:
+       case tmd2672:
+       case tsl2772:
+       case tmd2772:
+               return (*id & 0xf0) == SWORDFISH_ID;
+       }
+
+       return -EINVAL;
+}
+
+static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       s64 timestamp = iio_get_time_ns(indio_dev);
+       int ret;
+       u8 value;
+
+       value = i2c_smbus_read_byte_data(chip->client,
+                                        TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+
+       /* What type of interrupt do we need to process */
+       if (value & TSL2X7X_STA_PRX_INTR) {
+               tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
+                                                   0,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_EITHER),
+                                                   timestamp);
+       }
+
+       if (value & TSL2X7X_STA_ALS_INTR) {
+               tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
+               iio_push_event(indio_dev,
+                              IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+                                                   0,
+                                                   IIO_EV_TYPE_THRESH,
+                                                   IIO_EV_DIR_EITHER),
+                              timestamp);
+       }
+       /* Clear interrupt now that we have handled it. */
+       ret = i2c_smbus_write_byte(chip->client,
+                                  TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+                                  TSL2X7X_CMD_PROXALS_INT_CLR);
+       if (ret < 0)
+               dev_err(&chip->client->dev,
+                       "Failed to clear irq from event handler. err = %d\n",
+                       ret);
+
+       return IRQ_HANDLED;
+}
+
+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,
+       &dev_attr_in_illuminance0_target_input.attr,
+       &dev_attr_in_illuminance0_calibrate.attr,
+       &dev_attr_in_illuminance0_lux_table.attr,
+       NULL
+};
+
+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,
+       &dev_attr_in_illuminance0_target_input.attr,
+       &dev_attr_in_illuminance0_calibrate.attr,
+       &dev_attr_in_illuminance0_lux_table.attr,
+       &dev_attr_in_proximity0_calibrate.attr,
+       NULL
+};
+
+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,
+       &dev_attr_in_illuminance0_target_input.attr,
+       &dev_attr_in_illuminance0_calibrate.attr,
+       &dev_attr_in_illuminance0_lux_table.attr,
+       &dev_attr_in_proximity0_calibrate.attr,
+       &dev_attr_in_proximity0_calibscale_available.attr,
+       NULL
+};
+
+static struct attribute *tsl2X7X_ALS_event_attrs[] = {
+       &dev_attr_in_intensity0_thresh_period.attr,
+       NULL,
+};
+
+static struct attribute *tsl2X7X_PRX_event_attrs[] = {
+       &dev_attr_in_proximity0_thresh_period.attr,
+       NULL,
+};
+
+static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = {
+       &dev_attr_in_intensity0_thresh_period.attr,
+       &dev_attr_in_proximity0_thresh_period.attr,
+       NULL,
+};
+
+static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
+       [ALS] = {
+               .attrs = tsl2x7x_ALS_device_attrs,
+       },
+       [PRX] = {
+               .attrs = tsl2x7x_PRX_device_attrs,
+       },
+       [ALSPRX] = {
+               .attrs = tsl2x7x_ALSPRX_device_attrs,
+       },
+       [PRX2] = {
+               .attrs = tsl2x7x_PRX2_device_attrs,
+       },
+       [ALSPRX2] = {
+               .attrs = tsl2x7x_ALSPRX2_device_attrs,
+       },
+};
+
+static const struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
+       [ALS] = {
+               .attrs = tsl2X7X_ALS_event_attrs,
+               .name = "events",
+       },
+       [PRX] = {
+               .attrs = tsl2X7X_PRX_event_attrs,
+               .name = "events",
+       },
+       [ALSPRX] = {
+               .attrs = tsl2X7X_ALSPRX_event_attrs,
+               .name = "events",
+       },
+};
+
+static const struct iio_info tsl2X7X_device_info[] = {
+       [ALS] = {
+               .attrs = &tsl2X7X_device_attr_group_tbl[ALS],
+               .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS],
+               .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_config = &tsl2x7x_read_interrupt_config,
+               .write_event_config = &tsl2x7x_write_interrupt_config,
+       },
+       [PRX] = {
+               .attrs = &tsl2X7X_device_attr_group_tbl[PRX],
+               .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+               .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_config = &tsl2x7x_read_interrupt_config,
+               .write_event_config = &tsl2x7x_write_interrupt_config,
+       },
+       [ALSPRX] = {
+               .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
+               .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+               .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_config = &tsl2x7x_read_interrupt_config,
+               .write_event_config = &tsl2x7x_write_interrupt_config,
+       },
+       [PRX2] = {
+               .attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
+               .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+               .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_config = &tsl2x7x_read_interrupt_config,
+               .write_event_config = &tsl2x7x_write_interrupt_config,
+       },
+       [ALSPRX2] = {
+               .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
+               .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+               .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_config = &tsl2x7x_read_interrupt_config,
+               .write_event_config = &tsl2x7x_write_interrupt_config,
+       },
+};
+
+static const struct iio_event_spec tsl2x7x_events[] = {
+       {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_RISING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+                       BIT(IIO_EV_INFO_ENABLE),
+       }, {
+               .type = IIO_EV_TYPE_THRESH,
+               .dir = IIO_EV_DIR_FALLING,
+               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+                       BIT(IIO_EV_INFO_ENABLE),
+       },
+};
+
+static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
+       [ALS] = {
+               .channel = {
+                       {
+                       .type = IIO_LIGHT,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+                       }, {
+                       .type = IIO_INTENSITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                               BIT(IIO_CHAN_INFO_CALIBSCALE) |
+                               BIT(IIO_CHAN_INFO_CALIBBIAS),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       }, {
+                       .type = IIO_INTENSITY,
+                       .indexed = 1,
+                       .channel = 1,
+                       },
+               },
+       .chan_table_elements = 3,
+       .info = &tsl2X7X_device_info[ALS],
+       },
+       [PRX] = {
+               .channel = {
+                       {
+                       .type = IIO_PROXIMITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       },
+               },
+       .chan_table_elements = 1,
+       .info = &tsl2X7X_device_info[PRX],
+       },
+       [ALSPRX] = {
+               .channel = {
+                       {
+                       .type = IIO_LIGHT,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED)
+                       }, {
+                       .type = IIO_INTENSITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                               BIT(IIO_CHAN_INFO_CALIBSCALE) |
+                               BIT(IIO_CHAN_INFO_CALIBBIAS),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       }, {
+                       .type = IIO_INTENSITY,
+                       .indexed = 1,
+                       .channel = 1,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       }, {
+                       .type = IIO_PROXIMITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       },
+               },
+       .chan_table_elements = 4,
+       .info = &tsl2X7X_device_info[ALSPRX],
+       },
+       [PRX2] = {
+               .channel = {
+                       {
+                       .type = IIO_PROXIMITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                               BIT(IIO_CHAN_INFO_CALIBSCALE),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       },
+               },
+       .chan_table_elements = 1,
+       .info = &tsl2X7X_device_info[PRX2],
+       },
+       [ALSPRX2] = {
+               .channel = {
+                       {
+                       .type = IIO_LIGHT,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+                       }, {
+                       .type = IIO_INTENSITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                               BIT(IIO_CHAN_INFO_CALIBSCALE) |
+                               BIT(IIO_CHAN_INFO_CALIBBIAS),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       }, {
+                       .type = IIO_INTENSITY,
+                       .indexed = 1,
+                       .channel = 1,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+                       }, {
+                       .type = IIO_PROXIMITY,
+                       .indexed = 1,
+                       .channel = 0,
+                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                               BIT(IIO_CHAN_INFO_CALIBSCALE),
+                       .event_spec = tsl2x7x_events,
+                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
+                       },
+               },
+       .chan_table_elements = 4,
+       .info = &tsl2X7X_device_info[ALSPRX2],
+       },
+};
+
+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;
+
+       indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       chip = iio_priv(indio_dev);
+       chip->client = clientp;
+       i2c_set_clientdata(clientp, indio_dev);
+
+       ret = tsl2x7x_i2c_read(chip->client,
+                              TSL2X7X_CHIPID, &device_id);
+       if (ret < 0)
+               return ret;
+
+       if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
+           (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
+               dev_info(&chip->client->dev,
+                        "%s: i2c device found does not match expected id\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+       if (ret < 0) {
+               dev_err(&clientp->dev, "write to cmd reg failed. err = %d\n",
+                       ret);
+               return ret;
+       }
+
+       /*
+        * ALS and PROX functions can be invoked via user space poll
+        * or H/W interrupt. If busy return last sample.
+        */
+       mutex_init(&chip->als_mutex);
+       mutex_init(&chip->prox_mutex);
+
+       chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
+       chip->pdata = dev_get_platdata(&clientp->dev);
+       chip->id = id->driver_data;
+       chip->chip_info =
+               &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
+
+       indio_dev->info = chip->chip_info->info;
+       indio_dev->dev.parent = &clientp->dev;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->name = chip->client->name;
+       indio_dev->channels = chip->chip_info->channel;
+       indio_dev->num_channels = chip->chip_info->chan_table_elements;
+
+       if (clientp->irq) {
+               ret = devm_request_threaded_irq(&clientp->dev, clientp->irq,
+                                               NULL,
+                                               &tsl2x7x_event_handler,
+                                               IRQF_TRIGGER_RISING |
+                                               IRQF_ONESHOT,
+                                               "TSL2X7X_event",
+                                               indio_dev);
+               if (ret) {
+                       dev_err(&clientp->dev,
+                               "%s: irq request failed", __func__);
+                       return ret;
+               }
+       }
+
+       /* Load up the defaults */
+       tsl2x7x_defaults(chip);
+       /* Make sure the chip is on */
+       tsl2x7x_chip_on(indio_dev);
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(&clientp->dev,
+                       "%s: iio registration failed\n", __func__);
+               return ret;
+       }
+
+       dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
+
+       return 0;
+}
+
+static int tsl2x7x_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int ret = 0;
+
+       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+               ret = tsl2x7x_chip_off(indio_dev);
+               chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+       }
+
+       if (chip->pdata && chip->pdata->platform_power) {
+               pm_message_t pmm = {PM_EVENT_SUSPEND};
+
+               chip->pdata->platform_power(dev, pmm);
+       }
+
+       return ret;
+}
+
+static int tsl2x7x_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+       int ret = 0;
+
+       if (chip->pdata && chip->pdata->platform_power) {
+               pm_message_t pmm = {PM_EVENT_RESUME};
+
+               chip->pdata->platform_power(dev, pmm);
+       }
+
+       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
+               ret = tsl2x7x_chip_on(indio_dev);
+
+       return ret;
+}
+
+static int tsl2x7x_remove(struct i2c_client *client)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+       tsl2x7x_chip_off(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       return 0;
+}
+
+static struct i2c_device_id tsl2x7x_idtable[] = {
+       { "tsl2571", tsl2571 },
+       { "tsl2671", tsl2671 },
+       { "tmd2671", tmd2671 },
+       { "tsl2771", tsl2771 },
+       { "tmd2771", tmd2771 },
+       { "tsl2572", tsl2572 },
+       { "tsl2672", tsl2672 },
+       { "tmd2672", tmd2672 },
+       { "tsl2772", tsl2772 },
+       { "tmd2772", tmd2772 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
+
+static const struct dev_pm_ops tsl2x7x_pm_ops = {
+       .suspend = tsl2x7x_suspend,
+       .resume  = tsl2x7x_resume,
+};
+
+/* Driver definition */
+static struct i2c_driver tsl2x7x_driver = {
+       .driver = {
+               .name = "tsl2x7x",
+               .pm = &tsl2x7x_pm_ops,
+       },
+       .id_table = tsl2x7x_idtable,
+       .probe = tsl2x7x_probe,
+       .remove = tsl2x7x_remove,
+};
+
+module_i2c_driver(tsl2x7x_driver);
+
+MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
+MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
deleted file mode 100644 (file)
index af3910b..0000000
+++ /dev/null
@@ -1,2063 +0,0 @@
-/*
- * Device driver for monitoring ambient light intensity in (lux)
- * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
- *
- * Copyright (c) 2012, TAOS Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA        02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/iio/events.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include "tsl2x7x.h"
-
-/* Cal defs*/
-#define PROX_STAT_CAL        0
-#define PROX_STAT_SAMP       1
-#define MAX_SAMPLES_CAL      200
-
-/* TSL2X7X Device ID */
-#define TRITON_ID    0x00
-#define SWORDFISH_ID 0x30
-#define HALIBUT_ID   0x20
-
-/* Lux calculation constants */
-#define TSL2X7X_LUX_CALC_OVER_FLOW     65535
-
-/* TAOS Register definitions - note:
- * depending on device, some of these register are not used and the
- * register address is benign.
- */
-/* 2X7X register offsets */
-#define TSL2X7X_MAX_CONFIG_REG         16
-
-/* Device Registers and Masks */
-#define TSL2X7X_CNTRL                  0x00
-#define TSL2X7X_ALS_TIME               0X01
-#define TSL2X7X_PRX_TIME               0x02
-#define TSL2X7X_WAIT_TIME              0x03
-#define TSL2X7X_ALS_MINTHRESHLO        0X04
-#define TSL2X7X_ALS_MINTHRESHHI        0X05
-#define TSL2X7X_ALS_MAXTHRESHLO        0X06
-#define TSL2X7X_ALS_MAXTHRESHHI        0X07
-#define TSL2X7X_PRX_MINTHRESHLO        0X08
-#define TSL2X7X_PRX_MINTHRESHHI        0X09
-#define TSL2X7X_PRX_MAXTHRESHLO        0X0A
-#define TSL2X7X_PRX_MAXTHRESHHI        0X0B
-#define TSL2X7X_PERSISTENCE            0x0C
-#define TSL2X7X_PRX_CONFIG             0x0D
-#define TSL2X7X_PRX_COUNT              0x0E
-#define TSL2X7X_GAIN                   0x0F
-#define TSL2X7X_NOTUSED                0x10
-#define TSL2X7X_REVID                  0x11
-#define TSL2X7X_CHIPID                 0x12
-#define TSL2X7X_STATUS                 0x13
-#define TSL2X7X_ALS_CHAN0LO            0x14
-#define TSL2X7X_ALS_CHAN0HI            0x15
-#define TSL2X7X_ALS_CHAN1LO            0x16
-#define TSL2X7X_ALS_CHAN1HI            0x17
-#define TSL2X7X_PRX_LO                 0x18
-#define TSL2X7X_PRX_HI                 0x19
-
-/* tsl2X7X cmd reg masks */
-#define TSL2X7X_CMD_REG                0x80
-#define TSL2X7X_CMD_SPL_FN             0x60
-
-#define TSL2X7X_CMD_PROX_INT_CLR       0X05
-#define TSL2X7X_CMD_ALS_INT_CLR        0x06
-#define TSL2X7X_CMD_PROXALS_INT_CLR    0X07
-
-/* tsl2X7X cntrl reg masks */
-#define TSL2X7X_CNTL_ADC_ENBL          0x02
-#define TSL2X7X_CNTL_PWR_ON            0x01
-
-/* tsl2X7X status reg masks */
-#define TSL2X7X_STA_ADC_VALID          0x01
-#define TSL2X7X_STA_PRX_VALID          0x02
-#define TSL2X7X_STA_ADC_PRX_VALID      (TSL2X7X_STA_ADC_VALID |\
-                                       TSL2X7X_STA_PRX_VALID)
-#define TSL2X7X_STA_ALS_INTR           0x10
-#define TSL2X7X_STA_PRX_INTR           0x20
-
-/* tsl2X7X cntrl reg masks */
-#define TSL2X7X_CNTL_REG_CLEAR         0x00
-#define TSL2X7X_CNTL_PROX_INT_ENBL     0X20
-#define TSL2X7X_CNTL_ALS_INT_ENBL      0X10
-#define TSL2X7X_CNTL_WAIT_TMR_ENBL     0X08
-#define TSL2X7X_CNTL_PROX_DET_ENBL     0X04
-#define TSL2X7X_CNTL_PWRON             0x01
-#define TSL2X7X_CNTL_ALSPON_ENBL       0x03
-#define TSL2X7X_CNTL_INTALSPON_ENBL    0x13
-#define TSL2X7X_CNTL_PROXPON_ENBL      0x0F
-#define TSL2X7X_CNTL_INTPROXPON_ENBL   0x2F
-
-/*Prox diode to use */
-#define TSL2X7X_DIODE0                 0x10
-#define TSL2X7X_DIODE1                 0x20
-#define TSL2X7X_DIODE_BOTH             0x30
-
-/* LED Power */
-#define TSL2X7X_mA100                  0x00
-#define TSL2X7X_mA50                   0x40
-#define TSL2X7X_mA25                   0x80
-#define TSL2X7X_mA13                   0xD0
-#define TSL2X7X_MAX_TIMER_CNT          (0xFF)
-
-#define TSL2X7X_MIN_ITIME 3
-
-/* TAOS txx2x7x Device family members */
-enum {
-       tsl2571,
-       tsl2671,
-       tmd2671,
-       tsl2771,
-       tmd2771,
-       tsl2572,
-       tsl2672,
-       tmd2672,
-       tsl2772,
-       tmd2772
-};
-
-enum {
-       TSL2X7X_CHIP_UNKNOWN = 0,
-       TSL2X7X_CHIP_WORKING = 1,
-       TSL2X7X_CHIP_SUSPENDED = 2
-};
-
-struct tsl2x7x_parse_result {
-       int integer;
-       int fract;
-};
-
-/* Per-device data */
-struct tsl2x7x_als_info {
-       u16 als_ch0;
-       u16 als_ch1;
-       u16 lux;
-};
-
-struct tsl2x7x_prox_stat {
-       int min;
-       int max;
-       int mean;
-       unsigned long stddev;
-};
-
-struct tsl2x7x_chip_info {
-       int chan_table_elements;
-       struct iio_chan_spec            channel[4];
-       const struct iio_info           *info;
-};
-
-struct tsl2X7X_chip {
-       kernel_ulong_t id;
-       struct mutex prox_mutex;
-       struct mutex als_mutex;
-       struct i2c_client *client;
-       u16 prox_data;
-       struct tsl2x7x_als_info als_cur_info;
-       struct tsl2x7x_settings tsl2x7x_settings;
-       struct tsl2X7X_platform_data *pdata;
-       int als_time_scale;
-       int als_saturation;
-       int tsl2x7x_chip_status;
-       u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
-       const struct tsl2x7x_chip_info  *chip_info;
-       const struct iio_info *info;
-       s64 event_timestamp;
-       /*
-        * This structure is intentionally large to accommodate
-        * updates via sysfs.
-        * Sized to 9 = max 8 segments + 1 termination segment
-        */
-       struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
-};
-
-/* Different devices require different coefficents */
-static const struct tsl2x7x_lux tsl2x71_lux_table[] = {
-       { 14461,   611,   1211 },
-       { 18540,   352,    623 },
-       {     0,     0,      0 },
-};
-
-static const struct tsl2x7x_lux tmd2x71_lux_table[] = {
-       { 11635,   115,    256 },
-       { 15536,    87,    179 },
-       {     0,     0,      0 },
-};
-
-static const struct tsl2x7x_lux tsl2x72_lux_table[] = {
-       { 14013,   466,   917 },
-       { 18222,   310,   552 },
-       {     0,     0,     0 },
-};
-
-static const struct tsl2x7x_lux tmd2x72_lux_table[] = {
-       { 13218,   130,   262 },
-       { 17592,   92,    169 },
-       {     0,     0,     0 },
-};
-
-static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
-       [tsl2571] =     tsl2x71_lux_table,
-       [tsl2671] =     tsl2x71_lux_table,
-       [tmd2671] =     tmd2x71_lux_table,
-       [tsl2771] =     tsl2x71_lux_table,
-       [tmd2771] =     tmd2x71_lux_table,
-       [tsl2572] =     tsl2x72_lux_table,
-       [tsl2672] =     tsl2x72_lux_table,
-       [tmd2672] =     tmd2x72_lux_table,
-       [tsl2772] =     tsl2x72_lux_table,
-       [tmd2772] =     tmd2x72_lux_table,
-};
-
-static const struct tsl2x7x_settings tsl2x7x_default_settings = {
-       .als_time = 219, /* 101 ms */
-       .als_gain = 0,
-       .prx_time = 254, /* 5.4 ms */
-       .prox_gain = 1,
-       .wait_time = 245,
-       .prox_config = 0,
-       .als_gain_trim = 1000,
-       .als_cal_target = 150,
-       .als_thresh_low = 200,
-       .als_thresh_high = 256,
-       .persistence = 255,
-       .interrupts_en = 0,
-       .prox_thres_low  = 0,
-       .prox_thres_high = 512,
-       .prox_max_samples_cal = 30,
-       .prox_pulse_count = 8
-};
-
-static const s16 tsl2X7X_als_gainadj[] = {
-       1,
-       8,
-       16,
-       120
-};
-
-static const s16 tsl2X7X_prx_gainadj[] = {
-       1,
-       2,
-       4,
-       8
-};
-
-/* Channel variations */
-enum {
-       ALS,
-       PRX,
-       ALSPRX,
-       PRX2,
-       ALSPRX2,
-};
-
-static const u8 device_channel_config[] = {
-       ALS,
-       PRX,
-       PRX,
-       ALSPRX,
-       ALSPRX,
-       ALS,
-       PRX2,
-       PRX2,
-       ALSPRX2,
-       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
- *
- * The raw ch0 and ch1 values of the ambient light sensed in the last
- * integration cycle are read from the device.
- * Time scale factor array values are adjusted based on the integration time.
- * The raw values are multiplied by a scale factor, and device gain is obtained
- * using gain index. Limit checks are done next, then the ratio of a multiple
- * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
- * is then scanned to find the first ratio value that is just above the ratio
- * we just calculated. The ch0 and ch1 multiplier constants in the array are
- * then used along with the time scale factor array values, to calculate the
- * lux.
- */
-static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
-{
-       u16 ch0, ch1; /* separated ch0/ch1 data from device */
-       u32 lux; /* raw lux calculated from device data */
-       u64 lux64;
-       u32 ratio;
-       u8 buf[4];
-       struct tsl2x7x_lux *p;
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       int i, ret;
-       u32 ch0lux = 0;
-       u32 ch1lux = 0;
-
-       if (mutex_trylock(&chip->als_mutex) == 0)
-               return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
-
-       if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
-               /* device is not enabled */
-               dev_err(&chip->client->dev, "%s: device is not enabled\n",
-                       __func__);
-               ret = -EBUSY;
-               goto out_unlock;
-       }
-
-       ret = tsl2x7x_i2c_read(chip->client,
-                              (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
-       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)) {
-               dev_err(&chip->client->dev,
-                       "%s: data not valid yet\n", __func__);
-               ret = chip->als_cur_info.lux; /* return LAST VALUE */
-               goto out_unlock;
-       }
-
-       for (i = 0; i < 4; i++) {
-               ret = tsl2x7x_i2c_read(chip->client,
-                                      (TSL2X7X_CMD_REG |
-                                      (TSL2X7X_ALS_CHAN0LO + i)), &buf[i]);
-               if (ret < 0) {
-                       dev_err(&chip->client->dev,
-                               "failed to read. err=%x\n", ret);
-                       goto out_unlock;
-               }
-       }
-
-       /* clear any existing interrupt status */
-       ret = i2c_smbus_write_byte(chip->client,
-                                  (TSL2X7X_CMD_REG |
-                                  TSL2X7X_CMD_SPL_FN |
-                                  TSL2X7X_CMD_ALS_INT_CLR));
-       if (ret < 0) {
-               dev_err(&chip->client->dev,
-                       "i2c_write_command failed - err = %d\n", ret);
-               goto out_unlock; /* have no data, so return failure */
-       }
-
-       /* extract ALS/lux data */
-       ch0 = le16_to_cpup((const __le16 *)&buf[0]);
-       ch1 = le16_to_cpup((const __le16 *)&buf[2]);
-
-       chip->als_cur_info.als_ch0 = ch0;
-       chip->als_cur_info.als_ch1 = ch1;
-
-       if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) {
-               lux = TSL2X7X_LUX_CALC_OVER_FLOW;
-               goto return_max;
-       }
-
-       if (!ch0) {
-               /* have no data, so return LAST VALUE */
-               ret = chip->als_cur_info.lux;
-               goto out_unlock;
-       }
-       /* calculate ratio */
-       ratio = (ch1 << 15) / ch0;
-       /* convert to unscaled lux using the pointer to the table */
-       p = (struct tsl2x7x_lux *)chip->tsl2x7x_device_lux;
-       while (p->ratio != 0 && p->ratio < ratio)
-               p++;
-
-       if (p->ratio == 0) {
-               lux = 0;
-       } else {
-               ch0lux = DIV_ROUND_UP(ch0 * p->ch0,
-                       tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
-               ch1lux = DIV_ROUND_UP(ch1 * p->ch1,
-                       tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
-               lux = ch0lux - ch1lux;
-       }
-
-       /* note: lux is 31 bit max at this point */
-       if (ch1lux > ch0lux) {
-               dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
-               ret = chip->als_cur_info.lux;
-               goto out_unlock;
-       }
-
-       /* adjust for active time scale */
-       if (chip->als_time_scale == 0)
-               lux = 0;
-       else
-               lux = (lux + (chip->als_time_scale >> 1)) /
-                       chip->als_time_scale;
-
-       /* adjust for active gain scale
-        * The tsl2x7x_device_lux tables have a factor of 256 built-in.
-        * User-specified gain provides a multiplier.
-        * Apply user-specified gain before shifting right to retain precision.
-        * Use 64 bits to avoid overflow on multiplication.
-        * Then go back to 32 bits before division to avoid using div_u64().
-        */
-
-       lux64 = lux;
-       lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
-       lux64 >>= 8;
-       lux = lux64;
-       lux = (lux + 500) / 1000;
-
-       if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
-               lux = TSL2X7X_LUX_CALC_OVER_FLOW;
-
-       /* Update the structure with the latest lux. */
-return_max:
-       chip->als_cur_info.lux = lux;
-       ret = lux;
-
-out_unlock:
-       mutex_unlock(&chip->als_mutex);
-
-       return ret;
-}
-
-/**
- * tsl2x7x_get_prox() - Reads proximity data registers and updates
- *                      chip->prox_data.
- *
- * @indio_dev: pointer to IIO device
- */
-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);
-
-       if (mutex_trylock(&chip->prox_mutex) == 0) {
-               dev_err(&chip->client->dev,
-                       "%s: Can't get prox mutex\n", __func__);
-               return -EBUSY;
-       }
-
-       ret = tsl2x7x_i2c_read(chip->client,
-                              (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
-       if (ret < 0) {
-               dev_err(&chip->client->dev, "i2c err=%d\n", ret);
-               goto prox_poll_err;
-       }
-
-       switch (chip->id) {
-       case tsl2571:
-       case tsl2671:
-       case tmd2671:
-       case tsl2771:
-       case tmd2771:
-               if (!(status & TSL2X7X_STA_ADC_VALID))
-                       goto prox_poll_err;
-       break;
-       case tsl2572:
-       case tsl2672:
-       case tmd2672:
-       case tsl2772:
-       case tmd2772:
-               if (!(status & 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]);
-               if (ret < 0)
-                       goto prox_poll_err;
-       }
-
-       chip->prox_data =
-                       le16_to_cpup((const __le16 *)&chdata[0]);
-
-prox_poll_err:
-
-       mutex_unlock(&chip->prox_mutex);
-
-       return chip->prox_data;
-}
-
-/**
- * tsl2x7x_defaults() - Populates the device nominal operating parameters
- *                      with those provided by a 'platform' data struct or
- *                      with prefined defaults.
- *
- * @chip:               pointer to device structure.
- */
-static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
-{
-       /* If Operational settings defined elsewhere.. */
-       if (chip->pdata && chip->pdata->platform_default_settings)
-               memcpy(&chip->tsl2x7x_settings,
-                      chip->pdata->platform_default_settings,
-                      sizeof(tsl2x7x_default_settings));
-       else
-               memcpy(&chip->tsl2x7x_settings,
-                      &tsl2x7x_default_settings,
-                      sizeof(tsl2x7x_default_settings));
-
-       /* Load up the proper lux table. */
-       if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
-               memcpy(chip->tsl2x7x_device_lux,
-                      chip->pdata->platform_lux_table,
-                      sizeof(chip->pdata->platform_lux_table));
-       else
-               memcpy(chip->tsl2x7x_device_lux,
-               (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
-                               MAX_DEFAULT_TABLE_BYTES);
-}
-
-/**
- * tsl2x7x_als_calibrate() -   Obtain single reading and calculate
- *                              the als_gain_trim.
- *
- * @indio_dev: pointer to IIO device
- */
-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));
-       if (ret < 0) {
-               dev_err(&chip->client->dev,
-                       "failed to write CNTRL register, ret=%d\n", ret);
-               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) {
-               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) {
-               dev_err(&chip->client->dev,
-                       "%s: failed: STATUS - ADC not valid.\n", __func__);
-               return -ENODATA;
-       }
-
-       lux_val = tsl2x7x_get_lux(indio_dev);
-       if (lux_val < 0) {
-               dev_err(&chip->client->dev,
-                       "%s: failed to get lux\n", __func__);
-               return lux_val;
-       }
-
-       gain_trim_val =  ((chip->tsl2x7x_settings.als_cal_target)
-                       * chip->tsl2x7x_settings.als_gain_trim) / lux_val;
-       if ((gain_trim_val < 250) || (gain_trim_val > 4000))
-               return -ERANGE;
-
-       chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
-       dev_info(&chip->client->dev,
-                "%s als_calibrate completed\n", chip->client->name);
-
-       return (int)gain_trim_val;
-}
-
-static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
-{
-       int i;
-       int ret = 0;
-       u8 *dev_reg;
-       u8 utmp;
-       int als_count;
-       int als_time;
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       u8 reg_val = 0;
-
-       if (chip->pdata && chip->pdata->power_on)
-               chip->pdata->power_on(indio_dev);
-
-       /* Non calculated parameters */
-       chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
-                       chip->tsl2x7x_settings.prx_time;
-       chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
-                       chip->tsl2x7x_settings.wait_time;
-       chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
-                       chip->tsl2x7x_settings.prox_config;
-
-       chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
-               (chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
-               (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
-               (chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
-               (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
-               chip->tsl2x7x_settings.persistence;
-
-       chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
-                       chip->tsl2x7x_settings.prox_pulse_count;
-       chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
-                       (chip->tsl2x7x_settings.prox_thres_low) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHHI] =
-                       (chip->tsl2x7x_settings.prox_thres_low >> 8) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
-                       (chip->tsl2x7x_settings.prox_thres_high) & 0xFF;
-       chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHHI] =
-                       (chip->tsl2x7x_settings.prox_thres_high >> 8) & 0xFF;
-
-       /* and make sure we're not already on */
-       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
-               /* if forcing a register update - turn off, then on */
-               dev_info(&chip->client->dev, "device is already enabled\n");
-               return -EINVAL;
-       }
-
-       /* determine als integration register */
-       als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
-       if (!als_count)
-               als_count = 1; /* ensure at least one cycle */
-
-       /* convert back to time (encompasses overrides) */
-       als_time = (als_count * 27 + 5) / 10;
-       chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
-
-       /* Set the gain based on tsl2x7x_settings struct */
-       chip->tsl2x7x_config[TSL2X7X_GAIN] =
-               chip->tsl2x7x_settings.als_gain |
-                       (TSL2X7X_mA100 | TSL2X7X_DIODE1)
-                       | ((chip->tsl2x7x_settings.prox_gain) << 2);
-
-       /* set chip struct re scaling and saturation */
-       chip->als_saturation = als_count * 922; /* 90% of full scale */
-       chip->als_time_scale = (als_time + 25) / 50;
-
-       /*
-        * TSL2X7X Specific power-on / adc enable sequence
-        * Power on the device 1st.
-        */
-       utmp = TSL2X7X_CNTL_PWR_ON;
-       ret = i2c_smbus_write_byte_data(chip->client,
-                                       TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
-       if (ret < 0) {
-               dev_err(&chip->client->dev,
-                       "%s: failed on CNTRL reg.\n", __func__);
-               return ret;
-       }
-
-       /*
-        * Use the following shadow copy for our delay before enabling ADC.
-        * Write all the registers.
-        */
-       for (i = 0, dev_reg = chip->tsl2x7x_config;
-                       i < TSL2X7X_MAX_CONFIG_REG; i++) {
-               ret = i2c_smbus_write_byte_data(chip->client,
-                                               TSL2X7X_CMD_REG + i,
-                                               *dev_reg++);
-               if (ret < 0) {
-                       dev_err(&chip->client->dev,
-                               "failed on write to reg %d.\n", i);
-                       return ret;
-               }
-       }
-
-       mdelay(3);      /* Power-on settling time */
-
-       /*
-        * NOW enable the ADC
-        * initialize the desired mode of operation
-        */
-       utmp = TSL2X7X_CNTL_PWR_ON |
-                       TSL2X7X_CNTL_ADC_ENBL |
-                       TSL2X7X_CNTL_PROX_DET_ENBL;
-       ret = i2c_smbus_write_byte_data(chip->client,
-                                       TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
-       if (ret < 0) {
-               dev_err(&chip->client->dev,
-                       "%s: failed on 2nd CTRL reg.\n", __func__);
-               return ret;
-       }
-
-       chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
-
-       if (chip->tsl2x7x_settings.interrupts_en != 0) {
-               dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
-
-               reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
-               if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
-                   (chip->tsl2x7x_settings.interrupts_en == 0x30))
-                       reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
-
-               reg_val |= chip->tsl2x7x_settings.interrupts_en;
-               ret = i2c_smbus_write_byte_data(chip->client,
-                                               (TSL2X7X_CMD_REG |
-                                               TSL2X7X_CNTRL), reg_val);
-               if (ret < 0)
-                       dev_err(&chip->client->dev,
-                               "%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
-                               __func__);
-
-               /* Clear out any initial interrupts  */
-               ret = i2c_smbus_write_byte(chip->client,
-                                          TSL2X7X_CMD_REG |
-                                          TSL2X7X_CMD_SPL_FN |
-                                          TSL2X7X_CMD_PROXALS_INT_CLR);
-               if (ret < 0) {
-                       dev_err(&chip->client->dev,
-                               "%s: Failed to clear Int status\n",
-                               __func__);
-               return ret;
-               }
-       }
-
-       return ret;
-}
-
-static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
-{
-       int ret;
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-
-       /* turn device off */
-       chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
-
-       ret = i2c_smbus_write_byte_data(chip->client,
-                                       TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
-
-       if (chip->pdata && chip->pdata->power_off)
-               chip->pdata->power_off(chip->client);
-
-       return ret;
-}
-
-/**
- * tsl2x7x_invoke_change
- * @indio_dev: pointer to IIO device
- *
- * Obtain and lock both ALS and PROX resources,
- * determine and save device state (On/Off),
- * cycle device to implement updated parameter,
- * put device back into proper state, and unlock
- * resource.
- */
-static
-int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
-{
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       int device_status = chip->tsl2x7x_chip_status;
-
-       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)
-               tsl2x7x_chip_off(indio_dev);
-
-       mutex_unlock(&chip->prox_mutex);
-       mutex_unlock(&chip->als_mutex);
-
-       return 0;
-}
-
-static
-void tsl2x7x_prox_calculate(int *data, int length,
-                           struct tsl2x7x_prox_stat *statP)
-{
-       int i;
-       int sample_sum;
-       int tmp;
-
-       if (!length)
-               length = 1;
-
-       sample_sum = 0;
-       statP->min = INT_MAX;
-       statP->max = INT_MIN;
-       for (i = 0; i < length; i++) {
-               sample_sum += data[i];
-               statP->min = min(statP->min, data[i]);
-               statP->max = max(statP->max, data[i]);
-       }
-
-       statP->mean = sample_sum / length;
-       sample_sum = 0;
-       for (i = 0; i < length; i++) {
-               tmp = data[i] - statP->mean;
-               sample_sum += tmp * tmp;
-       }
-       statP->stddev = int_sqrt((long)sample_sum / length);
-}
-
-/**
- * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
- * @indio_dev: pointer to IIO device
- *
- * Calculates a standard deviation based on the samples,
- * and sets the threshold accordingly.
- */
-static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
-{
-       int prox_history[MAX_SAMPLES_CAL + 1];
-       int i;
-       struct tsl2x7x_prox_stat prox_stat_data[2];
-       struct tsl2x7x_prox_stat *calP;
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       u8 tmp_irq_settings;
-       u8 current_state = chip->tsl2x7x_chip_status;
-
-       if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
-               dev_err(&chip->client->dev,
-                       "max prox samples cal is too big: %d\n",
-                       chip->tsl2x7x_settings.prox_max_samples_cal);
-               chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
-       }
-
-       /* have to stop to change settings */
-       tsl2x7x_chip_off(indio_dev);
-
-       /* Enable proximity detection save just in case prox not wanted yet*/
-       tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
-       chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
-
-       /*turn on device if not already on*/
-       tsl2x7x_chip_on(indio_dev);
-
-       /*gather the samples*/
-       for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
-               mdelay(15);
-               tsl2x7x_get_prox(indio_dev);
-               prox_history[i] = chip->prox_data;
-               dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
-                        i, chip->prox_data);
-       }
-
-       tsl2x7x_chip_off(indio_dev);
-       calP = &prox_stat_data[PROX_STAT_CAL];
-       tsl2x7x_prox_calculate(prox_history,
-                              chip->tsl2x7x_settings.prox_max_samples_cal,
-                              calP);
-       chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
-
-       dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
-                calP->min, calP->mean, calP->max);
-       dev_info(&chip->client->dev,
-                "%s proximity threshold set to %d\n",
-                chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
-
-       /* back to the way they were */
-       chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
-       if (current_state == TSL2X7X_CHIP_WORKING)
-               tsl2x7x_chip_on(indio_dev);
-}
-
-static ssize_t tsl2x7x_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 tsl2x7x_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 tsl2x7x_gain_available_show(struct device *dev,
-                                          struct device_attribute *attr,
-                                          char *buf)
-{
-       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-
-       switch (chip->id) {
-       case tsl2571:
-       case tsl2671:
-       case tmd2671:
-       case tsl2771:
-       case tmd2771:
-               return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
-       }
-
-       return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
-}
-
-static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev,
-                                               struct device_attribute *attr,
-                                               char *buf)
-{
-               return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
-}
-
-static ssize_t tsl2x7x_als_time_show(struct device *dev,
-                                    struct device_attribute *attr,
-                                    char *buf)
-{
-       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-       int y, z;
-
-       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
-       z = y * TSL2X7X_MIN_ITIME;
-       y /= 1000;
-       z %= 1000;
-
-       return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
-}
-
-static ssize_t tsl2x7x_als_time_store(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       struct tsl2x7x_parse_result result;
-       int ret;
-
-       ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
-       if (ret)
-               return ret;
-
-       result.fract /= 3;
-       chip->tsl2x7x_settings.als_time =
-                       TSL2X7X_MAX_TIMER_CNT - (u8)result.fract;
-
-       dev_info(&chip->client->dev, "%s: als time = %d",
-                __func__, chip->tsl2x7x_settings.als_time);
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return IIO_VAL_INT_PLUS_MICRO;
-}
-
-static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
-               ".00272 - .696");
-
-static ssize_t tsl2x7x_als_cal_target_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_settings.als_cal_target);
-}
-
-static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
-                                           struct device_attribute *attr,
-                                           const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       unsigned long value;
-
-       if (kstrtoul(buf, 0, &value))
-               return -EINVAL;
-
-       if (value)
-               chip->tsl2x7x_settings.als_cal_target = value;
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return len;
-}
-
-/* persistence settings */
-static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
-                                           struct device_attribute *attr,
-                                           char *buf)
-{
-       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-       int y, z, filter_delay;
-
-       /* Determine integration time */
-       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
-       z = y * TSL2X7X_MIN_ITIME;
-       filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
-       y = filter_delay / 1000;
-       z = filter_delay % 1000;
-
-       return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
-}
-
-static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
-                                            struct device_attribute *attr,
-                                            const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       struct tsl2x7x_parse_result result;
-       int y, z, filter_delay;
-       int ret;
-
-       ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
-       if (ret)
-               return ret;
-
-       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
-       z = y * TSL2X7X_MIN_ITIME;
-
-       filter_delay =
-               DIV_ROUND_UP((result.integer * 1000) + result.fract, z);
-
-       chip->tsl2x7x_settings.persistence &= 0xF0;
-       chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
-
-       dev_info(&chip->client->dev, "%s: als persistence = %d",
-                __func__, filter_delay);
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return IIO_VAL_INT_PLUS_MICRO;
-}
-
-static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
-                                            struct device_attribute *attr,
-                                            char *buf)
-{
-       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-       int y, z, filter_delay;
-
-       /* Determine integration time */
-       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
-       z = y * TSL2X7X_MIN_ITIME;
-       filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
-       y = filter_delay / 1000;
-       z = filter_delay % 1000;
-
-       return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
-}
-
-static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
-                                             struct device_attribute *attr,
-                                             const char *buf, size_t len)
-{
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       struct tsl2x7x_parse_result result;
-       int y, z, filter_delay;
-       int ret;
-
-       ret = iio_str_to_fixpoint(buf, 100, &result.integer, &result.fract);
-       if (ret)
-               return ret;
-
-       y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
-       z = y * TSL2X7X_MIN_ITIME;
-
-       filter_delay =
-               DIV_ROUND_UP((result.integer * 1000) + result.fract, z);
-
-       chip->tsl2x7x_settings.persistence &= 0x0F;
-       chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
-
-       dev_info(&chip->client->dev, "%s: prox persistence = %d",
-                __func__, filter_delay);
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return IIO_VAL_INT_PLUS_MICRO;
-}
-
-static ssize_t tsl2x7x_do_calibrate(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_als_calibrate(indio_dev);
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return len;
-}
-
-static ssize_t tsl2x7x_luxtable_show(struct device *dev,
-                                    struct device_attribute *attr,
-                                    char *buf)
-{
-       struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
-       int i = 0;
-       int offset = 0;
-
-       while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
-               offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
-                       chip->tsl2x7x_device_lux[i].ratio,
-                       chip->tsl2x7x_device_lux[i].ch0,
-                       chip->tsl2x7x_device_lux[i].ch1);
-               if (chip->tsl2x7x_device_lux[i].ratio == 0) {
-                       /*
-                        * We just printed the first "0" entry.
-                        * Now get rid of the extra "," and break.
-                        */
-                       offset--;
-                       break;
-               }
-               i++;
-       }
-
-       offset += snprintf(buf + offset, PAGE_SIZE, "\n");
-       return offset;
-}
-
-static ssize_t tsl2x7x_luxtable_store(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t len)
-{
-       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;
-
-       get_options(buf, ARRAY_SIZE(value), value);
-
-       /* We now have an array of ints starting at value[1], and
-        * enumerated by value[0].
-        * We expect each group of three ints is one table entry,
-        * and the last table entry is all 0.
-        */
-       n = value[0];
-       if ((n % 3) || n < 6 ||
-           n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
-               dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
-               return -EINVAL;
-       }
-
-       if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
-               dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
-               return -EINVAL;
-       }
-
-       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
-               tsl2x7x_chip_off(indio_dev);
-
-       /* Zero out the table */
-       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);
-
-       return len;
-}
-
-static ssize_t tsl2x7x_do_prox_calibrate(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_prox_cal(indio_dev);
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return len;
-}
-
-static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
-                                        const struct iio_chan_spec *chan,
-                                        enum iio_event_type type,
-                                        enum iio_event_direction dir)
-{
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       int ret;
-
-       if (chan->type == IIO_INTENSITY)
-               ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
-       else
-               ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
-
-       return ret;
-}
-
-static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
-                                         const struct iio_chan_spec *chan,
-                                         enum iio_event_type type,
-                                         enum iio_event_direction dir,
-                                         int val)
-{
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-
-       if (chan->type == IIO_INTENSITY) {
-               if (val)
-                       chip->tsl2x7x_settings.interrupts_en |= 0x10;
-               else
-                       chip->tsl2x7x_settings.interrupts_en &= 0x20;
-       } else {
-               if (val)
-                       chip->tsl2x7x_settings.interrupts_en |= 0x20;
-               else
-                       chip->tsl2x7x_settings.interrupts_en &= 0x10;
-       }
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       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)
-{
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-
-       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;
-               }
-       }
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return 0;
-}
-
-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)
-{
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-
-       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;
-               }
-       }
-
-       return IIO_VAL_INT;
-}
-
-static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
-                           struct iio_chan_spec const *chan,
-                           int *val,
-                           int *val2,
-                           long mask)
-{
-       int ret = -EINVAL;
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-
-       switch (mask) {
-       case IIO_CHAN_INFO_PROCESSED:
-               switch (chan->type) {
-               case IIO_LIGHT:
-                       tsl2x7x_get_lux(indio_dev);
-                       *val = chip->als_cur_info.lux;
-                       ret = IIO_VAL_INT;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case IIO_CHAN_INFO_RAW:
-               switch (chan->type) {
-               case IIO_INTENSITY:
-                       tsl2x7x_get_lux(indio_dev);
-                       if (chan->channel == 0)
-                               *val = chip->als_cur_info.als_ch0;
-                       else
-                               *val = chip->als_cur_info.als_ch1;
-                       ret = IIO_VAL_INT;
-                       break;
-               case IIO_PROXIMITY:
-                       tsl2x7x_get_prox(indio_dev);
-                       *val = chip->prox_data;
-                       ret = IIO_VAL_INT;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case IIO_CHAN_INFO_CALIBSCALE:
-               if (chan->type == IIO_LIGHT)
-                       *val =
-                       tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
-               else
-                       *val =
-                       tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_CALIBBIAS:
-               *val = chip->tsl2x7x_settings.als_gain_trim;
-               ret = IIO_VAL_INT;
-               break;
-
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
-                            struct iio_chan_spec const *chan,
-                            int val,
-                            int val2,
-                            long mask)
-{
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-
-       switch (mask) {
-       case IIO_CHAN_INFO_CALIBSCALE:
-               if (chan->type == IIO_INTENSITY) {
-                       switch (val) {
-                       case 1:
-                               chip->tsl2x7x_settings.als_gain = 0;
-                               break;
-                       case 8:
-                               chip->tsl2x7x_settings.als_gain = 1;
-                               break;
-                       case 16:
-                               chip->tsl2x7x_settings.als_gain = 2;
-                               break;
-                       case 120:
-                               switch (chip->id) {
-                               case tsl2572:
-                               case tsl2672:
-                               case tmd2672:
-                               case tsl2772:
-                               case tmd2772:
-                                       return -EINVAL;
-                               }
-                               chip->tsl2x7x_settings.als_gain = 3;
-                               break;
-                       case 128:
-                               switch (chip->id) {
-                               case tsl2571:
-                               case tsl2671:
-                               case tmd2671:
-                               case tsl2771:
-                               case tmd2771:
-                                       return -EINVAL;
-                               }
-                               chip->tsl2x7x_settings.als_gain = 3;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-               } else {
-                       switch (val) {
-                       case 1:
-                               chip->tsl2x7x_settings.prox_gain = 0;
-                               break;
-                       case 2:
-                               chip->tsl2x7x_settings.prox_gain = 1;
-                               break;
-                       case 4:
-                               chip->tsl2x7x_settings.prox_gain = 2;
-                               break;
-                       case 8:
-                               chip->tsl2x7x_settings.prox_gain = 3;
-                               break;
-                       default:
-                               return -EINVAL;
-                       }
-               }
-               break;
-       case IIO_CHAN_INFO_CALIBBIAS:
-               chip->tsl2x7x_settings.als_gain_trim = val;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       tsl2x7x_invoke_change(indio_dev);
-
-       return 0;
-}
-
-static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
-               tsl2x7x_power_state_show, tsl2x7x_power_state_store);
-
-static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO,
-               tsl2x7x_prox_gain_available_show, NULL);
-
-static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO,
-               tsl2x7x_gain_available_show, NULL);
-
-static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR,
-               tsl2x7x_als_time_show, tsl2x7x_als_time_store);
-
-static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR,
-               tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store);
-
-static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL,
-               tsl2x7x_do_calibrate);
-
-static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL,
-               tsl2x7x_do_prox_calibrate);
-
-static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR,
-               tsl2x7x_luxtable_show, tsl2x7x_luxtable_store);
-
-static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR,
-               tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store);
-
-static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR,
-               tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store);
-
-/* Use the default register values to identify the Taos device */
-static int tsl2x7x_device_id(unsigned char *id, int target)
-{
-       switch (target) {
-       case tsl2571:
-       case tsl2671:
-       case tsl2771:
-               return (*id & 0xf0) == TRITON_ID;
-       case tmd2671:
-       case tmd2771:
-               return (*id & 0xf0) == HALIBUT_ID;
-       case tsl2572:
-       case tsl2672:
-       case tmd2672:
-       case tsl2772:
-       case tmd2772:
-               return (*id & 0xf0) == SWORDFISH_ID;
-       }
-
-       return -EINVAL;
-}
-
-static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
-{
-       struct iio_dev *indio_dev = private;
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       s64 timestamp = iio_get_time_ns(indio_dev);
-       int ret;
-       u8 value;
-
-       value = i2c_smbus_read_byte_data(chip->client,
-                                        TSL2X7X_CMD_REG | TSL2X7X_STATUS);
-
-       /* What type of interrupt do we need to process */
-       if (value & TSL2X7X_STA_PRX_INTR) {
-               tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
-               iio_push_event(indio_dev,
-                              IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
-                                                   0,
-                                                   IIO_EV_TYPE_THRESH,
-                                                   IIO_EV_DIR_EITHER),
-                                                   timestamp);
-       }
-
-       if (value & TSL2X7X_STA_ALS_INTR) {
-               tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
-               iio_push_event(indio_dev,
-                              IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
-                                                   0,
-                                                   IIO_EV_TYPE_THRESH,
-                                                   IIO_EV_DIR_EITHER),
-                              timestamp);
-       }
-       /* Clear interrupt now that we have handled it. */
-       ret = i2c_smbus_write_byte(chip->client,
-                                  TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
-                                  TSL2X7X_CMD_PROXALS_INT_CLR);
-       if (ret < 0)
-               dev_err(&chip->client->dev,
-                       "Failed to clear irq from event handler. err = %d\n",
-                       ret);
-
-       return IRQ_HANDLED;
-}
-
-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,
-       &dev_attr_in_illuminance0_target_input.attr,
-       &dev_attr_in_illuminance0_calibrate.attr,
-       &dev_attr_in_illuminance0_lux_table.attr,
-       NULL
-};
-
-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,
-       &dev_attr_in_illuminance0_target_input.attr,
-       &dev_attr_in_illuminance0_calibrate.attr,
-       &dev_attr_in_illuminance0_lux_table.attr,
-       &dev_attr_in_proximity0_calibrate.attr,
-       NULL
-};
-
-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,
-       &dev_attr_in_illuminance0_target_input.attr,
-       &dev_attr_in_illuminance0_calibrate.attr,
-       &dev_attr_in_illuminance0_lux_table.attr,
-       &dev_attr_in_proximity0_calibrate.attr,
-       &dev_attr_in_proximity0_calibscale_available.attr,
-       NULL
-};
-
-static struct attribute *tsl2X7X_ALS_event_attrs[] = {
-       &dev_attr_in_intensity0_thresh_period.attr,
-       NULL,
-};
-
-static struct attribute *tsl2X7X_PRX_event_attrs[] = {
-       &dev_attr_in_proximity0_thresh_period.attr,
-       NULL,
-};
-
-static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = {
-       &dev_attr_in_intensity0_thresh_period.attr,
-       &dev_attr_in_proximity0_thresh_period.attr,
-       NULL,
-};
-
-static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
-       [ALS] = {
-               .attrs = tsl2x7x_ALS_device_attrs,
-       },
-       [PRX] = {
-               .attrs = tsl2x7x_PRX_device_attrs,
-       },
-       [ALSPRX] = {
-               .attrs = tsl2x7x_ALSPRX_device_attrs,
-       },
-       [PRX2] = {
-               .attrs = tsl2x7x_PRX2_device_attrs,
-       },
-       [ALSPRX2] = {
-               .attrs = tsl2x7x_ALSPRX2_device_attrs,
-       },
-};
-
-static const struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
-       [ALS] = {
-               .attrs = tsl2X7X_ALS_event_attrs,
-               .name = "events",
-       },
-       [PRX] = {
-               .attrs = tsl2X7X_PRX_event_attrs,
-               .name = "events",
-       },
-       [ALSPRX] = {
-               .attrs = tsl2X7X_ALSPRX_event_attrs,
-               .name = "events",
-       },
-};
-
-static const struct iio_info tsl2X7X_device_info[] = {
-       [ALS] = {
-               .attrs = &tsl2X7X_device_attr_group_tbl[ALS],
-               .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS],
-               .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_config = &tsl2x7x_read_interrupt_config,
-               .write_event_config = &tsl2x7x_write_interrupt_config,
-       },
-       [PRX] = {
-               .attrs = &tsl2X7X_device_attr_group_tbl[PRX],
-               .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
-               .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_config = &tsl2x7x_read_interrupt_config,
-               .write_event_config = &tsl2x7x_write_interrupt_config,
-       },
-       [ALSPRX] = {
-               .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
-               .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
-               .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_config = &tsl2x7x_read_interrupt_config,
-               .write_event_config = &tsl2x7x_write_interrupt_config,
-       },
-       [PRX2] = {
-               .attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
-               .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
-               .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_config = &tsl2x7x_read_interrupt_config,
-               .write_event_config = &tsl2x7x_write_interrupt_config,
-       },
-       [ALSPRX2] = {
-               .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
-               .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
-               .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_config = &tsl2x7x_read_interrupt_config,
-               .write_event_config = &tsl2x7x_write_interrupt_config,
-       },
-};
-
-static const struct iio_event_spec tsl2x7x_events[] = {
-       {
-               .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_RISING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
-                       BIT(IIO_EV_INFO_ENABLE),
-       }, {
-               .type = IIO_EV_TYPE_THRESH,
-               .dir = IIO_EV_DIR_FALLING,
-               .mask_separate = BIT(IIO_EV_INFO_VALUE) |
-                       BIT(IIO_EV_INFO_ENABLE),
-       },
-};
-
-static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
-       [ALS] = {
-               .channel = {
-                       {
-                       .type = IIO_LIGHT,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
-                       }, {
-                       .type = IIO_INTENSITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                               BIT(IIO_CHAN_INFO_CALIBSCALE) |
-                               BIT(IIO_CHAN_INFO_CALIBBIAS),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       }, {
-                       .type = IIO_INTENSITY,
-                       .indexed = 1,
-                       .channel = 1,
-                       },
-               },
-       .chan_table_elements = 3,
-       .info = &tsl2X7X_device_info[ALS],
-       },
-       [PRX] = {
-               .channel = {
-                       {
-                       .type = IIO_PROXIMITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       },
-               },
-       .chan_table_elements = 1,
-       .info = &tsl2X7X_device_info[PRX],
-       },
-       [ALSPRX] = {
-               .channel = {
-                       {
-                       .type = IIO_LIGHT,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED)
-                       }, {
-                       .type = IIO_INTENSITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                               BIT(IIO_CHAN_INFO_CALIBSCALE) |
-                               BIT(IIO_CHAN_INFO_CALIBBIAS),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       }, {
-                       .type = IIO_INTENSITY,
-                       .indexed = 1,
-                       .channel = 1,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       }, {
-                       .type = IIO_PROXIMITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       },
-               },
-       .chan_table_elements = 4,
-       .info = &tsl2X7X_device_info[ALSPRX],
-       },
-       [PRX2] = {
-               .channel = {
-                       {
-                       .type = IIO_PROXIMITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                               BIT(IIO_CHAN_INFO_CALIBSCALE),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       },
-               },
-       .chan_table_elements = 1,
-       .info = &tsl2X7X_device_info[PRX2],
-       },
-       [ALSPRX2] = {
-               .channel = {
-                       {
-                       .type = IIO_LIGHT,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
-                       }, {
-                       .type = IIO_INTENSITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                               BIT(IIO_CHAN_INFO_CALIBSCALE) |
-                               BIT(IIO_CHAN_INFO_CALIBBIAS),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       }, {
-                       .type = IIO_INTENSITY,
-                       .indexed = 1,
-                       .channel = 1,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-                       }, {
-                       .type = IIO_PROXIMITY,
-                       .indexed = 1,
-                       .channel = 0,
-                       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                               BIT(IIO_CHAN_INFO_CALIBSCALE),
-                       .event_spec = tsl2x7x_events,
-                       .num_event_specs = ARRAY_SIZE(tsl2x7x_events),
-                       },
-               },
-       .chan_table_elements = 4,
-       .info = &tsl2X7X_device_info[ALSPRX2],
-       },
-};
-
-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;
-
-       indio_dev = devm_iio_device_alloc(&clientp->dev, sizeof(*chip));
-       if (!indio_dev)
-               return -ENOMEM;
-
-       chip = iio_priv(indio_dev);
-       chip->client = clientp;
-       i2c_set_clientdata(clientp, indio_dev);
-
-       ret = tsl2x7x_i2c_read(chip->client,
-                              TSL2X7X_CHIPID, &device_id);
-       if (ret < 0)
-               return ret;
-
-       if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
-           (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
-               dev_info(&chip->client->dev,
-                        "%s: i2c device found does not match expected id\n",
-                               __func__);
-               return -EINVAL;
-       }
-
-       ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
-       if (ret < 0) {
-               dev_err(&clientp->dev, "write to cmd reg failed. err = %d\n",
-                       ret);
-               return ret;
-       }
-
-       /*
-        * ALS and PROX functions can be invoked via user space poll
-        * or H/W interrupt. If busy return last sample.
-        */
-       mutex_init(&chip->als_mutex);
-       mutex_init(&chip->prox_mutex);
-
-       chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
-       chip->pdata = dev_get_platdata(&clientp->dev);
-       chip->id = id->driver_data;
-       chip->chip_info =
-               &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
-
-       indio_dev->info = chip->chip_info->info;
-       indio_dev->dev.parent = &clientp->dev;
-       indio_dev->modes = INDIO_DIRECT_MODE;
-       indio_dev->name = chip->client->name;
-       indio_dev->channels = chip->chip_info->channel;
-       indio_dev->num_channels = chip->chip_info->chan_table_elements;
-
-       if (clientp->irq) {
-               ret = devm_request_threaded_irq(&clientp->dev, clientp->irq,
-                                               NULL,
-                                               &tsl2x7x_event_handler,
-                                               IRQF_TRIGGER_RISING |
-                                               IRQF_ONESHOT,
-                                               "TSL2X7X_event",
-                                               indio_dev);
-               if (ret) {
-                       dev_err(&clientp->dev,
-                               "%s: irq request failed", __func__);
-                       return ret;
-               }
-       }
-
-       /* Load up the defaults */
-       tsl2x7x_defaults(chip);
-       /* Make sure the chip is on */
-       tsl2x7x_chip_on(indio_dev);
-
-       ret = iio_device_register(indio_dev);
-       if (ret) {
-               dev_err(&clientp->dev,
-                       "%s: iio registration failed\n", __func__);
-               return ret;
-       }
-
-       dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
-
-       return 0;
-}
-
-static int tsl2x7x_suspend(struct device *dev)
-{
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       int ret = 0;
-
-       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
-               ret = tsl2x7x_chip_off(indio_dev);
-               chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
-       }
-
-       if (chip->pdata && chip->pdata->platform_power) {
-               pm_message_t pmm = {PM_EVENT_SUSPEND};
-
-               chip->pdata->platform_power(dev, pmm);
-       }
-
-       return ret;
-}
-
-static int tsl2x7x_resume(struct device *dev)
-{
-       struct iio_dev *indio_dev = dev_get_drvdata(dev);
-       struct tsl2X7X_chip *chip = iio_priv(indio_dev);
-       int ret = 0;
-
-       if (chip->pdata && chip->pdata->platform_power) {
-               pm_message_t pmm = {PM_EVENT_RESUME};
-
-               chip->pdata->platform_power(dev, pmm);
-       }
-
-       if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
-               ret = tsl2x7x_chip_on(indio_dev);
-
-       return ret;
-}
-
-static int tsl2x7x_remove(struct i2c_client *client)
-{
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
-
-       tsl2x7x_chip_off(indio_dev);
-
-       iio_device_unregister(indio_dev);
-
-       return 0;
-}
-
-static struct i2c_device_id tsl2x7x_idtable[] = {
-       { "tsl2571", tsl2571 },
-       { "tsl2671", tsl2671 },
-       { "tmd2671", tmd2671 },
-       { "tsl2771", tsl2771 },
-       { "tmd2771", tmd2771 },
-       { "tsl2572", tsl2572 },
-       { "tsl2672", tsl2672 },
-       { "tmd2672", tmd2672 },
-       { "tsl2772", tsl2772 },
-       { "tmd2772", tmd2772 },
-       {}
-};
-
-MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
-
-static const struct dev_pm_ops tsl2x7x_pm_ops = {
-       .suspend = tsl2x7x_suspend,
-       .resume  = tsl2x7x_resume,
-};
-
-/* Driver definition */
-static struct i2c_driver tsl2x7x_driver = {
-       .driver = {
-               .name = "tsl2x7x",
-               .pm = &tsl2x7x_pm_ops,
-       },
-       .id_table = tsl2x7x_idtable,
-       .probe = tsl2x7x_probe,
-       .remove = tsl2x7x_remove,
-};
-
-module_i2c_driver(tsl2x7x_driver);
-
-MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
-MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
-MODULE_LICENSE("GPL");
index b71fbd313778375aa41155e82385480db00393c1..ce26abdeab923839dd6f8b2f5f5ead912b79fc07 100644 (file)
@@ -107,9 +107,8 @@ static int ade7753_spi_write_reg_8(struct device *dev,
        return ret;
 }
 
-static int ade7753_spi_write_reg_16(struct device *dev,
-               u8 reg_address,
-               u16 value)
+static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
+                                   u16 value)
 {
        int ret;
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
@@ -126,8 +125,8 @@ static int ade7753_spi_write_reg_16(struct device *dev,
 }
 
 static int ade7753_spi_read_reg_8(struct device *dev,
-               u8 reg_address,
-               u8 *val)
+                                 u8 reg_address,
+                                 u8 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7753_state *st = iio_priv(indio_dev);
@@ -136,7 +135,7 @@ static int ade7753_spi_read_reg_8(struct device *dev,
        ret = spi_w8r8(st->us, ADE7753_READ_REG(reg_address));
        if (ret < 0) {
                dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
-                               reg_address);
+                       reg_address);
                return ret;
        }
        *val = ret;
@@ -145,8 +144,8 @@ static int ade7753_spi_read_reg_8(struct device *dev,
 }
 
 static int ade7753_spi_read_reg_16(struct device *dev,
-               u8 reg_address,
-               u16 *val)
+                                  u8 reg_address,
+                                  u16 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7753_state *st = iio_priv(indio_dev);
@@ -165,8 +164,8 @@ static int ade7753_spi_read_reg_16(struct device *dev,
 }
 
 static int ade7753_spi_read_reg_24(struct device *dev,
-               u8 reg_address,
-               u32 *val)
+                                  u8 reg_address,
+                                  u32 *val)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7753_state *st = iio_priv(indio_dev);
@@ -189,7 +188,7 @@ static int ade7753_spi_read_reg_24(struct device *dev,
        ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
        if (ret) {
                dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
-                               reg_address);
+                       reg_address);
                goto error_ret;
        }
        *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
@@ -200,8 +199,8 @@ error_ret:
 }
 
 static ssize_t ade7753_read_8bit(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                struct device_attribute *attr,
+                                char *buf)
 {
        int ret;
        u8 val;
@@ -215,8 +214,8 @@ static ssize_t ade7753_read_8bit(struct device *dev,
 }
 
 static ssize_t ade7753_read_16bit(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        int ret;
        u16 val;
@@ -230,8 +229,8 @@ static ssize_t ade7753_read_16bit(struct device *dev,
 }
 
 static ssize_t ade7753_read_24bit(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                 struct device_attribute *attr,
+                                 char *buf)
 {
        int ret;
        u32 val;
@@ -245,9 +244,9 @@ static ssize_t ade7753_read_24bit(struct device *dev,
 }
 
 static ssize_t ade7753_write_8bit(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                 struct device_attribute *attr,
+                                 const char *buf,
+                                 size_t len)
 {
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        int ret;
@@ -263,9 +262,9 @@ error_ret:
 }
 
 static ssize_t ade7753_write_16bit(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                  struct device_attribute *attr,
+                                  const char *buf,
+                                  size_t len)
 {
        struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
        int ret;
@@ -298,92 +297,92 @@ static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY);
 static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY);
 static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY);
 static IIO_DEV_ATTR_LVAENERGY(ade7753_read_24bit, ADE7753_LVAENERGY);
-static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFDEN(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_CFDEN);
-static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFNUM(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_CFNUM);
 static IIO_DEV_ATTR_CHKSUM(ade7753_read_8bit, ADE7753_CHKSUM);
-static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_PHCAL(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_PHCAL);
-static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APOS(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_APOS);
-static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAGCYC(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_SAGCYC);
-static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAGLVL(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_SAGLVL);
-static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_LINECYC(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_LINECYC);
-static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_WDIV(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_WDIV);
-static IIO_DEV_ATTR_IRMS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_IRMS(0644,
                ade7753_read_24bit,
                NULL,
                ADE7753_IRMS);
-static IIO_DEV_ATTR_VRMS(S_IRUGO,
+static IIO_DEV_ATTR_VRMS(0444,
                ade7753_read_24bit,
                NULL,
                ADE7753_VRMS);
-static IIO_DEV_ATTR_IRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_IRMSOS(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_IRMSOS);
-static IIO_DEV_ATTR_VRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VRMSOS(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_VRMSOS);
-static IIO_DEV_ATTR_WGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_WGAIN(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_WGAIN);
-static IIO_DEV_ATTR_VAGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VAGAIN(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_VAGAIN);
-static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_PGA_GAIN(0644,
                ade7753_read_16bit,
                ade7753_write_16bit,
                ADE7753_GAIN);
-static IIO_DEV_ATTR_IPKLVL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_IPKLVL(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_IPKLVL);
-static IIO_DEV_ATTR_VPKLVL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VPKLVL(0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_VPKLVL);
-static IIO_DEV_ATTR_IPEAK(S_IRUGO,
+static IIO_DEV_ATTR_IPEAK(0444,
                ade7753_read_24bit,
                NULL,
                ADE7753_IPEAK);
-static IIO_DEV_ATTR_VPEAK(S_IRUGO,
+static IIO_DEV_ATTR_VPEAK(0444,
                ade7753_read_24bit,
                NULL,
                ADE7753_VPEAK);
-static IIO_DEV_ATTR_VPERIOD(S_IRUGO,
+static IIO_DEV_ATTR_VPERIOD(0444,
                ade7753_read_16bit,
                NULL,
                ADE7753_PERIOD);
-static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CH_OFF(1, 0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_CH1OS);
-static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CH_OFF(2, 0644,
                ade7753_read_8bit,
                ade7753_write_8bit,
                ADE7753_CH2OS);
@@ -450,8 +449,8 @@ err_ret:
 }
 
 static ssize_t ade7753_read_frequency(struct device *dev,
-               struct device_attribute *attr,
-               char *buf)
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
        int ret;
        u16 t;
@@ -468,9 +467,9 @@ static ssize_t ade7753_read_frequency(struct device *dev,
 }
 
 static ssize_t ade7753_write_frequency(struct device *dev,
-               struct device_attribute *attr,
-               const char *buf,
-               size_t len)
+                                      struct device_attribute *attr,
+                                      const char *buf,
+                                      size_t len)
 {
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ade7753_state *st = iio_priv(indio_dev);
@@ -514,7 +513,7 @@ static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit);
 static IIO_CONST_ATTR(in_temp_offset, "-25 C");
 static IIO_CONST_ATTR(in_temp_scale, "0.67 C");
 
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAMP_FREQ(0644,
                ade7753_read_frequency,
                ade7753_write_frequency);
 
index 32dc503417460b3520831a32b982048277d9eef4..be0df3fe42304418654f1adeb0e1b192787e8383 100644 (file)
@@ -316,111 +316,111 @@ static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY);
 static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY);
 static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY);
 static IIO_DEV_ATTR_LVAENERGY(ade7754_read_24bit, ADE7754_LVAENERGY);
-static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VPEAK(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_VPEAK);
-static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_IPEAK(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_VPEAK);
-static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APHCAL(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_APHCAL);
-static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BPHCAL(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_BPHCAL);
-static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CPHCAL(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_CPHCAL);
-static IIO_DEV_ATTR_AAPOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AAPOS(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_AAPOS);
-static IIO_DEV_ATTR_BAPOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BAPOS(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_BAPOS);
-static IIO_DEV_ATTR_CAPOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CAPOS(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_CAPOS);
-static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_WDIV(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_WDIV);
-static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VADIV(0644,
                ade7754_read_8bit,
                ade7754_write_8bit,
                ADE7754_VADIV);
-static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFNUM(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_CFNUM);
-static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFDEN(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_CFDEN);
-static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_AAPGAIN);
-static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_BAPGAIN);
-static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(0644,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_CAPGAIN);
-static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+static IIO_DEV_ATTR_AIRMS(0444,
                ade7754_read_24bit,
                NULL,
                ADE7754_AIRMS);
-static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+static IIO_DEV_ATTR_BIRMS(0444,
                ade7754_read_24bit,
                NULL,
                ADE7754_BIRMS);
-static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+static IIO_DEV_ATTR_CIRMS(0444,
                ade7754_read_24bit,
                NULL,
                ADE7754_CIRMS);
-static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+static IIO_DEV_ATTR_AVRMS(0444,
                ade7754_read_24bit,
                NULL,
                ADE7754_AVRMS);
-static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+static IIO_DEV_ATTR_BVRMS(0444,
                ade7754_read_24bit,
                NULL,
                ADE7754_BVRMS);
-static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+static IIO_DEV_ATTR_CVRMS(0444,
                ade7754_read_24bit,
                NULL,
                ADE7754_CVRMS);
-static IIO_DEV_ATTR_AIRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_AIRMSOS(0444,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_AIRMSOS);
-static IIO_DEV_ATTR_BIRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_BIRMSOS(0444,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_BIRMSOS);
-static IIO_DEV_ATTR_CIRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_CIRMSOS(0444,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_CIRMSOS);
-static IIO_DEV_ATTR_AVRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_AVRMSOS(0444,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_AVRMSOS);
-static IIO_DEV_ATTR_BVRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_BVRMSOS(0444,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_BVRMSOS);
-static IIO_DEV_ATTR_CVRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_CVRMSOS(0444,
                ade7754_read_16bit,
                ade7754_write_16bit,
                ADE7754_CVRMSOS);
@@ -549,7 +549,7 @@ static IIO_DEV_ATTR_TEMP_RAW(ade7754_read_8bit);
 static IIO_CONST_ATTR(in_temp_offset, "129 C");
 static IIO_CONST_ATTR(in_temp_scale, "4 C");
 
-static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAMP_FREQ(0644,
                ade7754_read_frequency,
                ade7754_write_frequency);
 
index 99c89e606c8d8b8090f4aa9207b9872fae6dceaf..40498af4dc4630638a79ddde0480b0423bf026ac 100644 (file)
@@ -301,103 +301,103 @@ static int ade7758_reset(struct device *dev)
        return ret;
 }
 
-static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VPEAK(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_VPEAK);
-static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_IPEAK(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_VPEAK);
-static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APHCAL(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_APHCAL);
-static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BPHCAL(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_BPHCAL);
-static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CPHCAL(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_CPHCAL);
-static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_WDIV(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_WDIV);
-static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VADIV(0644,
                ade7758_read_8bit,
                ade7758_write_8bit,
                ADE7758_VADIV);
-static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+static IIO_DEV_ATTR_AIRMS(0444,
                ade7758_read_24bit,
                NULL,
                ADE7758_AIRMS);
-static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+static IIO_DEV_ATTR_BIRMS(0444,
                ade7758_read_24bit,
                NULL,
                ADE7758_BIRMS);
-static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+static IIO_DEV_ATTR_CIRMS(0444,
                ade7758_read_24bit,
                NULL,
                ADE7758_CIRMS);
-static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+static IIO_DEV_ATTR_AVRMS(0444,
                ade7758_read_24bit,
                NULL,
                ADE7758_AVRMS);
-static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+static IIO_DEV_ATTR_BVRMS(0444,
                ade7758_read_24bit,
                NULL,
                ADE7758_BVRMS);
-static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+static IIO_DEV_ATTR_CVRMS(0444,
                ade7758_read_24bit,
                NULL,
                ADE7758_CVRMS);
-static IIO_DEV_ATTR_AIRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AIRMSOS(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_AIRMSOS);
-static IIO_DEV_ATTR_BIRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BIRMSOS(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_BIRMSOS);
-static IIO_DEV_ATTR_CIRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CIRMSOS(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_CIRMSOS);
-static IIO_DEV_ATTR_AVRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AVRMSOS(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_AVRMSOS);
-static IIO_DEV_ATTR_BVRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BVRMSOS(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_BVRMSOS);
-static IIO_DEV_ATTR_CVRMSOS(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CVRMSOS(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_CVRMSOS);
-static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AIGAIN(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_AIGAIN);
-static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BIGAIN(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_BIGAIN);
-static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CIGAIN(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_CIGAIN);
-static IIO_DEV_ATTR_AVRMSGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AVRMSGAIN(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_AVRMSGAIN);
-static IIO_DEV_ATTR_BVRMSGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BVRMSGAIN(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_BVRMSGAIN);
-static IIO_DEV_ATTR_CVRMSGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CVRMSGAIN(0644,
                ade7758_read_16bit,
                ade7758_write_16bit,
                ADE7758_CVRMSGAIN);
index c6cffc11b0ba96e24797ce328bbfc64a8277f276..70612da64a8baee961853f7b849be67258b8c561 100644 (file)
@@ -186,127 +186,127 @@ static int ade7854_reset(struct device *dev)
        return st->write_reg_16(dev, ADE7854_CONFIG, val);
 }
 
-static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AIGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_AIGAIN);
-static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BIGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_BIGAIN);
-static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CIGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_CIGAIN);
-static IIO_DEV_ATTR_NIGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_NIGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_NIGAIN);
-static IIO_DEV_ATTR_AVGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_AVGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_AVGAIN);
-static IIO_DEV_ATTR_BVGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BVGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_BVGAIN);
-static IIO_DEV_ATTR_CVGAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CVGAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_CVGAIN);
-static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_AVAGAIN);
-static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_BVAGAIN);
-static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_CVAGAIN);
-static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_AWATTOS);
-static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_BWATTOS);
-static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_CWATTOS);
-static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_AVARGAIN);
-static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_BVARGAIN);
-static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_CVARGAIN);
-static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_AVAROS);
-static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_BVAROS);
-static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(0644,
                ade7854_read_24bit,
                ade7854_write_24bit,
                ADE7854_CVAROS);
-static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_VPEAK(0644,
                ade7854_read_32bit,
                ade7854_write_32bit,
                ADE7854_VPEAK);
-static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_IPEAK(0644,
                ade7854_read_32bit,
                ade7854_write_32bit,
                ADE7854_VPEAK);
-static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_APHCAL(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_APHCAL);
-static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_BPHCAL(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_BPHCAL);
-static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CPHCAL(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_CPHCAL);
-static IIO_DEV_ATTR_CF1DEN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CF1DEN(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_CF1DEN);
-static IIO_DEV_ATTR_CF2DEN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CF2DEN(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_CF2DEN);
-static IIO_DEV_ATTR_CF3DEN(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CF3DEN(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_CF3DEN);
-static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_LINECYC(0644,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_LINECYC);
-static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_SAGCYC(0644,
                ade7854_read_8bit,
                ade7854_write_8bit,
                ADE7854_SAGCYC);
-static IIO_DEV_ATTR_CFCYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_CFCYC(0644,
                ade7854_read_8bit,
                ade7854_write_8bit,
                ADE7854_CFCYC);
-static IIO_DEV_ATTR_PEAKCYC(S_IWUSR | S_IRUGO,
+static IIO_DEV_ATTR_PEAKCYC(0644,
                ade7854_read_8bit,
                ade7854_write_8bit,
                ADE7854_PEAKCYC);
@@ -318,55 +318,55 @@ static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit,
                ADE7854_ANGLE1);
 static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit,
                ADE7854_ANGLE2);
-static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+static IIO_DEV_ATTR_AIRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_AIRMS);
-static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+static IIO_DEV_ATTR_BIRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_BIRMS);
-static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+static IIO_DEV_ATTR_CIRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_CIRMS);
-static IIO_DEV_ATTR_NIRMS(S_IRUGO,
+static IIO_DEV_ATTR_NIRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_NIRMS);
-static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+static IIO_DEV_ATTR_AVRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_AVRMS);
-static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+static IIO_DEV_ATTR_BVRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_BVRMS);
-static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+static IIO_DEV_ATTR_CVRMS(0444,
                ade7854_read_24bit,
                NULL,
                ADE7854_CVRMS);
-static IIO_DEV_ATTR_AIRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_AIRMSOS(0444,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_AIRMSOS);
-static IIO_DEV_ATTR_BIRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_BIRMSOS(0444,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_BIRMSOS);
-static IIO_DEV_ATTR_CIRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_CIRMSOS(0444,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_CIRMSOS);
-static IIO_DEV_ATTR_AVRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_AVRMSOS(0444,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_AVRMSOS);
-static IIO_DEV_ATTR_BVRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_BVRMSOS(0444,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_BVRMSOS);
-static IIO_DEV_ATTR_CVRMSOS(S_IRUGO,
+static IIO_DEV_ATTR_CVRMSOS(0444,
                ade7854_read_16bit,
                ade7854_write_16bit,
                ADE7854_CVRMSOS);
index f32d7c392c1ec9532a51e801e45a22e4942d0661..fc7aae64dcde8d51d6732395ad6555ceaa845f4a 100644 (file)
@@ -233,12 +233,14 @@ struct hid_sensor_common {
        atomic_t user_requested_state;
        int poll_interval;
        int raw_hystersis;
+       int latency_ms;
        struct iio_trigger *trigger;
        int timestamp_ns_scale;
        struct hid_sensor_hub_attribute_info poll;
        struct hid_sensor_hub_attribute_info report_state;
        struct hid_sensor_hub_attribute_info power_state;
        struct hid_sensor_hub_attribute_info sensitivity;
+       struct hid_sensor_hub_attribute_info report_latency;
        struct work_struct work;
 };
 
@@ -276,5 +278,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st);
 
 int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st,
                                     int64_t raw_value);
+bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st);
+int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency);
+int hid_sensor_get_report_latency(struct hid_sensor_common *st);
 
 #endif
index 761f86242473609ed94cee70672e9e639e32e818..76033e0420a737e82dee878c789999256cb841d4 100644 (file)
@@ -90,6 +90,8 @@
 #define HID_USAGE_SENSOR_ORIENT_TILT_Z                         0x200481
 
 #define HID_USAGE_SENSOR_DEVICE_ORIENTATION                    0x20008A
+#define HID_USAGE_SENSOR_RELATIVE_ORIENTATION                  0x20008E
+#define HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION               0x2000C1
 #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX                        0x200482
 #define HID_USAGE_SENSOR_ORIENT_QUATERNION                     0x200483
 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX                      0x200484
 #define HID_USAGE_SENSOR_PROP_REPORT_STATE                     0x200316
 #define HID_USAGE_SENSOR_PROY_POWER_STATE                      0x200319
 
+/* Batch mode selectors */
+#define HID_USAGE_SENSOR_PROP_REPORT_LATENCY                   0x20031B
+
 /* Per data field properties */
 #define HID_USAGE_SENSOR_DATA_MOD_NONE                                 0x00
 #define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS               0x1000
index 55535aef2e6cfae4ceffa83b6563a1ac61f6ffda..fa7d786ed99ef1ccde759b6cbc02ff7490067b84 100644 (file)
@@ -10,6 +10,7 @@
 #define _STM32_TIMER_TRIGGER_H_
 
 #define TIM1_TRGO      "tim1_trgo"
+#define TIM1_TRGO2     "tim1_trgo2"
 #define TIM1_CH1       "tim1_ch1"
 #define TIM1_CH2       "tim1_ch2"
 #define TIM1_CH3       "tim1_ch3"
@@ -44,6 +45,7 @@
 #define TIM7_TRGO      "tim7_trgo"
 
 #define TIM8_TRGO      "tim8_trgo"
+#define TIM8_TRGO2     "tim8_trgo2"
 #define TIM8_CH1       "tim8_ch1"
 #define TIM8_CH2       "tim8_ch2"
 #define TIM8_CH3       "tim8_ch3"
index 4a0abbc10ef6c2f4cd5c6ce0dbf7902024f55e05..ce7346e7f77a104414c58b6aa3f1ac2c95d04c56 100644 (file)
@@ -34,6 +34,7 @@
 #define TIM_CR1_DIR    BIT(4)  /* Counter Direction       */
 #define TIM_CR1_ARPE   BIT(7)  /* Auto-reload Preload Ena */
 #define TIM_CR2_MMS    (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
+#define TIM_CR2_MMS2   GENMASK(23, 20) /* Master mode selection 2 */
 #define TIM_SMCR_SMS   (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
 #define TIM_SMCR_TS    (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
 #define TIM_DIER_UIE   BIT(0)  /* Update interrupt        */
@@ -60,6 +61,7 @@
 
 #define MAX_TIM_PSC            0xFFFF
 #define TIM_CR2_MMS_SHIFT      4
+#define TIM_CR2_MMS2_SHIFT     20
 #define TIM_SMCR_TS_SHIFT      4
 #define TIM_BDTR_BKF_MASK      0xF
 #define TIM_BDTR_BKF_SHIFT     16
index 5446d625e17d63ab977900625581eed7a0de1735..8f08e03a9a5ecab158aa51e2c3493909d8c05b3c 100644 (file)
@@ -1,5 +1,5 @@
 CC = $(CROSS_COMPILE)gcc
-CFLAGS += -Wall -g -D_GNU_SOURCE
+CFLAGS += -Wall -g -D_GNU_SOURCE -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
 
 BINDIR=usr/bin
 INSTALL_PROGRAM=install -m 755 -p
index 780f2014f8fa224e761f312fd7124c5d73e70ce2..8b379da26e35d367c7aeecff465bc5154828def9 100644 (file)
@@ -13,7 +13,7 @@
 #include <stdint.h>
 
 /* Made up value to limit allocation sizes */
-#define IIO_MAX_NAME_LENGTH 30
+#define IIO_MAX_NAME_LENGTH 64
 
 #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
 #define FORMAT_TYPE_FILE "%s_type"