]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge tag 'iio-for-4.5a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Dec 2015 17:13:29 +0000 (09:13 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 Dec 2015 17:13:29 +0000 (09:13 -0800)
Jonathan writes:

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

Usual mixed bag, but the big item perhaps in this series is the DMA buffer
support added by Lars-Peter Clausen. It's been in the works for a long time
and it will be interesting to see what hardware support shows up now that
this is available.

New core features + associate cleanup.
* Add generic DMA buffer infrastructure
* Add a DMAengine framework based buffer
 Also associated minor changes.
   - Set the device buffer watermark based on the minimum watermark for all
     attached buffers rather than just the 'primary' one.
   - iio_buffer_init - only set the watermark default if one hasn't already
     been provided.  This allows simple support for devices with a fixed
     watermark.
   - read only attribute for watermark on fixed watermark devices.
   - add explicit buffer enable/disable callbacks to allow the buffer to
     do more than trivial actions when it is being turned on and off.
* IIO_VAL_INT support in write_raw_get_fmt function.

New device support
* Freescale MMA7455/7456L accelerometers
* Memsic MXC6255XC accelerometer
* ST lis2dh12 accelerometer
* TI ADS8688 ADC
* TI Palamas (twl6035/7) gpadc

New driver features
* mma8452
  - support either of the available interrupt pins to cope with the case
    where board layout has lead to a particular one being connected.

Staging graduation
* Dummy driver
  - this driver acts as both an example and a test device for those with
    out hardware to develop userspace code against.

Cleanups and minor bits and bobs.
* treewide
  - Sort out the ordering of iio_device_register/unregister vs runtime
    pm function calls so that it's all nice and consistent and not race
    prone.
  - Check sscanf return values.  None of the cases will actually happen as
    the strings are supplied internally, but best to be consistent on this.
* ad7780
  - switch over to the gpio descriptor interface and remove the now unused
    platform data which gets rid of a header entirely.
* ad7793
  - drop a pointless else statement.
* at91_adc
  - Swap kmalloc_array in for a kmalloc doing the same job.
* dummy
  - get rid of some commented out lines that snuck in during the move of
    the driver.
* lm3533-als
  - Print an error message on provision of an invalid resistance.
* mcp320x
  - Add compatible strings with vendor prefix and deprecate those with
    no vendor prefix.
* mxs-lradc
  - Use BIT macro in various places rather than shifted ones.
* pa12203001
  - Power off the chip if the registration fails.
* pulsedlight-lidar-lite
  - add runtime PM support.
* xilinx XADC
  - constify an iio_buffer_setup_ops structure.

70 files changed:
Documentation/devicetree/bindings/iio/accel/mma8452.txt
Documentation/devicetree/bindings/iio/adc/mcp320x.txt
Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/st-sensors.txt
drivers/iio/Kconfig
drivers/iio/Makefile
drivers/iio/accel/Kconfig
drivers/iio/accel/Makefile
drivers/iio/accel/bmc150-accel-core.c
drivers/iio/accel/kxcjk-1013.c
drivers/iio/accel/mma7455.h [new file with mode: 0644]
drivers/iio/accel/mma7455_core.c [new file with mode: 0644]
drivers/iio/accel/mma7455_i2c.c [new file with mode: 0644]
drivers/iio/accel/mma7455_spi.c [new file with mode: 0644]
drivers/iio/accel/mma8452.c
drivers/iio/accel/mma9551.c
drivers/iio/accel/mma9553.c
drivers/iio/accel/mxc6255.c [new file with mode: 0644]
drivers/iio/accel/st_accel.h
drivers/iio/accel/st_accel_core.c
drivers/iio/accel/st_accel_i2c.c
drivers/iio/accel/st_accel_spi.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/ad7793.c
drivers/iio/adc/at91_adc.c
drivers/iio/adc/mcp320x.c
drivers/iio/adc/palmas_gpadc.c [new file with mode: 0644]
drivers/iio/adc/ti-ads8688.c [new file with mode: 0644]
drivers/iio/adc/xilinx-xadc-core.c
drivers/iio/buffer/Kconfig
drivers/iio/buffer/Makefile
drivers/iio/buffer/industrialio-buffer-dma.c [new file with mode: 0644]
drivers/iio/buffer/industrialio-buffer-dmaengine.c [new file with mode: 0644]
drivers/iio/dummy/Kconfig [new file with mode: 0644]
drivers/iio/dummy/Makefile [new file with mode: 0644]
drivers/iio/dummy/iio_dummy_evgen.c [new file with mode: 0644]
drivers/iio/dummy/iio_dummy_evgen.h [new file with mode: 0644]
drivers/iio/dummy/iio_simple_dummy.c [new file with mode: 0644]
drivers/iio/dummy/iio_simple_dummy.h [new file with mode: 0644]
drivers/iio/dummy/iio_simple_dummy_buffer.c [new file with mode: 0644]
drivers/iio/dummy/iio_simple_dummy_events.c [new file with mode: 0644]
drivers/iio/gyro/adis16136.c
drivers/iio/gyro/bmg160_core.c
drivers/iio/imu/adis16400_core.c
drivers/iio/imu/adis16480.c
drivers/iio/imu/kmx61.c
drivers/iio/industrialio-buffer.c
drivers/iio/industrialio-core.c
drivers/iio/light/lm3533-als.c
drivers/iio/light/pa12203001.c
drivers/iio/light/rpr0521.c
drivers/iio/magnetometer/bmc150_magn.c
drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
drivers/staging/iio/Kconfig
drivers/staging/iio/Makefile
drivers/staging/iio/adc/ad7780.c
drivers/staging/iio/adc/ad7780.h [deleted file]
drivers/staging/iio/adc/mxs-lradc.c
drivers/staging/iio/iio_dummy_evgen.c [deleted file]
drivers/staging/iio/iio_dummy_evgen.h [deleted file]
drivers/staging/iio/iio_simple_dummy.c [deleted file]
drivers/staging/iio/iio_simple_dummy.h [deleted file]
drivers/staging/iio/iio_simple_dummy_buffer.c [deleted file]
drivers/staging/iio/iio_simple_dummy_events.c [deleted file]
include/linux/iio/buffer-dma.h [new file with mode: 0644]
include/linux/iio/buffer-dmaengine.h [new file with mode: 0644]
include/linux/iio/buffer.h
include/linux/mfd/palmas.h

index e3c37467d7dacb853bc2d2df7c3f26064c7566e5..3c10e8581144a128f380240ea8537bfc2a963956 100644 (file)
@@ -7,13 +7,18 @@ Required properties:
     * "fsl,mma8453"
     * "fsl,mma8652"
     * "fsl,mma8653"
+
   - reg: the I2C address of the chip
 
 Optional properties:
 
   - interrupt-parent: should be the phandle for the interrupt controller
+
   - interrupts: interrupt mapping for GPIO IRQ
 
+  - interrupt-names: should contain "INT1" and/or "INT2", the accelerometer's
+                    interrupt line in use.
+
 Example:
 
        mma8453fc@1d {
@@ -21,4 +26,5 @@ Example:
                reg = <0x1d>;
                interrupt-parent = <&gpio1>;
                interrupts = <5 0>;
+               interrupt-names = "INT2";
        };
index 2a1f3af30155d0f3a88d0c20ab4fc6711ded2ad1..bcd3ac8e6e0c57414b26aa60c91e543260208cdc 100644 (file)
@@ -10,16 +10,28 @@ must be specified.
 Required properties:
        - compatible:   Must be one of the following, depending on the
                        model:
-                               "mcp3001"
-                               "mcp3002"
-                               "mcp3004"
-                               "mcp3008"
-                               "mcp3201"
-                               "mcp3202"
-                               "mcp3204"
-                               "mcp3208"
-                               "mcp3301"
+                               "mcp3001" (DEPRECATED)
+                               "mcp3002" (DEPRECATED)
+                               "mcp3004" (DEPRECATED)
+                               "mcp3008" (DEPRECATED)
+                               "mcp3201" (DEPRECATED)
+                               "mcp3202" (DEPRECATED)
+                               "mcp3204" (DEPRECATED)
+                               "mcp3208" (DEPRECATED)
+                               "mcp3301" (DEPRECATED)
 
+                               "microchip,mcp3001"
+                               "microchip,mcp3002"
+                               "microchip,mcp3004"
+                               "microchip,mcp3008"
+                               "microchip,mcp3201"
+                               "microchip,mcp3202"
+                               "microchip,mcp3204"
+                               "microchip,mcp3208"
+                               "microchip,mcp3301"
+
+                       NOTE: The use of the compatibles with no vendor prefix
+                       is deprecated and only listed because old DT use them.
 
 Examples:
 spi_controller {
diff --git a/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt b/Documentation/devicetree/bindings/iio/adc/palmas-gpadc.txt
new file mode 100644 (file)
index 0000000..4bb9a86
--- /dev/null
@@ -0,0 +1,48 @@
+* Palmas general purpose ADC IP block devicetree bindings
+
+Channels list:
+       0 battery type
+       1 battery temp NTC (optional current source)
+       2 GP
+       3 temp (with ext. diode, optional current source)
+       4 GP
+       5 GP
+       6 VBAT_SENSE
+       7 VCC_SENSE
+       8 Backup Battery voltage
+       9 external charger (VCHG)
+       10 VBUS
+       11 DC-DC current probe (how does this work?)
+       12 internal die temp
+       13 internal die temp
+       14 USB ID pin voltage
+       15 test network
+
+Required properties:
+- compatible : Must be "ti,palmas-gpadc".
+- #io-channel-cells: Should be set to <1>.
+
+Optional sub-nodes:
+ti,channel0-current-microamp: Channel 0 current in uA.
+       Values are rounded to derive 0uA, 5uA, 15uA, 20uA.
+ti,channel3-current-microamp: Channel 3 current in uA.
+       Values are rounded to derive 0uA, 10uA, 400uA, 800uA.
+ti,enable-extended-delay: Enable extended delay.
+
+Example:
+
+pmic {
+       compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
+       ...
+       gpadc {
+               compatible = "ti,palmas-gpadc";
+               interrupts = <18 0
+                             16 0
+                             17 0>;
+               #io-channel-cells = <1>;
+               ti,channel0-current-microamp = <5>;
+               ti,channel3-current-microamp = <10>;
+               };
+       };
+       ...
+};
diff --git a/Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt b/Documentation/devicetree/bindings/iio/adc/ti-ads8688.txt
new file mode 100644 (file)
index 0000000..a02337d
--- /dev/null
@@ -0,0 +1,20 @@
+* Texas Instruments' ADS8684 and ADS8688 ADC chip
+
+Required properties:
+ - compatible: Should be "ti,ads8684" or "ti,ads8688"
+ - reg: spi chip select number for the device
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+               Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Optional properties:
+ - vref-supply: The regulator supply for ADC reference voltage
+
+Example:
+adc@0 {
+       compatible = "ti,ads8688";
+       reg = <0>;
+       vref-supply = <&vdd_supply>;
+       spi-max-frequency = <1000000>;
+};
index d3ccdb190c53b581f347ef2eb8444fcb3ac84592..d4b87cc1e446ec6dd73e367a2d1707a2ba0d5b96 100644 (file)
@@ -36,6 +36,7 @@ Accelerometers:
 - st,lsm303dlm-accel
 - st,lsm330-accel
 - st,lsm303agr-accel
+- st,lis2dh12-accel
 
 Gyroscopes:
 - st,l3g4200d-gyro
index 66792e707d74e8d3106a7c908565b5d90d03d79f..6b8c77c97d40dece2f2477e69b064cbed48321a8 100644 (file)
@@ -50,6 +50,7 @@ source "drivers/iio/amplifiers/Kconfig"
 source "drivers/iio/chemical/Kconfig"
 source "drivers/iio/common/Kconfig"
 source "drivers/iio/dac/Kconfig"
+source "drivers/iio/dummy/Kconfig"
 source "drivers/iio/frequency/Kconfig"
 source "drivers/iio/gyro/Kconfig"
 source "drivers/iio/humidity/Kconfig"
index aeca7269fe442967bd8704c8f9bf07ca0df3797a..6769f2f43e868b489cd40c7d873916c0c4ecb4a2 100644 (file)
@@ -16,6 +16,7 @@ obj-y += buffer/
 obj-y += chemical/
 obj-y += common/
 obj-y += dac/
+obj-y += dummy/
 obj-y += gyro/
 obj-y += frequency/
 obj-y += humidity/
index 969428dd63299af04e4200ae309f971463f3f5eb..edc29b173f6c9012635771116a6cca23193a096e 100644 (file)
@@ -64,7 +64,7 @@ config IIO_ST_ACCEL_3AXIS
        help
          Say yes here to build support for STMicroelectronics accelerometers:
          LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC,
-         LIS331DLH, LSM303DL, LSM303DLM, LSM330.
+         LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12.
 
          This driver can also be built as a module. If so, these modules
          will be created:
@@ -107,6 +107,35 @@ config KXCJK1013
          To compile this driver as a module, choose M here: the module will
          be called kxcjk-1013.
 
+config MMA7455
+       tristate
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+
+config MMA7455_I2C
+       tristate "Freescale MMA7455L/MMA7456L Accelerometer I2C Driver"
+       depends on I2C
+       select MMA7455
+       select REGMAP_I2C
+       help
+         Say yes here to build support for the Freescale MMA7455L and
+         MMA7456L 3-axis accelerometer.
+
+         To compile this driver as a module, choose M here: the module
+         will be called mma7455_i2c.
+
+config MMA7455_SPI
+       tristate "Freescale MMA7455L/MMA7456L Accelerometer SPI Driver"
+       depends on SPI_MASTER
+       select MMA7455
+       select REGMAP_SPI
+       help
+         Say yes here to build support for the Freescale MMA7455L and
+         MMA7456L 3-axis accelerometer.
+
+         To compile this driver as a module, choose M here: the module
+         will be called mma7455_spi.
+
 config MMA8452
        tristate "Freescale MMA8452Q and similar Accelerometers Driver"
        depends on I2C
@@ -158,6 +187,17 @@ config MXC4005
          To compile this driver as a module, choose M. The module will be
          called mxc4005.
 
+config MXC6255
+       tristate "Memsic MXC6255 Orientation Sensing Accelerometer Driver"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Say yes here to build support for the Memsic MXC6255 Orientation
+         Sensing Accelerometer Driver.
+
+         To compile this driver as a module, choose M here: the module will be
+         called mxc6255.
+
 config STK8312
        tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
        depends on I2C
index 7925f166e6e957c76cf7acc9862ea603f23d9ea0..71b6794de8858f967a1c8256a3dcd8b33e44e8cd 100644 (file)
@@ -10,6 +10,11 @@ obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
 obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
 obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
 obj-$(CONFIG_KXSD9)    += kxsd9.o
+
+obj-$(CONFIG_MMA7455)          += mma7455_core.o
+obj-$(CONFIG_MMA7455_I2C)      += mma7455_i2c.o
+obj-$(CONFIG_MMA7455_SPI)      += mma7455_spi.o
+
 obj-$(CONFIG_MMA8452)  += mma8452.o
 
 obj-$(CONFIG_MMA9551_CORE)     += mma9551_core.o
@@ -17,6 +22,7 @@ obj-$(CONFIG_MMA9551)         += mma9551.o
 obj-$(CONFIG_MMA9553)          += mma9553.o
 
 obj-$(CONFIG_MXC4005)          += mxc4005.o
+obj-$(CONFIG_MXC6255)          += mxc6255.o
 
 obj-$(CONFIG_STK8312)          += stk8312.o
 obj-$(CONFIG_STK8BA50)         += stk8ba50.o
index 2d33f1e821db0098a0d774e6c5d0fd44ba596675..c73331f7782b8af4b91c94c26dd29195ddc45d9a 100644 (file)
@@ -1623,24 +1623,22 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq,
                }
        }
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(dev, "Unable to register iio device\n");
-               goto err_trigger_unregister;
-       }
-
        ret = pm_runtime_set_active(dev);
        if (ret)
-               goto err_iio_unregister;
+               goto err_trigger_unregister;
 
        pm_runtime_enable(dev);
        pm_runtime_set_autosuspend_delay(dev, BMC150_AUTO_SUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(dev);
 
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(dev, "Unable to register iio device\n");
+               goto err_trigger_unregister;
+       }
+
        return 0;
 
-err_iio_unregister:
-       iio_device_unregister(indio_dev);
 err_trigger_unregister:
        bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 err_buffer_cleanup:
@@ -1655,12 +1653,12 @@ int bmc150_accel_core_remove(struct device *dev)
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct bmc150_accel_data *data = iio_priv(indio_dev);
 
+       iio_device_unregister(indio_dev);
+
        pm_runtime_disable(data->dev);
        pm_runtime_set_suspended(data->dev);
        pm_runtime_put_noidle(data->dev);
 
-       iio_device_unregister(indio_dev);
-
        bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
 
        iio_triggered_buffer_cleanup(indio_dev);
index 18c1b06684c1b4cb79d2fcb3812d16646fe62e98..edec1d099e917c6493afcfe0143651d23d1aa65c 100644 (file)
@@ -1264,25 +1264,23 @@ static int kxcjk1013_probe(struct i2c_client *client,
                goto err_trigger_unregister;
        }
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev, "unable to register iio device\n");
-               goto err_buffer_cleanup;
-       }
-
        ret = pm_runtime_set_active(&client->dev);
        if (ret)
-               goto err_iio_unregister;
+               goto err_buffer_cleanup;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev,
                                         KXCJK1013_SLEEP_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "unable to register iio device\n");
+               goto err_buffer_cleanup;
+       }
+
        return 0;
 
-err_iio_unregister:
-       iio_device_unregister(indio_dev);
 err_buffer_cleanup:
        if (data->dready_trig)
                iio_triggered_buffer_cleanup(indio_dev);
@@ -1302,12 +1300,12 @@ static int kxcjk1013_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct kxcjk1013_data *data = 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);
 
-       iio_device_unregister(indio_dev);
-
        if (data->dready_trig) {
                iio_triggered_buffer_cleanup(indio_dev);
                iio_trigger_unregister(data->dready_trig);
diff --git a/drivers/iio/accel/mma7455.h b/drivers/iio/accel/mma7455.h
new file mode 100644 (file)
index 0000000..2b1152c
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * IIO accel driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MMA7455_H
+#define __MMA7455_H
+
+extern const struct regmap_config mma7455_core_regmap;
+
+int mma7455_core_probe(struct device *dev, struct regmap *regmap,
+                      const char *name);
+int mma7455_core_remove(struct device *dev);
+
+#endif
diff --git a/drivers/iio/accel/mma7455_core.c b/drivers/iio/accel/mma7455_core.c
new file mode 100644 (file)
index 0000000..c633cc2
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * IIO accel core driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * UNSUPPORTED hardware features:
+ *  - 8-bit mode with different scales
+ *  - INT1/INT2 interrupts
+ *  - Offset calibration
+ *  - Events
+ */
+
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mma7455.h"
+
+#define MMA7455_REG_XOUTL              0x00
+#define MMA7455_REG_XOUTH              0x01
+#define MMA7455_REG_YOUTL              0x02
+#define MMA7455_REG_YOUTH              0x03
+#define MMA7455_REG_ZOUTL              0x04
+#define MMA7455_REG_ZOUTH              0x05
+#define MMA7455_REG_STATUS             0x09
+#define  MMA7455_STATUS_DRDY           BIT(0)
+#define MMA7455_REG_WHOAMI             0x0f
+#define  MMA7455_WHOAMI_ID             0x55
+#define MMA7455_REG_MCTL               0x16
+#define  MMA7455_MCTL_MODE_STANDBY     0x00
+#define  MMA7455_MCTL_MODE_MEASURE     0x01
+#define MMA7455_REG_CTL1               0x18
+#define  MMA7455_CTL1_DFBW_MASK                BIT(7)
+#define  MMA7455_CTL1_DFBW_125HZ       BIT(7)
+#define  MMA7455_CTL1_DFBW_62_5HZ      0
+#define MMA7455_REG_TW                 0x1e
+
+/*
+ * When MMA7455 is used in 10-bit it has a fullscale of -8g
+ * corresponding to raw value -512. The userspace interface
+ * uses m/s^2 and we declare micro units.
+ * So scale factor is given by:
+ *       g * 8 * 1e6 / 512 = 153228.90625, with g = 9.80665
+ */
+#define MMA7455_10BIT_SCALE    153229
+
+struct mma7455_data {
+       struct regmap *regmap;
+       struct device *dev;
+};
+
+static int mma7455_drdy(struct mma7455_data *mma7455)
+{
+       unsigned int reg;
+       int tries = 3;
+       int ret;
+
+       while (tries-- > 0) {
+               ret = regmap_read(mma7455->regmap, MMA7455_REG_STATUS, &reg);
+               if (ret)
+                       return ret;
+
+               if (reg & MMA7455_STATUS_DRDY)
+                       return 0;
+
+               msleep(20);
+       }
+
+       dev_warn(mma7455->dev, "data not ready\n");
+
+       return -EIO;
+}
+
+static irqreturn_t mma7455_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct mma7455_data *mma7455 = iio_priv(indio_dev);
+       u8 buf[16]; /* 3 x 16-bit channels + padding + ts */
+       int ret;
+
+       ret = mma7455_drdy(mma7455);
+       if (ret)
+               goto done;
+
+       ret = regmap_bulk_read(mma7455->regmap, MMA7455_REG_XOUTL, buf,
+                              sizeof(__le16) * 3);
+       if (ret)
+               goto done;
+
+       iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns());
+
+done:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int mma7455_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct mma7455_data *mma7455 = iio_priv(indio_dev);
+       unsigned int reg;
+       __le16 data;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               if (iio_buffer_enabled(indio_dev))
+                       return -EBUSY;
+
+               ret = mma7455_drdy(mma7455);
+               if (ret)
+                       return ret;
+
+               ret = regmap_bulk_read(mma7455->regmap, chan->address, &data,
+                                      sizeof(data));
+               if (ret)
+                       return ret;
+
+               *val = sign_extend32(le16_to_cpu(data), 9);
+
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = MMA7455_10BIT_SCALE;
+
+               return IIO_VAL_INT_PLUS_MICRO;
+
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = regmap_read(mma7455->regmap, MMA7455_REG_CTL1, &reg);
+               if (ret)
+                       return ret;
+
+               if (reg & MMA7455_CTL1_DFBW_MASK)
+                       *val = 250;
+               else
+                       *val = 125;
+
+               return IIO_VAL_INT;
+       }
+
+       return -EINVAL;
+}
+
+static int mma7455_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct mma7455_data *mma7455 = iio_priv(indio_dev);
+       int i;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               if (val == 250 && val2 == 0)
+                       i = MMA7455_CTL1_DFBW_125HZ;
+               else if (val == 125 && val2 == 0)
+                       i = MMA7455_CTL1_DFBW_62_5HZ;
+               else
+                       return -EINVAL;
+
+               return regmap_update_bits(mma7455->regmap, MMA7455_REG_CTL1,
+                                         MMA7455_CTL1_DFBW_MASK, i);
+
+       case IIO_CHAN_INFO_SCALE:
+               /* In 10-bit mode there is only one scale available */
+               if (val == 0 && val2 == MMA7455_10BIT_SCALE)
+                       return 0;
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_CONST_ATTR(sampling_frequency_available, "125 250");
+
+static struct attribute *mma7455_attributes[] = {
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group mma7455_group = {
+       .attrs = mma7455_attributes,
+};
+
+static const struct iio_info mma7455_info = {
+       .attrs = &mma7455_group,
+       .read_raw = mma7455_read_raw,
+       .write_raw = mma7455_write_raw,
+       .driver_module = THIS_MODULE,
+};
+
+#define MMA7455_CHANNEL(axis, idx) { \
+       .type = IIO_ACCEL, \
+       .modified = 1, \
+       .address = MMA7455_REG_##axis##OUTL,\
+       .channel2 = IIO_MOD_##axis, \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
+                                   BIT(IIO_CHAN_INFO_SCALE), \
+       .scan_index = idx, \
+       .scan_type = { \
+               .sign = 's', \
+               .realbits = 10, \
+               .storagebits = 16, \
+               .endianness = IIO_LE, \
+       }, \
+}
+
+static const struct iio_chan_spec mma7455_channels[] = {
+       MMA7455_CHANNEL(X, 0),
+       MMA7455_CHANNEL(Y, 1),
+       MMA7455_CHANNEL(Z, 2),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const unsigned long mma7455_scan_masks[] = {0x7, 0};
+
+const struct regmap_config mma7455_core_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = MMA7455_REG_TW,
+};
+EXPORT_SYMBOL_GPL(mma7455_core_regmap);
+
+int mma7455_core_probe(struct device *dev, struct regmap *regmap,
+                      const char *name)
+{
+       struct mma7455_data *mma7455;
+       struct iio_dev *indio_dev;
+       unsigned int reg;
+       int ret;
+
+       ret = regmap_read(regmap, MMA7455_REG_WHOAMI, &reg);
+       if (ret) {
+               dev_err(dev, "unable to read reg\n");
+               return ret;
+       }
+
+       if (reg != MMA7455_WHOAMI_ID) {
+               dev_err(dev, "device id mismatch\n");
+               return -ENODEV;
+       }
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*mma7455));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       dev_set_drvdata(dev, indio_dev);
+       mma7455 = iio_priv(indio_dev);
+       mma7455->regmap = regmap;
+       mma7455->dev = dev;
+
+       indio_dev->info = &mma7455_info;
+       indio_dev->name = name;
+       indio_dev->dev.parent = dev;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = mma7455_channels;
+       indio_dev->num_channels = ARRAY_SIZE(mma7455_channels);
+       indio_dev->available_scan_masks = mma7455_scan_masks;
+
+       regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
+                    MMA7455_MCTL_MODE_MEASURE);
+
+       ret = iio_triggered_buffer_setup(indio_dev, NULL,
+                                        mma7455_trigger_handler, NULL);
+       if (ret) {
+               dev_err(dev, "unable to setup triggered buffer\n");
+               return ret;
+       }
+
+       ret = iio_device_register(indio_dev);
+       if (ret) {
+               dev_err(dev, "unable to register device\n");
+               iio_triggered_buffer_cleanup(indio_dev);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mma7455_core_probe);
+
+int mma7455_core_remove(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct mma7455_data *mma7455 = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+       iio_triggered_buffer_cleanup(indio_dev);
+
+       regmap_write(mma7455->regmap, MMA7455_REG_MCTL,
+                    MMA7455_MCTL_MODE_STANDBY);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(mma7455_core_remove);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Freescale MMA7455L core accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma7455_i2c.c b/drivers/iio/accel/mma7455_i2c.c
new file mode 100644 (file)
index 0000000..3cab5fb
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * IIO accel I2C driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mma7455.h"
+
+static int mma7455_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct regmap *regmap;
+       const char *name = NULL;
+
+       regmap = devm_regmap_init_i2c(i2c, &mma7455_core_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       if (id)
+               name = id->name;
+
+       return mma7455_core_probe(&i2c->dev, regmap, name);
+}
+
+static int mma7455_i2c_remove(struct i2c_client *i2c)
+{
+       return mma7455_core_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id mma7455_i2c_ids[] = {
+       { "mma7455", 0 },
+       { "mma7456", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mma7455_i2c_ids);
+
+static struct i2c_driver mma7455_i2c_driver = {
+       .probe = mma7455_i2c_probe,
+       .remove = mma7455_i2c_remove,
+       .id_table = mma7455_i2c_ids,
+       .driver = {
+               .name   = "mma7455-i2c",
+       },
+};
+module_i2c_driver(mma7455_i2c_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Freescale MMA7455L I2C accelerometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/accel/mma7455_spi.c b/drivers/iio/accel/mma7455_spi.c
new file mode 100644 (file)
index 0000000..79df8f2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * IIO accel SPI driver for Freescale MMA7455L 3-axis 10-bit accelerometer
+ * Copyright 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "mma7455.h"
+
+static int mma7455_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct regmap *regmap;
+
+       regmap = devm_regmap_init_spi(spi, &mma7455_core_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       return mma7455_core_probe(&spi->dev, regmap, id->name);
+}
+
+static int mma7455_spi_remove(struct spi_device *spi)
+{
+       return mma7455_core_remove(&spi->dev);
+}
+
+static const struct spi_device_id mma7455_spi_ids[] = {
+       { "mma7455", 0 },
+       { "mma7456", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, mma7455_spi_ids);
+
+static struct spi_driver mma7455_spi_driver = {
+       .probe = mma7455_spi_probe,
+       .remove = mma7455_spi_remove,
+       .id_table = mma7455_spi_ids,
+       .driver = {
+               .name = "mma7455-spi",
+       },
+};
+module_spi_driver(mma7455_spi_driver);
+
+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
+MODULE_DESCRIPTION("Freescale MMA7455L SPI accelerometer driver");
+MODULE_LICENSE("GPL v2");
index 1eccc2dcf14cdcf53c6df1a5c9eb562a8d26db5c..116a6e401a6aa382896207786da8229c2ce41092 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/iio/events.h>
 #include <linux/delay.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 
 #define MMA8452_STATUS                         0x00
 #define  MMA8452_STATUS_DRDY                   (BIT(2) | BIT(1) | BIT(0))
@@ -1130,13 +1131,21 @@ static int mma8452_probe(struct i2c_client *client,
                                           MMA8452_INT_FF_MT;
                int enabled_interrupts = MMA8452_INT_TRANS |
                                         MMA8452_INT_FF_MT;
+               int irq2;
 
-               /* Assume wired to INT1 pin */
-               ret = i2c_smbus_write_byte_data(client,
-                                               MMA8452_CTRL_REG5,
-                                               supported_interrupts);
-               if (ret < 0)
-                       return ret;
+               irq2 = of_irq_get_byname(client->dev.of_node, "INT2");
+
+               if (irq2 == client->irq) {
+                       dev_dbg(&client->dev, "using interrupt line INT2\n");
+               } else {
+                       ret = i2c_smbus_write_byte_data(client,
+                                                       MMA8452_CTRL_REG5,
+                                                       supported_interrupts);
+                       if (ret < 0)
+                               return ret;
+
+                       dev_dbg(&client->dev, "using interrupt line INT1\n");
+               }
 
                ret = i2c_smbus_write_byte_data(client,
                                                MMA8452_CTRL_REG4,
index 7db7cc0bf362fceb3b97c770cc0ef0552dd4c4d3..d899a4d4307f9dbb9abf011281874ad629a6e026 100644 (file)
@@ -495,25 +495,23 @@ static int mma9551_probe(struct i2c_client *client,
        if (ret < 0)
                goto out_poweroff;
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev, "unable to register iio device\n");
-               goto out_poweroff;
-       }
-
        ret = pm_runtime_set_active(&client->dev);
        if (ret < 0)
-               goto out_iio_unregister;
+               goto out_poweroff;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev,
                                         MMA9551_AUTO_SUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "unable to register iio device\n");
+               goto out_poweroff;
+       }
+
        return 0;
 
-out_iio_unregister:
-       iio_device_unregister(indio_dev);
 out_poweroff:
        mma9551_set_device_state(client, false);
 
@@ -525,11 +523,12 @@ static int mma9551_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct mma9551_data *data = 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);
 
-       iio_device_unregister(indio_dev);
        mutex_lock(&data->mutex);
        mma9551_set_device_state(data->client, false);
        mutex_unlock(&data->mutex);
index 9408ef3add58fbe9cfbcbece029dd8c828c49329..fa7d36217c4ba9924064b92598740a6126eaadca 100644 (file)
@@ -1133,27 +1133,24 @@ static int mma9553_probe(struct i2c_client *client,
                }
        }
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev, "unable to register iio device\n");
-               goto out_poweroff;
-       }
-
        ret = pm_runtime_set_active(&client->dev);
        if (ret < 0)
-               goto out_iio_unregister;
+               goto out_poweroff;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev,
                                         MMA9551_AUTO_SUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
-       dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "unable to register iio device\n");
+               goto out_poweroff;
+       }
 
+       dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
        return 0;
 
-out_iio_unregister:
-       iio_device_unregister(indio_dev);
 out_poweroff:
        mma9551_set_device_state(client, false);
        return ret;
@@ -1164,11 +1161,12 @@ static int mma9553_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct mma9553_data *data = 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);
 
-       iio_device_unregister(indio_dev);
        mutex_lock(&data->mutex);
        mma9551_set_device_state(data->client, false);
        mutex_unlock(&data->mutex);
diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c
new file mode 100644 (file)
index 0000000..97ccde7
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * MXC6255 - MEMSIC orientation sensing accelerometer
+ *
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for MXC6255 (7-bit I2C slave address 0x15).
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/iio/iio.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/iio/sysfs.h>
+
+#define MXC6255_DRV_NAME               "mxc6255"
+#define MXC6255_REGMAP_NAME            "mxc6255_regmap"
+
+#define MXC6255_REG_XOUT               0x00
+#define MXC6255_REG_YOUT               0x01
+#define MXC6255_REG_CHIP_ID            0x08
+
+#define MXC6255_CHIP_ID                        0x05
+
+/*
+ * MXC6255 has only one measurement range: +/- 2G.
+ * The acceleration output is an 8-bit value.
+ *
+ * Scale is calculated as follows:
+ * (2 + 2) * 9.80665 / (2^8 - 1) = 0.153829
+ *
+ * Scale value for +/- 2G measurement range
+ */
+#define MXC6255_SCALE                  153829
+
+enum mxc6255_axis {
+       AXIS_X,
+       AXIS_Y,
+};
+
+struct mxc6255_data {
+       struct i2c_client *client;
+       struct regmap *regmap;
+};
+
+static int mxc6255_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long mask)
+{
+       struct mxc6255_data *data = iio_priv(indio_dev);
+       unsigned int reg;
+       int ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               ret = regmap_read(data->regmap, chan->address, &reg);
+               if (ret < 0) {
+                       dev_err(&data->client->dev,
+                               "Error reading reg %lu\n", chan->address);
+                       return ret;
+               }
+
+               *val = sign_extend32(reg, 7);
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               *val = 0;
+               *val2 = MXC6255_SCALE;
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static const struct iio_info mxc6255_info = {
+       .driver_module  = THIS_MODULE,
+       .read_raw       = mxc6255_read_raw,
+};
+
+#define MXC6255_CHANNEL(_axis, reg) {                          \
+       .type = IIO_ACCEL,                                      \
+       .modified = 1,                                          \
+       .channel2 = IIO_MOD_##_axis,                            \
+       .address = reg,                                         \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
+       .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+}
+
+static const struct iio_chan_spec mxc6255_channels[] = {
+       MXC6255_CHANNEL(X, MXC6255_REG_XOUT),
+       MXC6255_CHANNEL(Y, MXC6255_REG_YOUT),
+};
+
+static bool mxc6255_is_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MXC6255_REG_XOUT:
+       case MXC6255_REG_YOUT:
+       case MXC6255_REG_CHIP_ID:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static const struct regmap_config mxc6255_regmap_config = {
+       .name = MXC6255_REGMAP_NAME,
+
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .readable_reg = mxc6255_is_readable_reg,
+};
+
+static int mxc6255_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct mxc6255_data *data;
+       struct iio_dev *indio_dev;
+       struct regmap *regmap;
+       unsigned int chip_id;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       regmap = devm_regmap_init_i2c(client, &mxc6255_regmap_config);
+       if (IS_ERR(regmap)) {
+               dev_err(&client->dev, "Error initializing regmap\n");
+               return PTR_ERR(regmap);
+       }
+
+       data = iio_priv(indio_dev);
+       i2c_set_clientdata(client, indio_dev);
+       data->client = client;
+       data->regmap = regmap;
+
+       indio_dev->name = MXC6255_DRV_NAME;
+       indio_dev->dev.parent = &client->dev;
+       indio_dev->channels = mxc6255_channels;
+       indio_dev->num_channels = ARRAY_SIZE(mxc6255_channels);
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &mxc6255_info;
+
+       ret = regmap_read(data->regmap, MXC6255_REG_CHIP_ID, &chip_id);
+       if (ret < 0) {
+               dev_err(&client->dev, "Error reading chip id %d\n", ret);
+               return ret;
+       }
+
+       if (chip_id != MXC6255_CHIP_ID) {
+               dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
+               return -ENODEV;
+       }
+
+       dev_dbg(&client->dev, "Chip id %x\n", chip_id);
+
+       ret = devm_iio_device_register(&client->dev, indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "Could not register IIO device\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct acpi_device_id mxc6255_acpi_match[] = {
+       {"MXC6255",     0},
+       { }
+};
+MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
+
+static const struct i2c_device_id mxc6255_id[] = {
+       {"mxc6255",     0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mxc6255_id);
+
+static struct i2c_driver mxc6255_driver = {
+       .driver = {
+               .name = MXC6255_DRV_NAME,
+               .acpi_match_table = ACPI_PTR(mxc6255_acpi_match),
+       },
+       .probe          = mxc6255_probe,
+       .id_table       = mxc6255_id,
+};
+
+module_i2c_driver(mxc6255_driver);
+
+MODULE_AUTHOR("Teodora Baluta <teodora.baluta@intel.com>");
+MODULE_DESCRIPTION("MEMSIC MXC6255 orientation sensing accelerometer driver");
+MODULE_LICENSE("GPL v2");
index 468f21fa2950bd2bd59c226919b7b22be1407398..5d4a1897b293ec60644efe18f1f8d0508b051fa9 100644 (file)
@@ -27,6 +27,7 @@
 #define LSM303DLM_ACCEL_DEV_NAME       "lsm303dlm_accel"
 #define LSM330_ACCEL_DEV_NAME          "lsm330_accel"
 #define LSM303AGR_ACCEL_DEV_NAME       "lsm303agr_accel"
+#define LIS2DH12_ACCEL_DEV_NAME                "lis2dh12_accel"
 
 /**
 * struct st_sensors_platform_data - default accel platform data
index 197a08b4e2f3634ad48af3f246fb855d04f8b12d..70f042797f152a42bff02304987dad0c60d2fd0f 100644 (file)
@@ -232,6 +232,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
                        [3] = LSM330DL_ACCEL_DEV_NAME,
                        [4] = LSM330DLC_ACCEL_DEV_NAME,
                        [5] = LSM303AGR_ACCEL_DEV_NAME,
+                       [6] = LIS2DH12_ACCEL_DEV_NAME,
                },
                .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
                .odr = {
index 8b9cc84fd44f96be22186fb7364a5cf6259de701..294a32f89367b479fb29b4316b3f12c622db6efa 100644 (file)
@@ -72,6 +72,10 @@ static const struct of_device_id st_accel_of_match[] = {
                .compatible = "st,lsm303agr-accel",
                .data = LSM303AGR_ACCEL_DEV_NAME,
        },
+       {
+               .compatible = "st,lis2dh12-accel",
+               .data = LIS2DH12_ACCEL_DEV_NAME,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, st_accel_of_match);
@@ -121,6 +125,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
        { LSM303DLM_ACCEL_DEV_NAME },
        { LSM330_ACCEL_DEV_NAME },
        { LSM303AGR_ACCEL_DEV_NAME },
+       { LIS2DH12_ACCEL_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
index f71b0d391272476a96656bef1ad22172fd3e2f28..fcd5847a3fd34a11531e2db3ae6ed0365cd71bd5 100644 (file)
@@ -58,6 +58,7 @@ static const struct spi_device_id st_accel_id_table[] = {
        { LSM303DLM_ACCEL_DEV_NAME },
        { LSM330_ACCEL_DEV_NAME },
        { LSM303AGR_ACCEL_DEV_NAME },
+       { LIS2DH12_ACCEL_DEV_NAME },
        {},
 };
 MODULE_DEVICE_TABLE(spi, st_accel_id_table);
index 7868c744fd4bd25cc869f3a8c3d44ab348afbba2..9162dfefff30df5ff8ac75dc50a299d960e04a65 100644 (file)
@@ -275,6 +275,14 @@ config NAU7802
          To compile this driver as a module, choose M here: the
          module will be called nau7802.
 
+config PALMAS_GPADC
+       tristate "TI Palmas General Purpose ADC"
+       depends on MFD_PALMAS
+       help
+         Palmas series pmic chip by Texas Instruments (twl6035/6037)
+         is used in smartphones and tablets and supports a 16 channel
+         general purpose ADC.
+
 config QCOM_SPMI_IADC
        tristate "Qualcomm SPMI PMIC current ADC"
        depends on SPMI
@@ -333,6 +341,16 @@ config TI_ADC128S052
          This driver can also be built as a module. If so, the module will be
          called ti-adc128s052.
 
+config TI_ADS8688
+       tristate "Texas Instruments ADS8688"
+       depends on SPI && OF
+       help
+         If you say yes here you get support for Texas Instruments ADS8684 and
+         and ADS8688 ADC chips
+
+         This driver can also be built as a module. If so, the module will be
+         called ti-ads8688.
+
 config TI_AM335X_ADC
        tristate "TI's AM335X ADC driver"
        depends on MFD_TI_AM335X_TSCADC
index 99b37a963a1ef6ce2ee9b1ca981696ad97c76ecd..91a65bf11c584097b6373bcd356fdbf74c3aea68 100644 (file)
@@ -27,11 +27,13 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
+obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
 obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
 obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
+obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
 obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
 obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
 obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
index 4d960d3b93c0b45c70183ed5f4a218649d0dfb87..7b07bb651671c902082bb9a95640e14fd763a965 100644 (file)
@@ -478,10 +478,9 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
                                *val2 = st->
                                        scale_avail[(st->conf >> 8) & 0x7][1];
                                return IIO_VAL_INT_PLUS_NANO;
-                       } else {
-                               /* 1170mV / 2^23 * 6 */
-                               scale_uv = (1170ULL * 1000000000ULL * 6ULL);
                        }
+                       /* 1170mV / 2^23 * 6 */
+                       scale_uv = (1170ULL * 1000000000ULL * 6ULL);
                        break;
                case IIO_TEMP:
                                /* 1170mV / 0.81 mV/C / 2^23 */
index 7b40925dd4ff297e56fa0a3541980e9964d14092..f284cd6a93d6484fa942085b58e25f1b4de84fa5 100644 (file)
@@ -742,7 +742,7 @@ static int at91_adc_of_get_resolution(struct at91_adc_state *st,
                return count;
        }
 
-       resolutions = kmalloc(count * sizeof(*resolutions), GFP_KERNEL);
+       resolutions = kmalloc_array(count, sizeof(*resolutions), GFP_KERNEL);
        if (!resolutions)
                return -ENOMEM;
 
index 8569c8e1f4b276db3e968356626c67fab9b60c16..d1c05f6eed18124a907ab4e04fd255b1677c280b 100644 (file)
@@ -354,6 +354,7 @@ static int mcp320x_remove(struct spi_device *spi)
 
 #if defined(CONFIG_OF)
 static const struct of_device_id mcp320x_dt_ids[] = {
+       /* NOTE: The use of compatibles with no vendor prefix is deprecated. */
        {
                .compatible = "mcp3001",
                .data = &mcp320x_chip_infos[mcp3001],
@@ -381,6 +382,33 @@ static const struct of_device_id mcp320x_dt_ids[] = {
        }, {
                .compatible = "mcp3301",
                .data = &mcp320x_chip_infos[mcp3301],
+       }, {
+               .compatible = "microchip,mcp3001",
+               .data = &mcp320x_chip_infos[mcp3001],
+       }, {
+               .compatible = "microchip,mcp3002",
+               .data = &mcp320x_chip_infos[mcp3002],
+       }, {
+               .compatible = "microchip,mcp3004",
+               .data = &mcp320x_chip_infos[mcp3004],
+       }, {
+               .compatible = "microchip,mcp3008",
+               .data = &mcp320x_chip_infos[mcp3008],
+       }, {
+               .compatible = "microchip,mcp3201",
+               .data = &mcp320x_chip_infos[mcp3201],
+       }, {
+               .compatible = "microchip,mcp3202",
+               .data = &mcp320x_chip_infos[mcp3202],
+       }, {
+               .compatible = "microchip,mcp3204",
+               .data = &mcp320x_chip_infos[mcp3204],
+       }, {
+               .compatible = "microchip,mcp3208",
+               .data = &mcp320x_chip_infos[mcp3208],
+       }, {
+               .compatible = "microchip,mcp3301",
+               .data = &mcp320x_chip_infos[mcp3301],
        }, {
        }
 };
diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c
new file mode 100644 (file)
index 0000000..f42eb8a
--- /dev/null
@@ -0,0 +1,859 @@
+/*
+ * palmas-adc.c -- TI PALMAS GPADC.
+ *
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * Author: Pradeep Goudagunta <pgoudagunta@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/pm.h>
+#include <linux/mfd/palmas.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+#define MOD_NAME "palmas-gpadc"
+#define PALMAS_ADC_CONVERSION_TIMEOUT  (msecs_to_jiffies(5000))
+#define PALMAS_TO_BE_CALCULATED 0
+#define PALMAS_GPADC_TRIMINVALID       -1
+
+struct palmas_gpadc_info {
+/* calibration codes and regs */
+       int x1; /* lower ideal code */
+       int x2; /* higher ideal code */
+       int v1; /* expected lower volt reading */
+       int v2; /* expected higher volt reading */
+       u8 trim1_reg;   /* register number for lower trim */
+       u8 trim2_reg;   /* register number for upper trim */
+       int gain;       /* calculated from above (after reading trim regs) */
+       int offset;     /* calculated from above (after reading trim regs) */
+       int gain_error; /* calculated from above (after reading trim regs) */
+       bool is_uncalibrated;   /* if channel has calibration data */
+};
+
+#define PALMAS_ADC_INFO(_chan, _x1, _x2, _v1, _v2, _t1, _t2, _is_uncalibrated) \
+       [PALMAS_ADC_CH_##_chan] = { \
+               .x1 = _x1, \
+               .x2 = _x2, \
+               .v1 = _v1, \
+               .v2 = _v2, \
+               .gain = PALMAS_TO_BE_CALCULATED, \
+               .offset = PALMAS_TO_BE_CALCULATED, \
+               .gain_error = PALMAS_TO_BE_CALCULATED, \
+               .trim1_reg = PALMAS_GPADC_TRIM##_t1, \
+               .trim2_reg = PALMAS_GPADC_TRIM##_t2,  \
+               .is_uncalibrated = _is_uncalibrated \
+       }
+
+static struct palmas_gpadc_info palmas_gpadc_info[] = {
+       PALMAS_ADC_INFO(IN0, 2064, 3112, 630, 950, 1, 2, false),
+       PALMAS_ADC_INFO(IN1, 2064, 3112, 630, 950, 1, 2, false),
+       PALMAS_ADC_INFO(IN2, 2064, 3112, 1260, 1900, 3, 4, false),
+       PALMAS_ADC_INFO(IN3, 2064, 3112, 630, 950, 1, 2, false),
+       PALMAS_ADC_INFO(IN4, 2064, 3112, 630, 950, 1, 2, false),
+       PALMAS_ADC_INFO(IN5, 2064, 3112, 630, 950, 1, 2, false),
+       PALMAS_ADC_INFO(IN6, 2064, 3112, 2520, 3800, 5, 6, false),
+       PALMAS_ADC_INFO(IN7, 2064, 3112, 2520, 3800, 7, 8, false),
+       PALMAS_ADC_INFO(IN8, 2064, 3112, 3150, 4750, 9, 10, false),
+       PALMAS_ADC_INFO(IN9, 2064, 3112, 5670, 8550, 11, 12, false),
+       PALMAS_ADC_INFO(IN10, 2064, 3112, 3465, 5225, 13, 14, false),
+       PALMAS_ADC_INFO(IN11, 0, 0, 0, 0, INVALID, INVALID, true),
+       PALMAS_ADC_INFO(IN12, 0, 0, 0, 0, INVALID, INVALID, true),
+       PALMAS_ADC_INFO(IN13, 0, 0, 0, 0, INVALID, INVALID, true),
+       PALMAS_ADC_INFO(IN14, 2064, 3112, 3645, 5225, 15, 16, false),
+       PALMAS_ADC_INFO(IN15, 0, 0, 0, 0, INVALID, INVALID, true),
+};
+
+/**
+ * struct palmas_gpadc - the palmas_gpadc structure
+ * @ch0_current:       channel 0 current source setting
+ *                     0: 0 uA
+ *                     1: 5 uA
+ *                     2: 15 uA
+ *                     3: 20 uA
+ * @ch3_current:       channel 0 current source setting
+ *                     0: 0 uA
+ *                     1: 10 uA
+ *                     2: 400 uA
+ *                     3: 800 uA
+ * @extended_delay:    enable the gpadc extended delay mode
+ * @auto_conversion_period:    define the auto_conversion_period
+ *
+ * This is the palmas_gpadc structure to store run-time information
+ * and pointers for this driver instance.
+ */
+
+struct palmas_gpadc {
+       struct device                   *dev;
+       struct palmas                   *palmas;
+       u8                              ch0_current;
+       u8                              ch3_current;
+       bool                            extended_delay;
+       int                             irq;
+       int                             irq_auto_0;
+       int                             irq_auto_1;
+       struct palmas_gpadc_info        *adc_info;
+       struct completion               conv_completion;
+       struct palmas_adc_wakeup_property wakeup1_data;
+       struct palmas_adc_wakeup_property wakeup2_data;
+       bool                            wakeup1_enable;
+       bool                            wakeup2_enable;
+       int                             auto_conversion_period;
+};
+
+/*
+ * GPADC lock issue in AUTO mode.
+ * Impact: In AUTO mode, GPADC conversion can be locked after disabling AUTO
+ *        mode feature.
+ * Details:
+ *     When the AUTO mode is the only conversion mode enabled, if the AUTO
+ *     mode feature is disabled with bit GPADC_AUTO_CTRL.  AUTO_CONV1_EN = 0
+ *     or bit GPADC_AUTO_CTRL.  AUTO_CONV0_EN = 0 during a conversion, the
+ *     conversion mechanism can be seen as locked meaning that all following
+ *     conversion will give 0 as a result.  Bit GPADC_STATUS.GPADC_AVAILABLE
+ *     will stay at 0 meaning that GPADC is busy.  An RT conversion can unlock
+ *     the GPADC.
+ *
+ * Workaround(s):
+ *     To avoid the lock mechanism, the workaround to follow before any stop
+ *     conversion request is:
+ *     Force the GPADC state machine to be ON by using the GPADC_CTRL1.
+ *             GPADC_FORCE bit = 1
+ *     Shutdown the GPADC AUTO conversion using
+ *             GPADC_AUTO_CTRL.SHUTDOWN_CONV[01] = 0.
+ *     After 100us, force the GPADC state machine to be OFF by using the
+ *             GPADC_CTRL1.  GPADC_FORCE bit = 0
+ */
+
+static int palmas_disable_auto_conversion(struct palmas_gpadc *adc)
+{
+       int ret;
+
+       ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_CTRL1,
+                       PALMAS_GPADC_CTRL1_GPADC_FORCE,
+                       PALMAS_GPADC_CTRL1_GPADC_FORCE);
+       if (ret < 0) {
+               dev_err(adc->dev, "GPADC_CTRL1 update failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_AUTO_CTRL,
+                       PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 |
+                       PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0,
+                       0);
+       if (ret < 0) {
+               dev_err(adc->dev, "AUTO_CTRL update failed: %d\n", ret);
+               return ret;
+       }
+
+       udelay(100);
+
+       ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_CTRL1,
+                       PALMAS_GPADC_CTRL1_GPADC_FORCE, 0);
+       if (ret < 0)
+               dev_err(adc->dev, "GPADC_CTRL1 update failed: %d\n", ret);
+
+       return ret;
+}
+
+static irqreturn_t palmas_gpadc_irq(int irq, void *data)
+{
+       struct palmas_gpadc *adc = data;
+
+       complete(&adc->conv_completion);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t palmas_gpadc_irq_auto(int irq, void *data)
+{
+       struct palmas_gpadc *adc = data;
+
+       dev_dbg(adc->dev, "Threshold interrupt %d occurs\n", irq);
+       palmas_disable_auto_conversion(adc);
+
+       return IRQ_HANDLED;
+}
+
+static int palmas_gpadc_start_mask_interrupt(struct palmas_gpadc *adc,
+                                               bool mask)
+{
+       int ret;
+
+       if (!mask)
+               ret = palmas_update_bits(adc->palmas, PALMAS_INTERRUPT_BASE,
+                                       PALMAS_INT3_MASK,
+                                       PALMAS_INT3_MASK_GPADC_EOC_SW, 0);
+       else
+               ret = palmas_update_bits(adc->palmas, PALMAS_INTERRUPT_BASE,
+                                       PALMAS_INT3_MASK,
+                                       PALMAS_INT3_MASK_GPADC_EOC_SW,
+                                       PALMAS_INT3_MASK_GPADC_EOC_SW);
+       if (ret < 0)
+               dev_err(adc->dev, "GPADC INT MASK update failed: %d\n", ret);
+
+       return ret;
+}
+
+static int palmas_gpadc_enable(struct palmas_gpadc *adc, int adc_chan,
+                              int enable)
+{
+       unsigned int mask, val;
+       int ret;
+
+       if (enable) {
+               val = (adc->extended_delay
+                       << PALMAS_GPADC_RT_CTRL_EXTEND_DELAY_SHIFT);
+               ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                                       PALMAS_GPADC_RT_CTRL,
+                                       PALMAS_GPADC_RT_CTRL_EXTEND_DELAY, val);
+               if (ret < 0) {
+                       dev_err(adc->dev, "RT_CTRL update failed: %d\n", ret);
+                       return ret;
+               }
+
+               mask = (PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK |
+                       PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK |
+                       PALMAS_GPADC_CTRL1_GPADC_FORCE);
+               val = (adc->ch0_current
+                       << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT);
+               val |= (adc->ch3_current
+                       << PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT);
+               val |= PALMAS_GPADC_CTRL1_GPADC_FORCE;
+               ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_CTRL1, mask, val);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "Failed to update current setting: %d\n", ret);
+                       return ret;
+               }
+
+               mask = (PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_MASK |
+                       PALMAS_GPADC_SW_SELECT_SW_CONV_EN);
+               val = (adc_chan | PALMAS_GPADC_SW_SELECT_SW_CONV_EN);
+               ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_SW_SELECT, mask, val);
+               if (ret < 0) {
+                       dev_err(adc->dev, "SW_SELECT update failed: %d\n", ret);
+                       return ret;
+               }
+       } else {
+               ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_SW_SELECT, 0);
+               if (ret < 0)
+                       dev_err(adc->dev, "SW_SELECT write failed: %d\n", ret);
+
+               ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_CTRL1,
+                               PALMAS_GPADC_CTRL1_GPADC_FORCE, 0);
+               if (ret < 0) {
+                       dev_err(adc->dev, "CTRL1 update failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+static int palmas_gpadc_read_prepare(struct palmas_gpadc *adc, int adc_chan)
+{
+       int ret;
+
+       ret = palmas_gpadc_enable(adc, adc_chan, true);
+       if (ret < 0)
+               return ret;
+
+       return palmas_gpadc_start_mask_interrupt(adc, 0);
+}
+
+static void palmas_gpadc_read_done(struct palmas_gpadc *adc, int adc_chan)
+{
+       palmas_gpadc_start_mask_interrupt(adc, 1);
+       palmas_gpadc_enable(adc, adc_chan, false);
+}
+
+static int palmas_gpadc_calibrate(struct palmas_gpadc *adc, int adc_chan)
+{
+       int k;
+       int d1;
+       int d2;
+       int ret;
+       int gain;
+       int x1 =  adc->adc_info[adc_chan].x1;
+       int x2 =  adc->adc_info[adc_chan].x2;
+       int v1 = adc->adc_info[adc_chan].v1;
+       int v2 = adc->adc_info[adc_chan].v2;
+
+       ret = palmas_read(adc->palmas, PALMAS_TRIM_GPADC_BASE,
+                               adc->adc_info[adc_chan].trim1_reg, &d1);
+       if (ret < 0) {
+               dev_err(adc->dev, "TRIM read failed: %d\n", ret);
+               goto scrub;
+       }
+
+       ret = palmas_read(adc->palmas, PALMAS_TRIM_GPADC_BASE,
+                               adc->adc_info[adc_chan].trim2_reg, &d2);
+       if (ret < 0) {
+               dev_err(adc->dev, "TRIM read failed: %d\n", ret);
+               goto scrub;
+       }
+
+       /* gain error calculation */
+       k = (1000 + (1000 * (d2 - d1)) / (x2 - x1));
+
+       /* gain calculation */
+       gain = ((v2 - v1) * 1000) / (x2 - x1);
+
+       adc->adc_info[adc_chan].gain_error = k;
+       adc->adc_info[adc_chan].gain = gain;
+       /* offset Calculation */
+       adc->adc_info[adc_chan].offset = (d1 * 1000) - ((k - 1000) * x1);
+
+scrub:
+       return ret;
+}
+
+static int palmas_gpadc_start_conversion(struct palmas_gpadc *adc, int adc_chan)
+{
+       unsigned int val;
+       int ret;
+
+       init_completion(&adc->conv_completion);
+       ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_SW_SELECT,
+                               PALMAS_GPADC_SW_SELECT_SW_START_CONV0,
+                               PALMAS_GPADC_SW_SELECT_SW_START_CONV0);
+       if (ret < 0) {
+               dev_err(adc->dev, "SELECT_SW_START write failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = wait_for_completion_timeout(&adc->conv_completion,
+                               PALMAS_ADC_CONVERSION_TIMEOUT);
+       if (ret == 0) {
+               dev_err(adc->dev, "conversion not completed\n");
+               return -ETIMEDOUT;
+       }
+
+       ret = palmas_bulk_read(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_SW_CONV0_LSB, &val, 2);
+       if (ret < 0) {
+               dev_err(adc->dev, "SW_CONV0_LSB read failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = val & 0xFFF;
+
+       return ret;
+}
+
+static int palmas_gpadc_get_calibrated_code(struct palmas_gpadc *adc,
+                                               int adc_chan, int val)
+{
+       if (!adc->adc_info[adc_chan].is_uncalibrated)
+               val  = (val*1000 - adc->adc_info[adc_chan].offset) /
+                                       adc->adc_info[adc_chan].gain_error;
+
+       if (val < 0) {
+               dev_err(adc->dev, "Mismatch with calibration\n");
+               return 0;
+       }
+
+       val = (val * adc->adc_info[adc_chan].gain) / 1000;
+
+       return val;
+}
+
+static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
+       struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+       struct  palmas_gpadc *adc = iio_priv(indio_dev);
+       int adc_chan = chan->channel;
+       int ret = 0;
+
+       if (adc_chan > PALMAS_ADC_CH_MAX)
+               return -EINVAL;
+
+       mutex_lock(&indio_dev->mlock);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+       case IIO_CHAN_INFO_PROCESSED:
+               ret = palmas_gpadc_read_prepare(adc, adc_chan);
+               if (ret < 0)
+                       goto out;
+
+               ret = palmas_gpadc_start_conversion(adc, adc_chan);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                       "ADC start conversion failed\n");
+                       goto out;
+               }
+
+               if (mask == IIO_CHAN_INFO_PROCESSED)
+                       ret = palmas_gpadc_get_calibrated_code(
+                                                       adc, adc_chan, ret);
+
+               *val = ret;
+
+               ret = IIO_VAL_INT;
+               goto out;
+       }
+
+       mutex_unlock(&indio_dev->mlock);
+       return ret;
+
+out:
+       palmas_gpadc_read_done(adc, adc_chan);
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static const struct iio_info palmas_gpadc_iio_info = {
+       .read_raw = palmas_gpadc_read_raw,
+       .driver_module = THIS_MODULE,
+};
+
+#define PALMAS_ADC_CHAN_IIO(chan, _type, chan_info)    \
+{                                                      \
+       .datasheet_name = PALMAS_DATASHEET_NAME(chan),  \
+       .type = _type,                                  \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
+                       BIT(chan_info),                 \
+       .indexed = 1,                                   \
+       .channel = PALMAS_ADC_CH_##chan,                \
+}
+
+static const struct iio_chan_spec palmas_gpadc_iio_channel[] = {
+       PALMAS_ADC_CHAN_IIO(IN0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN1, IIO_TEMP, IIO_CHAN_INFO_RAW),
+       PALMAS_ADC_CHAN_IIO(IN2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN3, IIO_TEMP, IIO_CHAN_INFO_RAW),
+       PALMAS_ADC_CHAN_IIO(IN4, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN12, IIO_TEMP, IIO_CHAN_INFO_RAW),
+       PALMAS_ADC_CHAN_IIO(IN13, IIO_TEMP, IIO_CHAN_INFO_RAW),
+       PALMAS_ADC_CHAN_IIO(IN14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+       PALMAS_ADC_CHAN_IIO(IN15, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
+};
+
+static int palmas_gpadc_get_adc_dt_data(struct platform_device *pdev,
+       struct palmas_gpadc_platform_data **gpadc_pdata)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct palmas_gpadc_platform_data *gp_data;
+       int ret;
+       u32 pval;
+
+       gp_data = devm_kzalloc(&pdev->dev, sizeof(*gp_data), GFP_KERNEL);
+       if (!gp_data)
+               return -ENOMEM;
+
+       ret = of_property_read_u32(np, "ti,channel0-current-microamp", &pval);
+       if (!ret)
+               gp_data->ch0_current = pval;
+
+       ret = of_property_read_u32(np, "ti,channel3-current-microamp", &pval);
+       if (!ret)
+               gp_data->ch3_current = pval;
+
+       gp_data->extended_delay = of_property_read_bool(np,
+                                       "ti,enable-extended-delay");
+
+       *gpadc_pdata = gp_data;
+
+       return 0;
+}
+
+static int palmas_gpadc_probe(struct platform_device *pdev)
+{
+       struct palmas_gpadc *adc;
+       struct palmas_platform_data *pdata;
+       struct palmas_gpadc_platform_data *gpadc_pdata = NULL;
+       struct iio_dev *indio_dev;
+       int ret, i;
+
+       pdata = dev_get_platdata(pdev->dev.parent);
+
+       if (pdata && pdata->gpadc_pdata)
+               gpadc_pdata = pdata->gpadc_pdata;
+
+       if (!gpadc_pdata && pdev->dev.of_node) {
+               ret = palmas_gpadc_get_adc_dt_data(pdev, &gpadc_pdata);
+               if (ret < 0)
+                       return ret;
+       }
+       if (!gpadc_pdata)
+               return -EINVAL;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
+       if (!indio_dev) {
+               dev_err(&pdev->dev, "iio_device_alloc failed\n");
+               return -ENOMEM;
+       }
+
+       adc = iio_priv(indio_dev);
+       adc->dev = &pdev->dev;
+       adc->palmas = dev_get_drvdata(pdev->dev.parent);
+       adc->adc_info = palmas_gpadc_info;
+       init_completion(&adc->conv_completion);
+       dev_set_drvdata(&pdev->dev, indio_dev);
+
+       adc->auto_conversion_period = gpadc_pdata->auto_conversion_period_ms;
+       adc->irq = palmas_irq_get_virq(adc->palmas, PALMAS_GPADC_EOC_SW_IRQ);
+       if (adc->irq < 0) {
+               dev_err(adc->dev,
+                       "get virq failed: %d\n", adc->irq);
+               ret = adc->irq;
+               goto out;
+       }
+       ret = request_threaded_irq(adc->irq, NULL,
+               palmas_gpadc_irq,
+               IRQF_ONESHOT | IRQF_EARLY_RESUME, dev_name(adc->dev),
+               adc);
+       if (ret < 0) {
+               dev_err(adc->dev,
+                       "request irq %d failed: %d\n", adc->irq, ret);
+               goto out;
+       }
+
+       if (gpadc_pdata->adc_wakeup1_data) {
+               memcpy(&adc->wakeup1_data, gpadc_pdata->adc_wakeup1_data,
+                       sizeof(adc->wakeup1_data));
+               adc->wakeup1_enable = true;
+               adc->irq_auto_0 =  platform_get_irq(pdev, 1);
+               ret = request_threaded_irq(adc->irq_auto_0, NULL,
+                               palmas_gpadc_irq_auto,
+                               IRQF_ONESHOT | IRQF_EARLY_RESUME,
+                               "palmas-adc-auto-0", adc);
+               if (ret < 0) {
+                       dev_err(adc->dev, "request auto0 irq %d failed: %d\n",
+                               adc->irq_auto_0, ret);
+                       goto out_irq_free;
+               }
+       }
+
+       if (gpadc_pdata->adc_wakeup2_data) {
+               memcpy(&adc->wakeup2_data, gpadc_pdata->adc_wakeup2_data,
+                               sizeof(adc->wakeup2_data));
+               adc->wakeup2_enable = true;
+               adc->irq_auto_1 =  platform_get_irq(pdev, 2);
+               ret = request_threaded_irq(adc->irq_auto_1, NULL,
+                               palmas_gpadc_irq_auto,
+                               IRQF_ONESHOT | IRQF_EARLY_RESUME,
+                               "palmas-adc-auto-1", adc);
+               if (ret < 0) {
+                       dev_err(adc->dev, "request auto1 irq %d failed: %d\n",
+                               adc->irq_auto_1, ret);
+                       goto out_irq_auto0_free;
+               }
+       }
+
+       /* set the current source 0 (value 0/5/15/20 uA => 0..3) */
+       if (gpadc_pdata->ch0_current <= 1)
+               adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_0;
+       else if (gpadc_pdata->ch0_current <= 5)
+               adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_5;
+       else if (gpadc_pdata->ch0_current <= 15)
+               adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_15;
+       else
+               adc->ch0_current = PALMAS_ADC_CH0_CURRENT_SRC_20;
+
+       /* set the current source 3 (value 0/10/400/800 uA => 0..3) */
+       if (gpadc_pdata->ch3_current <= 1)
+               adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_0;
+       else if (gpadc_pdata->ch3_current <= 10)
+               adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_10;
+       else if (gpadc_pdata->ch3_current <= 400)
+               adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_400;
+       else
+               adc->ch3_current = PALMAS_ADC_CH3_CURRENT_SRC_800;
+
+       adc->extended_delay = gpadc_pdata->extended_delay;
+
+       indio_dev->name = MOD_NAME;
+       indio_dev->dev.parent = &pdev->dev;
+       indio_dev->info = &palmas_gpadc_iio_info;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = palmas_gpadc_iio_channel;
+       indio_dev->num_channels = ARRAY_SIZE(palmas_gpadc_iio_channel);
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(adc->dev, "iio_device_register() failed: %d\n", ret);
+               goto out_irq_auto1_free;
+       }
+
+       device_set_wakeup_capable(&pdev->dev, 1);
+       for (i = 0; i < PALMAS_ADC_CH_MAX; i++) {
+               if (!(adc->adc_info[i].is_uncalibrated))
+                       palmas_gpadc_calibrate(adc, i);
+       }
+
+       if (adc->wakeup1_enable || adc->wakeup2_enable)
+               device_wakeup_enable(&pdev->dev);
+
+       return 0;
+
+out_irq_auto1_free:
+       if (gpadc_pdata->adc_wakeup2_data)
+               free_irq(adc->irq_auto_1, adc);
+out_irq_auto0_free:
+       if (gpadc_pdata->adc_wakeup1_data)
+               free_irq(adc->irq_auto_0, adc);
+out_irq_free:
+       free_irq(adc->irq, adc);
+out:
+       return ret;
+}
+
+static int palmas_gpadc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(&pdev->dev);
+       struct palmas_gpadc *adc = iio_priv(indio_dev);
+
+       if (adc->wakeup1_enable || adc->wakeup2_enable)
+               device_wakeup_disable(&pdev->dev);
+       iio_device_unregister(indio_dev);
+       free_irq(adc->irq, adc);
+       if (adc->wakeup1_enable)
+               free_irq(adc->irq_auto_0, adc);
+       if (adc->wakeup2_enable)
+               free_irq(adc->irq_auto_1, adc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int palmas_adc_wakeup_configure(struct palmas_gpadc *adc)
+{
+       int adc_period, conv;
+       int i;
+       int ch0 = 0, ch1 = 0;
+       int thres;
+       int ret;
+
+       adc_period = adc->auto_conversion_period;
+       for (i = 0; i < 16; ++i) {
+               if (((1000 * (1 << i)) / 32) < adc_period)
+                       continue;
+       }
+       if (i > 0)
+               i--;
+       adc_period = i;
+       ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_AUTO_CTRL,
+                       PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK,
+                       adc_period);
+       if (ret < 0) {
+               dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
+               return ret;
+       }
+
+       conv = 0;
+       if (adc->wakeup1_enable) {
+               int polarity;
+
+               ch0 = adc->wakeup1_data.adc_channel_number;
+               conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN;
+               if (adc->wakeup1_data.adc_high_threshold > 0) {
+                       thres = adc->wakeup1_data.adc_high_threshold;
+                       polarity = 0;
+               } else {
+                       thres = adc->wakeup1_data.adc_low_threshold;
+                       polarity = PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL;
+               }
+
+               ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_THRES_CONV0_LSB, thres & 0xFF);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "THRES_CONV0_LSB write failed: %d\n", ret);
+                       return ret;
+               }
+
+               ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_THRES_CONV0_MSB,
+                               ((thres >> 8) & 0xF) | polarity);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "THRES_CONV0_MSB write failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (adc->wakeup2_enable) {
+               int polarity;
+
+               ch1 = adc->wakeup2_data.adc_channel_number;
+               conv |= PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN;
+               if (adc->wakeup2_data.adc_high_threshold > 0) {
+                       thres = adc->wakeup2_data.adc_high_threshold;
+                       polarity = 0;
+               } else {
+                       thres = adc->wakeup2_data.adc_low_threshold;
+                       polarity = PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL;
+               }
+
+               ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_THRES_CONV1_LSB, thres & 0xFF);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "THRES_CONV1_LSB write failed: %d\n", ret);
+                       return ret;
+               }
+
+               ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                               PALMAS_GPADC_THRES_CONV1_MSB,
+                               ((thres >> 8) & 0xF) | polarity);
+               if (ret < 0) {
+                       dev_err(adc->dev,
+                               "THRES_CONV1_MSB write failed: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_AUTO_SELECT, (ch1 << 4) | ch0);
+       if (ret < 0) {
+               dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = palmas_update_bits(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_AUTO_CTRL,
+                       PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN |
+                       PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN, conv);
+       if (ret < 0)
+               dev_err(adc->dev, "AUTO_CTRL write failed: %d\n", ret);
+
+       return ret;
+}
+
+static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc)
+{
+       int ret;
+
+       ret = palmas_write(adc->palmas, PALMAS_GPADC_BASE,
+                       PALMAS_GPADC_AUTO_SELECT, 0);
+       if (ret < 0) {
+               dev_err(adc->dev, "AUTO_SELECT write failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = palmas_disable_auto_conversion(adc);
+       if (ret < 0)
+               dev_err(adc->dev, "Disable auto conversion failed: %d\n", ret);
+
+       return ret;
+}
+
+static int palmas_gpadc_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct palmas_gpadc *adc = iio_priv(indio_dev);
+       int wakeup = adc->wakeup1_enable || adc->wakeup2_enable;
+       int ret;
+
+       if (!device_may_wakeup(dev) || !wakeup)
+               return 0;
+
+       ret = palmas_adc_wakeup_configure(adc);
+       if (ret < 0)
+               return ret;
+
+       if (adc->wakeup1_enable)
+               enable_irq_wake(adc->irq_auto_0);
+
+       if (adc->wakeup2_enable)
+               enable_irq_wake(adc->irq_auto_1);
+
+       return 0;
+}
+
+static int palmas_gpadc_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct palmas_gpadc *adc = iio_priv(indio_dev);
+       int wakeup = adc->wakeup1_enable || adc->wakeup2_enable;
+       int ret;
+
+       if (!device_may_wakeup(dev) || !wakeup)
+               return 0;
+
+       ret = palmas_adc_wakeup_reset(adc);
+       if (ret < 0)
+               return ret;
+
+       if (adc->wakeup1_enable)
+               disable_irq_wake(adc->irq_auto_0);
+
+       if (adc->wakeup2_enable)
+               disable_irq_wake(adc->irq_auto_1);
+
+       return 0;
+};
+#endif
+
+static const struct dev_pm_ops palmas_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(palmas_gpadc_suspend,
+                               palmas_gpadc_resume)
+};
+
+static const struct of_device_id of_palmas_gpadc_match_tbl[] = {
+       { .compatible = "ti,palmas-gpadc", },
+       { /* end */ }
+};
+MODULE_DEVICE_TABLE(of, of_palmas_gpadc_match_tbl);
+
+static struct platform_driver palmas_gpadc_driver = {
+       .probe = palmas_gpadc_probe,
+       .remove = palmas_gpadc_remove,
+       .driver = {
+               .name = MOD_NAME,
+               .pm = &palmas_pm_ops,
+               .of_match_table = of_palmas_gpadc_match_tbl,
+       },
+};
+
+static int __init palmas_gpadc_init(void)
+{
+       return platform_driver_register(&palmas_gpadc_driver);
+}
+module_init(palmas_gpadc_init);
+
+static void __exit palmas_gpadc_exit(void)
+{
+       platform_driver_unregister(&palmas_gpadc_driver);
+}
+module_exit(palmas_gpadc_exit);
+
+MODULE_DESCRIPTION("palmas GPADC driver");
+MODULE_AUTHOR("Pradeep Goudagunta<pgoudagunta@nvidia.com>");
+MODULE_ALIAS("platform:palmas-gpadc");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c
new file mode 100644 (file)
index 0000000..03e9070
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2015 Prevas A/S
+ *
+ * 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/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define ADS8688_CMD_REG(x)             (x << 8)
+#define ADS8688_CMD_REG_NOOP           0x00
+#define ADS8688_CMD_REG_RST            0x85
+#define ADS8688_CMD_REG_MAN_CH(chan)   (0xC0 | (4 * chan))
+#define ADS8688_CMD_DONT_CARE_BITS     16
+
+#define ADS8688_PROG_REG(x)            (x << 9)
+#define ADS8688_PROG_REG_RANGE_CH(chan)        (0x05 + chan)
+#define ADS8688_PROG_WR_BIT            BIT(8)
+#define ADS8688_PROG_DONT_CARE_BITS    8
+
+#define ADS8688_REG_PLUSMINUS25VREF    0
+#define ADS8688_REG_PLUSMINUS125VREF   1
+#define ADS8688_REG_PLUSMINUS0625VREF  2
+#define ADS8688_REG_PLUS25VREF         5
+#define ADS8688_REG_PLUS125VREF                6
+
+#define ADS8688_VREF_MV                        4096
+#define ADS8688_REALBITS               16
+
+/*
+ * enum ads8688_range - ADS8688 reference voltage range
+ * @ADS8688_PLUSMINUS25VREF: Device is configured for input range Â±2.5 * VREF
+ * @ADS8688_PLUSMINUS125VREF: Device is configured for input range Â±1.25 * VREF
+ * @ADS8688_PLUSMINUS0625VREF: Device is configured for input range Â±0.625 * VREF
+ * @ADS8688_PLUS25VREF: Device is configured for input range 0 - 2.5 * VREF
+ * @ADS8688_PLUS125VREF: Device is configured for input range 0 - 1.25 * VREF
+ */
+enum ads8688_range {
+       ADS8688_PLUSMINUS25VREF,
+       ADS8688_PLUSMINUS125VREF,
+       ADS8688_PLUSMINUS0625VREF,
+       ADS8688_PLUS25VREF,
+       ADS8688_PLUS125VREF,
+};
+
+struct ads8688_chip_info {
+       const struct iio_chan_spec *channels;
+       unsigned int num_channels;
+};
+
+struct ads8688_state {
+       struct mutex                    lock;
+       const struct ads8688_chip_info  *chip_info;
+       struct spi_device               *spi;
+       struct regulator                *reg;
+       unsigned int                    vref_mv;
+       enum ads8688_range              range[8];
+       union {
+               __be32 d32;
+               u8 d8[4];
+       } data[2] ____cacheline_aligned;
+};
+
+enum ads8688_id {
+       ID_ADS8684,
+       ID_ADS8688,
+};
+
+struct ads8688_ranges {
+       enum ads8688_range range;
+       unsigned int scale;
+       int offset;
+       u8 reg;
+};
+
+static const struct ads8688_ranges ads8688_range_def[5] = {
+       {
+               .range = ADS8688_PLUSMINUS25VREF,
+               .scale = 76295,
+               .offset = -(1 << (ADS8688_REALBITS - 1)),
+               .reg = ADS8688_REG_PLUSMINUS25VREF,
+       }, {
+               .range = ADS8688_PLUSMINUS125VREF,
+               .scale = 38148,
+               .offset = -(1 << (ADS8688_REALBITS - 1)),
+               .reg = ADS8688_REG_PLUSMINUS125VREF,
+       }, {
+               .range = ADS8688_PLUSMINUS0625VREF,
+               .scale = 19074,
+               .offset = -(1 << (ADS8688_REALBITS - 1)),
+               .reg = ADS8688_REG_PLUSMINUS0625VREF,
+       }, {
+               .range = ADS8688_PLUS25VREF,
+               .scale = 38148,
+               .offset = 0,
+               .reg = ADS8688_REG_PLUS25VREF,
+       }, {
+               .range = ADS8688_PLUS125VREF,
+               .scale = 19074,
+               .offset = 0,
+               .reg = ADS8688_REG_PLUS125VREF,
+       }
+};
+
+static ssize_t ads8688_show_scales(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct ads8688_state *st = iio_priv(dev_to_iio_dev(dev));
+
+       return sprintf(buf, "0.%09u 0.%09u 0.%09u\n",
+                      ads8688_range_def[0].scale * st->vref_mv,
+                      ads8688_range_def[1].scale * st->vref_mv,
+                      ads8688_range_def[2].scale * st->vref_mv);
+}
+
+static ssize_t ads8688_show_offsets(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d %d\n", ads8688_range_def[0].offset,
+                      ads8688_range_def[3].offset);
+}
+
+static IIO_DEVICE_ATTR(in_voltage_scale_available, S_IRUGO,
+                      ads8688_show_scales, NULL, 0);
+static IIO_DEVICE_ATTR(in_voltage_offset_available, S_IRUGO,
+                      ads8688_show_offsets, NULL, 0);
+
+static struct attribute *ads8688_attributes[] = {
+       &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
+       &iio_dev_attr_in_voltage_offset_available.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ads8688_attribute_group = {
+       .attrs = ads8688_attributes,
+};
+
+#define ADS8688_CHAN(index)                                    \
+{                                                              \
+       .type = IIO_VOLTAGE,                                    \
+       .indexed = 1,                                           \
+       .channel = index,                                       \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)            \
+                             | BIT(IIO_CHAN_INFO_SCALE)        \
+                             | BIT(IIO_CHAN_INFO_OFFSET),      \
+}
+
+static const struct iio_chan_spec ads8684_channels[] = {
+       ADS8688_CHAN(0),
+       ADS8688_CHAN(1),
+       ADS8688_CHAN(2),
+       ADS8688_CHAN(3),
+};
+
+static const struct iio_chan_spec ads8688_channels[] = {
+       ADS8688_CHAN(0),
+       ADS8688_CHAN(1),
+       ADS8688_CHAN(2),
+       ADS8688_CHAN(3),
+       ADS8688_CHAN(4),
+       ADS8688_CHAN(5),
+       ADS8688_CHAN(6),
+       ADS8688_CHAN(7),
+};
+
+static int ads8688_prog_write(struct iio_dev *indio_dev, unsigned int addr,
+                             unsigned int val)
+{
+       struct ads8688_state *st = iio_priv(indio_dev);
+       u32 tmp;
+
+       tmp = ADS8688_PROG_REG(addr) | ADS8688_PROG_WR_BIT | val;
+       tmp <<= ADS8688_PROG_DONT_CARE_BITS;
+       st->data[0].d32 = cpu_to_be32(tmp);
+
+       return spi_write(st->spi, &st->data[0].d8[1], 3);
+}
+
+static int ads8688_reset(struct iio_dev *indio_dev)
+{
+       struct ads8688_state *st = iio_priv(indio_dev);
+       u32 tmp;
+
+       tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_RST);
+       tmp <<= ADS8688_CMD_DONT_CARE_BITS;
+       st->data[0].d32 = cpu_to_be32(tmp);
+
+       return spi_write(st->spi, &st->data[0].d8[0], 4);
+}
+
+static int ads8688_read(struct iio_dev *indio_dev, unsigned int chan)
+{
+       struct ads8688_state *st = iio_priv(indio_dev);
+       int ret;
+       u32 tmp;
+       struct spi_transfer t[] = {
+               {
+                       .tx_buf = &st->data[0].d8[0],
+                       .len = 4,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = &st->data[1].d8[0],
+                       .rx_buf = &st->data[1].d8[0],
+                       .len = 4,
+               },
+       };
+
+       tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_MAN_CH(chan));
+       tmp <<= ADS8688_CMD_DONT_CARE_BITS;
+       st->data[0].d32 = cpu_to_be32(tmp);
+
+       tmp = ADS8688_CMD_REG(ADS8688_CMD_REG_NOOP);
+       tmp <<= ADS8688_CMD_DONT_CARE_BITS;
+       st->data[1].d32 = cpu_to_be32(tmp);
+
+       ret = spi_sync_transfer(st->spi, t, ARRAY_SIZE(t));
+       if (ret < 0)
+               return ret;
+
+       return be32_to_cpu(st->data[1].d32) & 0xffff;
+}
+
+static int ads8688_read_raw(struct iio_dev *indio_dev,
+                           struct iio_chan_spec const *chan,
+                           int *val, int *val2, long m)
+{
+       int ret, offset;
+       unsigned long scale_mv;
+
+       struct ads8688_state *st = iio_priv(indio_dev);
+
+       mutex_lock(&st->lock);
+       switch (m) {
+       case IIO_CHAN_INFO_RAW:
+               ret = ads8688_read(indio_dev, chan->channel);
+               mutex_unlock(&st->lock);
+               if (ret < 0)
+                       return ret;
+               *val = ret;
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SCALE:
+               scale_mv = st->vref_mv;
+               scale_mv *= ads8688_range_def[st->range[chan->channel]].scale;
+               *val = 0;
+               *val2 = scale_mv;
+               mutex_unlock(&st->lock);
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_OFFSET:
+               offset = ads8688_range_def[st->range[chan->channel]].offset;
+               *val = offset;
+               mutex_unlock(&st->lock);
+               return IIO_VAL_INT;
+       }
+       mutex_unlock(&st->lock);
+
+       return -EINVAL;
+}
+
+static int ads8688_write_reg_range(struct iio_dev *indio_dev,
+                                  struct iio_chan_spec const *chan,
+                                  enum ads8688_range range)
+{
+       unsigned int tmp;
+       int ret;
+
+       tmp = ADS8688_PROG_REG_RANGE_CH(chan->channel);
+       ret = ads8688_prog_write(indio_dev, tmp, range);
+
+       return ret;
+}
+
+static int ads8688_write_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int val, int val2, long mask)
+{
+       struct ads8688_state *st = iio_priv(indio_dev);
+       unsigned int scale = 0;
+       int ret = -EINVAL, i, offset = 0;
+
+       mutex_lock(&st->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               /* If the offset is 0 the Â±2.5 * VREF mode is not available */
+               offset = ads8688_range_def[st->range[chan->channel]].offset;
+               if (offset == 0 && val2 == ads8688_range_def[0].scale * st->vref_mv) {
+                       mutex_unlock(&st->lock);
+                       return -EINVAL;
+               }
+
+               /* Lookup new mode */
+               for (i = 0; i < ARRAY_SIZE(ads8688_range_def); i++)
+                       if (val2 == ads8688_range_def[i].scale * st->vref_mv &&
+                           offset == ads8688_range_def[i].offset) {
+                               ret = ads8688_write_reg_range(indio_dev, chan,
+                                       ads8688_range_def[i].reg);
+                               break;
+                       }
+               break;
+       case IIO_CHAN_INFO_OFFSET:
+               /*
+                * There are only two available offsets:
+                * 0 and -(1 << (ADS8688_REALBITS - 1))
+                */
+               if (!(ads8688_range_def[0].offset == val ||
+                   ads8688_range_def[3].offset == val)) {
+                       mutex_unlock(&st->lock);
+                       return -EINVAL;
+               }
+
+               /*
+                * If the device are in Â±2.5 * VREF mode, it's not allowed to
+                * switch to a mode where the offset is 0
+                */
+               if (val == 0 &&
+                   st->range[chan->channel] == ADS8688_PLUSMINUS25VREF) {
+                       mutex_unlock(&st->lock);
+                       return -EINVAL;
+               }
+
+               scale = ads8688_range_def[st->range[chan->channel]].scale;
+
+               /* Lookup new mode */
+               for (i = 0; i < ARRAY_SIZE(ads8688_range_def); i++)
+                       if (val == ads8688_range_def[i].offset &&
+                           scale == ads8688_range_def[i].scale) {
+                               ret = ads8688_write_reg_range(indio_dev, chan,
+                                       ads8688_range_def[i].reg);
+                               break;
+                       }
+               break;
+       }
+
+       if (!ret)
+               st->range[chan->channel] = ads8688_range_def[i].range;
+
+       mutex_unlock(&st->lock);
+
+       return ret;
+}
+
+static int ads8688_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                    struct iio_chan_spec const *chan,
+                                    long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_OFFSET:
+               return IIO_VAL_INT;
+       }
+
+       return -EINVAL;
+}
+
+static const struct iio_info ads8688_info = {
+       .read_raw = &ads8688_read_raw,
+       .write_raw = &ads8688_write_raw,
+       .write_raw_get_fmt = &ads8688_write_raw_get_fmt,
+       .attrs = &ads8688_attribute_group,
+       .driver_module = THIS_MODULE,
+};
+
+static const struct ads8688_chip_info ads8688_chip_info_tbl[] = {
+       [ID_ADS8684] = {
+               .channels = ads8684_channels,
+               .num_channels = ARRAY_SIZE(ads8684_channels),
+       },
+       [ID_ADS8688] = {
+               .channels = ads8688_channels,
+               .num_channels = ARRAY_SIZE(ads8688_channels),
+       },
+};
+
+static int ads8688_probe(struct spi_device *spi)
+{
+       struct ads8688_state *st;
+       struct iio_dev *indio_dev;
+       int ret;
+
+       indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+       if (indio_dev == NULL)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+
+       st->reg = devm_regulator_get_optional(&spi->dev, "vref");
+       if (!IS_ERR(st->reg)) {
+               ret = regulator_enable(st->reg);
+               if (ret)
+                       return ret;
+
+               ret = regulator_get_voltage(st->reg);
+               if (ret < 0)
+                       goto error_out;
+
+               st->vref_mv = ret / 1000;
+       } else {
+               /* Use internal reference */
+               st->vref_mv = ADS8688_VREF_MV;
+       }
+
+       st->chip_info = &ads8688_chip_info_tbl[spi_get_device_id(spi)->driver_data];
+
+       spi->mode = SPI_MODE_1;
+
+       spi_set_drvdata(spi, indio_dev);
+
+       st->spi = spi;
+
+       indio_dev->name = spi_get_device_id(spi)->name;
+       indio_dev->dev.parent = &spi->dev;
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->channels = st->chip_info->channels;
+       indio_dev->num_channels = st->chip_info->num_channels;
+       indio_dev->info = &ads8688_info;
+
+       ads8688_reset(indio_dev);
+
+       mutex_init(&st->lock);
+
+       ret = iio_device_register(indio_dev);
+       if (ret)
+               goto error_out;
+
+       return 0;
+
+error_out:
+       if (!IS_ERR_OR_NULL(st->reg))
+               regulator_disable(st->reg);
+
+       return ret;
+}
+
+static int ads8688_remove(struct spi_device *spi)
+{
+       struct iio_dev *indio_dev = spi_get_drvdata(spi);
+       struct ads8688_state *st = iio_priv(indio_dev);
+
+       iio_device_unregister(indio_dev);
+
+       if (!IS_ERR_OR_NULL(st->reg))
+               regulator_disable(st->reg);
+
+       return 0;
+}
+
+static const struct spi_device_id ads8688_id[] = {
+       {"ads8684", ID_ADS8684},
+       {"ads8688", ID_ADS8688},
+       {}
+};
+MODULE_DEVICE_TABLE(spi, ads8688_id);
+
+static const struct of_device_id ads8688_of_match[] = {
+       { .compatible = "ti,ads8684" },
+       { .compatible = "ti,ads8688" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ads8688_of_match);
+
+static struct spi_driver ads8688_driver = {
+       .driver = {
+               .name   = "ads8688",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ads8688_probe,
+       .remove         = ads8688_remove,
+       .id_table       = ads8688_id,
+};
+module_spi_driver(ads8688_driver);
+
+MODULE_AUTHOR("Sean Nyekjaer <sean.nyekjaer@prevas.dk>");
+MODULE_DESCRIPTION("Texas Instruments ADS8688 driver");
+MODULE_LICENSE("GPL v2");
index 02e636a1c49a7a17bbb2cd19356301c41781710f..0a6beb3d99cbc741697203181070be72cd8cba17 100644 (file)
@@ -803,7 +803,7 @@ err:
        return ret;
 }
 
-static struct iio_buffer_setup_ops xadc_buffer_ops = {
+static const struct iio_buffer_setup_ops xadc_buffer_ops = {
        .preenable = &xadc_preenable,
        .postenable = &iio_triggered_buffer_postenable,
        .predisable = &iio_triggered_buffer_predisable,
index 0a7b2fd3699bf6f7ed7877974bf77d305f16f80f..4ffd3db7817f8d5492fec31f12b7df2c62bdc887 100644 (file)
@@ -9,6 +9,26 @@ config IIO_BUFFER_CB
          Should be selected by any drivers that do in-kernel push
          usage.  That is, those where the data is pushed to the consumer.
 
+config IIO_BUFFER_DMA
+       tristate
+       help
+         Provides the generic IIO DMA buffer infrastructure that can be used by
+         drivers for devices with DMA support to implement the IIO buffer.
+
+         Should be selected by drivers that want to use the generic DMA buffer
+         infrastructure.
+
+config IIO_BUFFER_DMAENGINE
+       tristate
+       select IIO_BUFFER_DMA
+       help
+         Provides a bonding of the generic IIO DMA buffer infrastructure with the
+         DMAengine framework. This can be used by converter drivers with a DMA port
+         connected to an external DMA controller which is supported by the
+         DMAengine framework.
+
+         Should be selected by drivers that want to use this functionality.
+
 config IIO_KFIFO_BUF
        tristate "Industrial I/O buffering based on kfifo"
        help
index 4d193b9a9123e212a2d0569bee722677d1322829..85beaae831aee154045601f507e9d053f731ae42 100644 (file)
@@ -4,5 +4,7 @@
 
 # When adding new entries keep the list in alphabetical order
 obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
+obj-$(CONFIG_IIO_BUFFER_DMA) += industrialio-buffer-dma.o
+obj-$(CONFIG_IIO_BUFFER_DMAENGINE) += industrialio-buffer-dmaengine.o
 obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
 obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c
new file mode 100644 (file)
index 0000000..212cbed
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * Copyright 2013-2015 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dma.h>
+#include <linux/dma-mapping.h>
+#include <linux/sizes.h>
+
+/*
+ * For DMA buffers the storage is sub-divided into so called blocks. Each block
+ * has its own memory buffer. The size of the block is the granularity at which
+ * memory is exchanged between the hardware and the application. Increasing the
+ * basic unit of data exchange from one sample to one block decreases the
+ * management overhead that is associated with each sample. E.g. if we say the
+ * management overhead for one exchange is x and the unit of exchange is one
+ * sample the overhead will be x for each sample. Whereas when using a block
+ * which contains n samples the overhead per sample is reduced to x/n. This
+ * allows to achieve much higher samplerates than what can be sustained with
+ * the one sample approach.
+ *
+ * Blocks are exchanged between the DMA controller and the application via the
+ * means of two queues. The incoming queue and the outgoing queue. Blocks on the
+ * incoming queue are waiting for the DMA controller to pick them up and fill
+ * them with data. Block on the outgoing queue have been filled with data and
+ * are waiting for the application to dequeue them and read the data.
+ *
+ * A block can be in one of the following states:
+ *  * Owned by the application. In this state the application can read data from
+ *    the block.
+ *  * On the incoming list: Blocks on the incoming list are queued up to be
+ *    processed by the DMA controller.
+ *  * Owned by the DMA controller: The DMA controller is processing the block
+ *    and filling it with data.
+ *  * On the outgoing list: Blocks on the outgoing list have been successfully
+ *    processed by the DMA controller and contain data. They can be dequeued by
+ *    the application.
+ *  * Dead: A block that is dead has been marked as to be freed. It might still
+ *    be owned by either the application or the DMA controller at the moment.
+ *    But once they are done processing it instead of going to either the
+ *    incoming or outgoing queue the block will be freed.
+ *
+ * In addition to this blocks are reference counted and the memory associated
+ * with both the block structure as well as the storage memory for the block
+ * will be freed when the last reference to the block is dropped. This means a
+ * block must not be accessed without holding a reference.
+ *
+ * The iio_dma_buffer implementation provides a generic infrastructure for
+ * managing the blocks.
+ *
+ * A driver for a specific piece of hardware that has DMA capabilities need to
+ * implement the submit() callback from the iio_dma_buffer_ops structure. This
+ * callback is supposed to initiate the DMA transfer copying data from the
+ * converter to the memory region of the block. Once the DMA transfer has been
+ * completed the driver must call iio_dma_buffer_block_done() for the completed
+ * block.
+ *
+ * Prior to this it must set the bytes_used field of the block contains
+ * the actual number of bytes in the buffer. Typically this will be equal to the
+ * size of the block, but if the DMA hardware has certain alignment requirements
+ * for the transfer length it might choose to use less than the full size. In
+ * either case it is expected that bytes_used is a multiple of the bytes per
+ * datum, i.e. the block must not contain partial samples.
+ *
+ * The driver must call iio_dma_buffer_block_done() for each block it has
+ * received through its submit_block() callback, even if it does not actually
+ * perform a DMA transfer for the block, e.g. because the buffer was disabled
+ * before the block transfer was started. In this case it should set bytes_used
+ * to 0.
+ *
+ * In addition it is recommended that a driver implements the abort() callback.
+ * It will be called when the buffer is disabled and can be used to cancel
+ * pending and stop active transfers.
+ *
+ * The specific driver implementation should use the default callback
+ * implementations provided by this module for the iio_buffer_access_funcs
+ * struct. It may overload some callbacks with custom variants if the hardware
+ * has special requirements that are not handled by the generic functions. If a
+ * driver chooses to overload a callback it has to ensure that the generic
+ * callback is called from within the custom callback.
+ */
+
+static void iio_buffer_block_release(struct kref *kref)
+{
+       struct iio_dma_buffer_block *block = container_of(kref,
+               struct iio_dma_buffer_block, kref);
+
+       WARN_ON(block->state != IIO_BLOCK_STATE_DEAD);
+
+       dma_free_coherent(block->queue->dev, PAGE_ALIGN(block->size),
+                                       block->vaddr, block->phys_addr);
+
+       iio_buffer_put(&block->queue->buffer);
+       kfree(block);
+}
+
+static void iio_buffer_block_get(struct iio_dma_buffer_block *block)
+{
+       kref_get(&block->kref);
+}
+
+static void iio_buffer_block_put(struct iio_dma_buffer_block *block)
+{
+       kref_put(&block->kref, iio_buffer_block_release);
+}
+
+/*
+ * dma_free_coherent can sleep, hence we need to take some special care to be
+ * able to drop a reference from an atomic context.
+ */
+static LIST_HEAD(iio_dma_buffer_dead_blocks);
+static DEFINE_SPINLOCK(iio_dma_buffer_dead_blocks_lock);
+
+static void iio_dma_buffer_cleanup_worker(struct work_struct *work)
+{
+       struct iio_dma_buffer_block *block, *_block;
+       LIST_HEAD(block_list);
+
+       spin_lock_irq(&iio_dma_buffer_dead_blocks_lock);
+       list_splice_tail_init(&iio_dma_buffer_dead_blocks, &block_list);
+       spin_unlock_irq(&iio_dma_buffer_dead_blocks_lock);
+
+       list_for_each_entry_safe(block, _block, &block_list, head)
+               iio_buffer_block_release(&block->kref);
+}
+static DECLARE_WORK(iio_dma_buffer_cleanup_work, iio_dma_buffer_cleanup_worker);
+
+static void iio_buffer_block_release_atomic(struct kref *kref)
+{
+       struct iio_dma_buffer_block *block;
+       unsigned long flags;
+
+       block = container_of(kref, struct iio_dma_buffer_block, kref);
+
+       spin_lock_irqsave(&iio_dma_buffer_dead_blocks_lock, flags);
+       list_add_tail(&block->head, &iio_dma_buffer_dead_blocks);
+       spin_unlock_irqrestore(&iio_dma_buffer_dead_blocks_lock, flags);
+
+       schedule_work(&iio_dma_buffer_cleanup_work);
+}
+
+/*
+ * Version of iio_buffer_block_put() that can be called from atomic context
+ */
+static void iio_buffer_block_put_atomic(struct iio_dma_buffer_block *block)
+{
+       kref_put(&block->kref, iio_buffer_block_release_atomic);
+}
+
+static struct iio_dma_buffer_queue *iio_buffer_to_queue(struct iio_buffer *buf)
+{
+       return container_of(buf, struct iio_dma_buffer_queue, buffer);
+}
+
+static struct iio_dma_buffer_block *iio_dma_buffer_alloc_block(
+       struct iio_dma_buffer_queue *queue, size_t size)
+{
+       struct iio_dma_buffer_block *block;
+
+       block = kzalloc(sizeof(*block), GFP_KERNEL);
+       if (!block)
+               return NULL;
+
+       block->vaddr = dma_alloc_coherent(queue->dev, PAGE_ALIGN(size),
+               &block->phys_addr, GFP_KERNEL);
+       if (!block->vaddr) {
+               kfree(block);
+               return NULL;
+       }
+
+       block->size = size;
+       block->state = IIO_BLOCK_STATE_DEQUEUED;
+       block->queue = queue;
+       INIT_LIST_HEAD(&block->head);
+       kref_init(&block->kref);
+
+       iio_buffer_get(&queue->buffer);
+
+       return block;
+}
+
+static void _iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
+{
+       struct iio_dma_buffer_queue *queue = block->queue;
+
+       /*
+        * The buffer has already been freed by the application, just drop the
+        * reference.
+        */
+       if (block->state != IIO_BLOCK_STATE_DEAD) {
+               block->state = IIO_BLOCK_STATE_DONE;
+               list_add_tail(&block->head, &queue->outgoing);
+       }
+}
+
+/**
+ * iio_dma_buffer_block_done() - Indicate that a block has been completed
+ * @block: The completed block
+ *
+ * Should be called when the DMA controller has finished handling the block to
+ * pass back ownership of the block to the queue.
+ */
+void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block)
+{
+       struct iio_dma_buffer_queue *queue = block->queue;
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->list_lock, flags);
+       _iio_dma_buffer_block_done(block);
+       spin_unlock_irqrestore(&queue->list_lock, flags);
+
+       iio_buffer_block_put_atomic(block);
+       wake_up_interruptible_poll(&queue->buffer.pollq, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_block_done);
+
+/**
+ * iio_dma_buffer_block_list_abort() - Indicate that a list block has been
+ *   aborted
+ * @queue: Queue for which to complete blocks.
+ * @list: List of aborted blocks. All blocks in this list must be from @queue.
+ *
+ * Typically called from the abort() callback after the DMA controller has been
+ * stopped. This will set bytes_used to 0 for each block in the list and then
+ * hand the blocks back to the queue.
+ */
+void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue,
+       struct list_head *list)
+{
+       struct iio_dma_buffer_block *block, *_block;
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->list_lock, flags);
+       list_for_each_entry_safe(block, _block, list, head) {
+               list_del(&block->head);
+               block->bytes_used = 0;
+               _iio_dma_buffer_block_done(block);
+               iio_buffer_block_put_atomic(block);
+       }
+       spin_unlock_irqrestore(&queue->list_lock, flags);
+
+       wake_up_interruptible_poll(&queue->buffer.pollq, POLLIN | POLLRDNORM);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_block_list_abort);
+
+static bool iio_dma_block_reusable(struct iio_dma_buffer_block *block)
+{
+       /*
+        * If the core owns the block it can be re-used. This should be the
+        * default case when enabling the buffer, unless the DMA controller does
+        * not support abort and has not given back the block yet.
+        */
+       switch (block->state) {
+       case IIO_BLOCK_STATE_DEQUEUED:
+       case IIO_BLOCK_STATE_QUEUED:
+       case IIO_BLOCK_STATE_DONE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+/**
+ * iio_dma_buffer_request_update() - DMA buffer request_update callback
+ * @buffer: The buffer which to request an update
+ *
+ * Should be used as the iio_dma_buffer_request_update() callback for
+ * iio_buffer_access_ops struct for DMA buffers.
+ */
+int iio_dma_buffer_request_update(struct iio_buffer *buffer)
+{
+       struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+       struct iio_dma_buffer_block *block;
+       bool try_reuse = false;
+       size_t size;
+       int ret = 0;
+       int i;
+
+       /*
+        * Split the buffer into two even parts. This is used as a double
+        * buffering scheme with usually one block at a time being used by the
+        * DMA and the other one by the application.
+        */
+       size = DIV_ROUND_UP(queue->buffer.bytes_per_datum *
+               queue->buffer.length, 2);
+
+       mutex_lock(&queue->lock);
+
+       /* Allocations are page aligned */
+       if (PAGE_ALIGN(queue->fileio.block_size) == PAGE_ALIGN(size))
+               try_reuse = true;
+
+       queue->fileio.block_size = size;
+       queue->fileio.active_block = NULL;
+
+       spin_lock_irq(&queue->list_lock);
+       for (i = 0; i < 2; i++) {
+               block = queue->fileio.blocks[i];
+
+               /* If we can't re-use it free it */
+               if (block && (!iio_dma_block_reusable(block) || !try_reuse))
+                       block->state = IIO_BLOCK_STATE_DEAD;
+       }
+
+       /*
+        * At this point all blocks are either owned by the core or marked as
+        * dead. This means we can reset the lists without having to fear
+        * corrution.
+        */
+       INIT_LIST_HEAD(&queue->outgoing);
+       spin_unlock_irq(&queue->list_lock);
+
+       INIT_LIST_HEAD(&queue->incoming);
+
+       for (i = 0; i < 2; i++) {
+               if (queue->fileio.blocks[i]) {
+                       block = queue->fileio.blocks[i];
+                       if (block->state == IIO_BLOCK_STATE_DEAD) {
+                               /* Could not reuse it */
+                               iio_buffer_block_put(block);
+                               block = NULL;
+                       } else {
+                               block->size = size;
+                       }
+               } else {
+                       block = NULL;
+               }
+
+               if (!block) {
+                       block = iio_dma_buffer_alloc_block(queue, size);
+                       if (!block) {
+                               ret = -ENOMEM;
+                               goto out_unlock;
+                       }
+                       queue->fileio.blocks[i] = block;
+               }
+
+               block->state = IIO_BLOCK_STATE_QUEUED;
+               list_add_tail(&block->head, &queue->incoming);
+       }
+
+out_unlock:
+       mutex_unlock(&queue->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_request_update);
+
+static void iio_dma_buffer_submit_block(struct iio_dma_buffer_queue *queue,
+       struct iio_dma_buffer_block *block)
+{
+       int ret;
+
+       /*
+        * If the hardware has already been removed we put the block into
+        * limbo. It will neither be on the incoming nor outgoing list, nor will
+        * it ever complete. It will just wait to be freed eventually.
+        */
+       if (!queue->ops)
+               return;
+
+       block->state = IIO_BLOCK_STATE_ACTIVE;
+       iio_buffer_block_get(block);
+       ret = queue->ops->submit(queue, block);
+       if (ret) {
+               /*
+                * This is a bit of a problem and there is not much we can do
+                * other then wait for the buffer to be disabled and re-enabled
+                * and try again. But it should not really happen unless we run
+                * out of memory or something similar.
+                *
+                * TODO: Implement support in the IIO core to allow buffers to
+                * notify consumers that something went wrong and the buffer
+                * should be disabled.
+                */
+               iio_buffer_block_put(block);
+       }
+}
+
+/**
+ * iio_dma_buffer_enable() - Enable DMA buffer
+ * @buffer: IIO buffer to enable
+ * @indio_dev: IIO device the buffer is attached to
+ *
+ * Needs to be called when the device that the buffer is attached to starts
+ * sampling. Typically should be the iio_buffer_access_ops enable callback.
+ *
+ * This will allocate the DMA buffers and start the DMA transfers.
+ */
+int iio_dma_buffer_enable(struct iio_buffer *buffer,
+       struct iio_dev *indio_dev)
+{
+       struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+       struct iio_dma_buffer_block *block, *_block;
+
+       mutex_lock(&queue->lock);
+       queue->active = true;
+       list_for_each_entry_safe(block, _block, &queue->incoming, head) {
+               list_del(&block->head);
+               iio_dma_buffer_submit_block(queue, block);
+       }
+       mutex_unlock(&queue->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_enable);
+
+/**
+ * iio_dma_buffer_disable() - Disable DMA buffer
+ * @buffer: IIO DMA buffer to disable
+ * @indio_dev: IIO device the buffer is attached to
+ *
+ * Needs to be called when the device that the buffer is attached to stops
+ * sampling. Typically should be the iio_buffer_access_ops disable callback.
+ */
+int iio_dma_buffer_disable(struct iio_buffer *buffer,
+       struct iio_dev *indio_dev)
+{
+       struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+
+       mutex_lock(&queue->lock);
+       queue->active = false;
+
+       if (queue->ops && queue->ops->abort)
+               queue->ops->abort(queue);
+       mutex_unlock(&queue->lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_disable);
+
+static void iio_dma_buffer_enqueue(struct iio_dma_buffer_queue *queue,
+       struct iio_dma_buffer_block *block)
+{
+       if (block->state == IIO_BLOCK_STATE_DEAD) {
+               iio_buffer_block_put(block);
+       } else if (queue->active) {
+               iio_dma_buffer_submit_block(queue, block);
+       } else {
+               block->state = IIO_BLOCK_STATE_QUEUED;
+               list_add_tail(&block->head, &queue->incoming);
+       }
+}
+
+static struct iio_dma_buffer_block *iio_dma_buffer_dequeue(
+       struct iio_dma_buffer_queue *queue)
+{
+       struct iio_dma_buffer_block *block;
+
+       spin_lock_irq(&queue->list_lock);
+       block = list_first_entry_or_null(&queue->outgoing, struct
+               iio_dma_buffer_block, head);
+       if (block != NULL) {
+               list_del(&block->head);
+               block->state = IIO_BLOCK_STATE_DEQUEUED;
+       }
+       spin_unlock_irq(&queue->list_lock);
+
+       return block;
+}
+
+/**
+ * iio_dma_buffer_read() - DMA buffer read callback
+ * @buffer: Buffer to read form
+ * @n: Number of bytes to read
+ * @user_buffer: Userspace buffer to copy the data to
+ *
+ * Should be used as the read_first_n callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n,
+       char __user *user_buffer)
+{
+       struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buffer);
+       struct iio_dma_buffer_block *block;
+       int ret;
+
+       if (n < buffer->bytes_per_datum)
+               return -EINVAL;
+
+       mutex_lock(&queue->lock);
+
+       if (!queue->fileio.active_block) {
+               block = iio_dma_buffer_dequeue(queue);
+               if (block == NULL) {
+                       ret = 0;
+                       goto out_unlock;
+               }
+               queue->fileio.pos = 0;
+               queue->fileio.active_block = block;
+       } else {
+               block = queue->fileio.active_block;
+       }
+
+       n = rounddown(n, buffer->bytes_per_datum);
+       if (n > block->bytes_used - queue->fileio.pos)
+               n = block->bytes_used - queue->fileio.pos;
+
+       if (copy_to_user(user_buffer, block->vaddr + queue->fileio.pos, n)) {
+               ret = -EFAULT;
+               goto out_unlock;
+       }
+
+       queue->fileio.pos += n;
+
+       if (queue->fileio.pos == block->bytes_used) {
+               queue->fileio.active_block = NULL;
+               iio_dma_buffer_enqueue(queue, block);
+       }
+
+       ret = n;
+
+out_unlock:
+       mutex_unlock(&queue->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_read);
+
+/**
+ * iio_dma_buffer_data_available() - DMA buffer data_available callback
+ * @buf: Buffer to check for data availability
+ *
+ * Should be used as the data_available callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+size_t iio_dma_buffer_data_available(struct iio_buffer *buf)
+{
+       struct iio_dma_buffer_queue *queue = iio_buffer_to_queue(buf);
+       struct iio_dma_buffer_block *block;
+       size_t data_available = 0;
+
+       /*
+        * For counting the available bytes we'll use the size of the block not
+        * the number of actual bytes available in the block. Otherwise it is
+        * possible that we end up with a value that is lower than the watermark
+        * but won't increase since all blocks are in use.
+        */
+
+       mutex_lock(&queue->lock);
+       if (queue->fileio.active_block)
+               data_available += queue->fileio.active_block->size;
+
+       spin_lock_irq(&queue->list_lock);
+       list_for_each_entry(block, &queue->outgoing, head)
+               data_available += block->size;
+       spin_unlock_irq(&queue->list_lock);
+       mutex_unlock(&queue->lock);
+
+       return data_available;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_data_available);
+
+/**
+ * iio_dma_buffer_set_bytes_per_datum() - DMA buffer set_bytes_per_datum callback
+ * @buffer: Buffer to set the bytes-per-datum for
+ * @bpd: The new bytes-per-datum value
+ *
+ * Should be used as the set_bytes_per_datum callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd)
+{
+       buffer->bytes_per_datum = bpd;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_set_bytes_per_datum);
+
+/**
+ * iio_dma_buffer_set_length - DMA buffer set_length callback
+ * @buffer: Buffer to set the length for
+ * @length: The new buffer length
+ *
+ * Should be used as the set_length callback for iio_buffer_access_ops
+ * struct for DMA buffers.
+ */
+int iio_dma_buffer_set_length(struct iio_buffer *buffer, int length)
+{
+       /* Avoid an invalid state */
+       if (length < 2)
+               length = 2;
+       buffer->length = length;
+       buffer->watermark = length / 2;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_set_length);
+
+/**
+ * iio_dma_buffer_init() - Initialize DMA buffer queue
+ * @queue: Buffer to initialize
+ * @dev: DMA device
+ * @ops: DMA buffer queue callback operations
+ *
+ * The DMA device will be used by the queue to do DMA memory allocations. So it
+ * should refer to the device that will perform the DMA to ensure that
+ * allocations are done from a memory region that can be accessed by the device.
+ */
+int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue,
+       struct device *dev, const struct iio_dma_buffer_ops *ops)
+{
+       iio_buffer_init(&queue->buffer);
+       queue->buffer.length = PAGE_SIZE;
+       queue->buffer.watermark = queue->buffer.length / 2;
+       queue->dev = dev;
+       queue->ops = ops;
+
+       INIT_LIST_HEAD(&queue->incoming);
+       INIT_LIST_HEAD(&queue->outgoing);
+
+       mutex_init(&queue->lock);
+       spin_lock_init(&queue->list_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_init);
+
+/**
+ * iio_dma_buffer_exit() - Cleanup DMA buffer queue
+ * @queue: Buffer to cleanup
+ *
+ * After this function has completed it is safe to free any resources that are
+ * associated with the buffer and are accessed inside the callback operations.
+ */
+void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue)
+{
+       unsigned int i;
+
+       mutex_lock(&queue->lock);
+
+       spin_lock_irq(&queue->list_lock);
+       for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+               if (!queue->fileio.blocks[i])
+                       continue;
+               queue->fileio.blocks[i]->state = IIO_BLOCK_STATE_DEAD;
+       }
+       INIT_LIST_HEAD(&queue->outgoing);
+       spin_unlock_irq(&queue->list_lock);
+
+       INIT_LIST_HEAD(&queue->incoming);
+
+       for (i = 0; i < ARRAY_SIZE(queue->fileio.blocks); i++) {
+               if (!queue->fileio.blocks[i])
+                       continue;
+               iio_buffer_block_put(queue->fileio.blocks[i]);
+               queue->fileio.blocks[i] = NULL;
+       }
+       queue->fileio.active_block = NULL;
+       queue->ops = NULL;
+
+       mutex_unlock(&queue->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_exit);
+
+/**
+ * iio_dma_buffer_release() - Release final buffer resources
+ * @queue: Buffer to release
+ *
+ * Frees resources that can't yet be freed in iio_dma_buffer_exit(). Should be
+ * called in the buffers release callback implementation right before freeing
+ * the memory associated with the buffer.
+ */
+void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue)
+{
+       mutex_destroy(&queue->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dma_buffer_release);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("DMA buffer for the IIO framework");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c
new file mode 100644 (file)
index 0000000..ebdb838
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2014-2015 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/buffer-dma.h>
+#include <linux/iio/buffer-dmaengine.h>
+
+/*
+ * The IIO DMAengine buffer combines the generic IIO DMA buffer infrastructure
+ * with the DMAengine framework. The generic IIO DMA buffer infrastructure is
+ * used to manage the buffer memory and implement the IIO buffer operations
+ * while the DMAengine framework is used to perform the DMA transfers. Combined
+ * this results in a device independent fully functional DMA buffer
+ * implementation that can be used by device drivers for peripherals which are
+ * connected to a DMA controller which has a DMAengine driver implementation.
+ */
+
+struct dmaengine_buffer {
+       struct iio_dma_buffer_queue queue;
+
+       struct dma_chan *chan;
+       struct list_head active;
+
+       size_t align;
+       size_t max_size;
+};
+
+static struct dmaengine_buffer *iio_buffer_to_dmaengine_buffer(
+               struct iio_buffer *buffer)
+{
+       return container_of(buffer, struct dmaengine_buffer, queue.buffer);
+}
+
+static void iio_dmaengine_buffer_block_done(void *data)
+{
+       struct iio_dma_buffer_block *block = data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&block->queue->list_lock, flags);
+       list_del(&block->head);
+       spin_unlock_irqrestore(&block->queue->list_lock, flags);
+       iio_dma_buffer_block_done(block);
+}
+
+static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue,
+       struct iio_dma_buffer_block *block)
+{
+       struct dmaengine_buffer *dmaengine_buffer =
+               iio_buffer_to_dmaengine_buffer(&queue->buffer);
+       struct dma_async_tx_descriptor *desc;
+       dma_cookie_t cookie;
+
+       block->bytes_used = min(block->size, dmaengine_buffer->max_size);
+       block->bytes_used = rounddown(block->bytes_used,
+                       dmaengine_buffer->align);
+
+       desc = dmaengine_prep_slave_single(dmaengine_buffer->chan,
+               block->phys_addr, block->bytes_used, DMA_DEV_TO_MEM,
+               DMA_PREP_INTERRUPT);
+       if (!desc)
+               return -ENOMEM;
+
+       desc->callback = iio_dmaengine_buffer_block_done;
+       desc->callback_param = block;
+
+       cookie = dmaengine_submit(desc);
+       if (dma_submit_error(cookie))
+               return dma_submit_error(cookie);
+
+       spin_lock_irq(&dmaengine_buffer->queue.list_lock);
+       list_add_tail(&block->head, &dmaengine_buffer->active);
+       spin_unlock_irq(&dmaengine_buffer->queue.list_lock);
+
+       dma_async_issue_pending(dmaengine_buffer->chan);
+
+       return 0;
+}
+
+static void iio_dmaengine_buffer_abort(struct iio_dma_buffer_queue *queue)
+{
+       struct dmaengine_buffer *dmaengine_buffer =
+               iio_buffer_to_dmaengine_buffer(&queue->buffer);
+
+       dmaengine_terminate_all(dmaengine_buffer->chan);
+       /* FIXME: There is a slight chance of a race condition here.
+        * dmaengine_terminate_all() does not guarantee that all transfer
+        * callbacks have finished running. Need to introduce a
+        * dmaengine_terminate_all_sync().
+        */
+       iio_dma_buffer_block_list_abort(queue, &dmaengine_buffer->active);
+}
+
+static void iio_dmaengine_buffer_release(struct iio_buffer *buf)
+{
+       struct dmaengine_buffer *dmaengine_buffer =
+               iio_buffer_to_dmaengine_buffer(buf);
+
+       iio_dma_buffer_release(&dmaengine_buffer->queue);
+       kfree(dmaengine_buffer);
+}
+
+static const struct iio_buffer_access_funcs iio_dmaengine_buffer_ops = {
+       .read_first_n = iio_dma_buffer_read,
+       .set_bytes_per_datum = iio_dma_buffer_set_bytes_per_datum,
+       .set_length = iio_dma_buffer_set_length,
+       .request_update = iio_dma_buffer_request_update,
+       .enable = iio_dma_buffer_enable,
+       .disable = iio_dma_buffer_disable,
+       .data_available = iio_dma_buffer_data_available,
+       .release = iio_dmaengine_buffer_release,
+
+       .modes = INDIO_BUFFER_HARDWARE,
+       .flags = INDIO_BUFFER_FLAG_FIXED_WATERMARK,
+};
+
+static const struct iio_dma_buffer_ops iio_dmaengine_default_ops = {
+       .submit = iio_dmaengine_buffer_submit_block,
+       .abort = iio_dmaengine_buffer_abort,
+};
+
+/**
+ * iio_dmaengine_buffer_alloc() - Allocate new buffer which uses DMAengine
+ * @dev: Parent device for the buffer
+ * @channel: DMA channel name, typically "rx".
+ *
+ * This allocates a new IIO buffer which internally uses the DMAengine framework
+ * to perform its transfers. The parent device will be used to request the DMA
+ * channel.
+ *
+ * Once done using the buffer iio_dmaengine_buffer_free() should be used to
+ * release it.
+ */
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+       const char *channel)
+{
+       struct dmaengine_buffer *dmaengine_buffer;
+       unsigned int width, src_width, dest_width;
+       struct dma_slave_caps caps;
+       struct dma_chan *chan;
+       int ret;
+
+       dmaengine_buffer = kzalloc(sizeof(*dmaengine_buffer), GFP_KERNEL);
+       if (!dmaengine_buffer)
+               return ERR_PTR(-ENOMEM);
+
+       chan = dma_request_slave_channel_reason(dev, channel);
+       if (IS_ERR(chan)) {
+               ret = PTR_ERR(chan);
+               goto err_free;
+       }
+
+       ret = dma_get_slave_caps(chan, &caps);
+       if (ret < 0)
+               goto err_free;
+
+       /* Needs to be aligned to the maximum of the minimums */
+       if (caps.src_addr_widths)
+               src_width = __ffs(caps.src_addr_widths);
+       else
+               src_width = 1;
+       if (caps.dst_addr_widths)
+               dest_width = __ffs(caps.dst_addr_widths);
+       else
+               dest_width = 1;
+       width = max(src_width, dest_width);
+
+       INIT_LIST_HEAD(&dmaengine_buffer->active);
+       dmaengine_buffer->chan = chan;
+       dmaengine_buffer->align = width;
+       dmaengine_buffer->max_size = dma_get_max_seg_size(chan->device->dev);
+
+       iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev,
+               &iio_dmaengine_default_ops);
+
+       dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops;
+
+       return &dmaengine_buffer->queue.buffer;
+
+err_free:
+       kfree(dmaengine_buffer);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(iio_dmaengine_buffer_alloc);
+
+/**
+ * iio_dmaengine_buffer_free() - Free dmaengine buffer
+ * @buffer: Buffer to free
+ *
+ * Frees a buffer previously allocated with iio_dmaengine_buffer_alloc().
+ */
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer)
+{
+       struct dmaengine_buffer *dmaengine_buffer =
+               iio_buffer_to_dmaengine_buffer(buffer);
+
+       iio_dma_buffer_exit(&dmaengine_buffer->queue);
+       dma_release_channel(dmaengine_buffer->chan);
+
+       iio_buffer_put(buffer);
+}
+EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free);
diff --git a/drivers/iio/dummy/Kconfig b/drivers/iio/dummy/Kconfig
new file mode 100644 (file)
index 0000000..e8676aa
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# Industrial I/O subsystem Dummy Driver configuration
+#
+menu "IIO dummy driver"
+       depends on IIO
+
+config IIO_DUMMY_EVGEN
+       tristate
+
+config IIO_SIMPLE_DUMMY
+       tristate "An example driver with no hardware requirements"
+       help
+        Driver intended mainly as documentation for how to write
+        a driver. May also be useful for testing userspace code
+        without hardware.
+
+if IIO_SIMPLE_DUMMY
+
+config IIO_SIMPLE_DUMMY_EVENTS
+       bool "Event generation support"
+       select IIO_DUMMY_EVGEN
+       help
+         Add some dummy events to the simple dummy driver.
+
+config IIO_SIMPLE_DUMMY_BUFFER
+       bool "Buffered capture support"
+       select IIO_BUFFER
+       select IIO_TRIGGER
+       select IIO_KFIFO_BUF
+       help
+         Add buffered data capture to the simple dummy driver.
+
+endif # IIO_SIMPLE_DUMMY
+
+endmenu
diff --git a/drivers/iio/dummy/Makefile b/drivers/iio/dummy/Makefile
new file mode 100644 (file)
index 0000000..0765e93
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for the IIO Dummy Driver
+#
+
+obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
+iio_dummy-y := iio_simple_dummy.o
+iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o
+iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
+
+obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
diff --git a/drivers/iio/dummy/iio_dummy_evgen.c b/drivers/iio/dummy/iio_dummy_evgen.c
new file mode 100644 (file)
index 0000000..9e83f34
--- /dev/null
@@ -0,0 +1,262 @@
+/**
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Companion module to the iio simple dummy example driver.
+ * The purpose of this is to generate 'fake' event interrupts thus
+ * allowing that driver's code to be as close as possible to that of
+ * a normal driver talking to hardware.  The approach used here
+ * is not intended to be general and just happens to work for this
+ * particular use case.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/sysfs.h>
+
+#include "iio_dummy_evgen.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/irq_work.h>
+
+/* Fiddly bit of faking and irq without hardware */
+#define IIO_EVENTGEN_NO 10
+
+/**
+ * struct iio_dummy_handle_irq - helper struct to simulate interrupt generation
+ * @work: irq_work used to run handlers from hardirq context
+ * @irq: fake irq line number to trigger an interrupt
+ */
+struct iio_dummy_handle_irq {
+       struct irq_work work;
+       int irq;
+};
+
+/**
+ * struct iio_dummy_evgen - evgen state
+ * @chip: irq chip we are faking
+ * @base: base of irq range
+ * @enabled: mask of which irqs are enabled
+ * @inuse: mask of which irqs are connected
+ * @regs: irq regs we are faking
+ * @lock: protect the evgen state
+ * @handler: helper for a 'hardware-like' interrupt simulation
+ */
+struct iio_dummy_eventgen {
+       struct irq_chip chip;
+       int base;
+       bool enabled[IIO_EVENTGEN_NO];
+       bool inuse[IIO_EVENTGEN_NO];
+       struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
+       struct mutex lock;
+       struct iio_dummy_handle_irq handler;
+};
+
+/* We can only ever have one instance of this 'device' */
+static struct iio_dummy_eventgen *iio_evgen;
+static const char *iio_evgen_name = "iio_dummy_evgen";
+
+static void iio_dummy_event_irqmask(struct irq_data *d)
+{
+       struct irq_chip *chip = irq_data_get_irq_chip(d);
+       struct iio_dummy_eventgen *evgen =
+               container_of(chip, struct iio_dummy_eventgen, chip);
+
+       evgen->enabled[d->irq - evgen->base] = false;
+}
+
+static void iio_dummy_event_irqunmask(struct irq_data *d)
+{
+       struct irq_chip *chip = irq_data_get_irq_chip(d);
+       struct iio_dummy_eventgen *evgen =
+               container_of(chip, struct iio_dummy_eventgen, chip);
+
+       evgen->enabled[d->irq - evgen->base] = true;
+}
+
+static void iio_dummy_work_handler(struct irq_work *work)
+{
+       struct iio_dummy_handle_irq *irq_handler;
+
+       irq_handler = container_of(work, struct iio_dummy_handle_irq, work);
+       handle_simple_irq(irq_to_desc(irq_handler->irq));
+}
+
+static int iio_dummy_evgen_create(void)
+{
+       int ret, i;
+
+       iio_evgen = kzalloc(sizeof(*iio_evgen), GFP_KERNEL);
+       if (!iio_evgen)
+               return -ENOMEM;
+
+       iio_evgen->base = irq_alloc_descs(-1, 0, IIO_EVENTGEN_NO, 0);
+       if (iio_evgen->base < 0) {
+               ret = iio_evgen->base;
+               kfree(iio_evgen);
+               return ret;
+       }
+       iio_evgen->chip.name = iio_evgen_name;
+       iio_evgen->chip.irq_mask = &iio_dummy_event_irqmask;
+       iio_evgen->chip.irq_unmask = &iio_dummy_event_irqunmask;
+       for (i = 0; i < IIO_EVENTGEN_NO; i++) {
+               irq_set_chip(iio_evgen->base + i, &iio_evgen->chip);
+               irq_set_handler(iio_evgen->base + i, &handle_simple_irq);
+               irq_modify_status(iio_evgen->base + i,
+                                 IRQ_NOREQUEST | IRQ_NOAUTOEN,
+                                 IRQ_NOPROBE);
+       }
+       init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
+       mutex_init(&iio_evgen->lock);
+       return 0;
+}
+
+/**
+ * iio_dummy_evgen_get_irq() - get an evgen provided irq for a device
+ *
+ * This function will give a free allocated irq to a client device.
+ * That irq can then be caused to 'fire' by using the associated sysfs file.
+ */
+int iio_dummy_evgen_get_irq(void)
+{
+       int i, ret = 0;
+
+       if (!iio_evgen)
+               return -ENODEV;
+
+       mutex_lock(&iio_evgen->lock);
+       for (i = 0; i < IIO_EVENTGEN_NO; i++)
+               if (!iio_evgen->inuse[i]) {
+                       ret = iio_evgen->base + i;
+                       iio_evgen->inuse[i] = true;
+                       break;
+               }
+       mutex_unlock(&iio_evgen->lock);
+       if (i == IIO_EVENTGEN_NO)
+               return -ENOMEM;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
+
+/**
+ * iio_dummy_evgen_release_irq() - give the irq back.
+ * @irq: irq being returned to the pool
+ *
+ * Used by client driver instances to give the irqs back when they disconnect
+ */
+void iio_dummy_evgen_release_irq(int irq)
+{
+       mutex_lock(&iio_evgen->lock);
+       iio_evgen->inuse[irq - iio_evgen->base] = false;
+       mutex_unlock(&iio_evgen->lock);
+}
+EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
+
+struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq)
+{
+       return &iio_evgen->regs[irq - iio_evgen->base];
+}
+EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
+
+static void iio_dummy_evgen_free(void)
+{
+       irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
+       kfree(iio_evgen);
+}
+
+static void iio_evgen_release(struct device *dev)
+{
+       iio_dummy_evgen_free();
+}
+
+static ssize_t iio_evgen_poke(struct device *dev,
+                             struct device_attribute *attr,
+                             const char *buf,
+                             size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       unsigned long event;
+       int ret;
+
+       ret = kstrtoul(buf, 10, &event);
+       if (ret)
+               return ret;
+
+       iio_evgen->regs[this_attr->address].reg_id   = this_attr->address;
+       iio_evgen->regs[this_attr->address].reg_data = event;
+
+       iio_evgen->handler.irq = iio_evgen->base + this_attr->address;
+       if (iio_evgen->enabled[this_attr->address])
+               irq_work_queue(&iio_evgen->handler.work);
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(poke_ev0, S_IWUSR, NULL, &iio_evgen_poke, 0);
+static IIO_DEVICE_ATTR(poke_ev1, S_IWUSR, NULL, &iio_evgen_poke, 1);
+static IIO_DEVICE_ATTR(poke_ev2, S_IWUSR, NULL, &iio_evgen_poke, 2);
+static IIO_DEVICE_ATTR(poke_ev3, S_IWUSR, NULL, &iio_evgen_poke, 3);
+static IIO_DEVICE_ATTR(poke_ev4, S_IWUSR, NULL, &iio_evgen_poke, 4);
+static IIO_DEVICE_ATTR(poke_ev5, S_IWUSR, NULL, &iio_evgen_poke, 5);
+static IIO_DEVICE_ATTR(poke_ev6, S_IWUSR, NULL, &iio_evgen_poke, 6);
+static IIO_DEVICE_ATTR(poke_ev7, S_IWUSR, NULL, &iio_evgen_poke, 7);
+static IIO_DEVICE_ATTR(poke_ev8, S_IWUSR, NULL, &iio_evgen_poke, 8);
+static IIO_DEVICE_ATTR(poke_ev9, S_IWUSR, NULL, &iio_evgen_poke, 9);
+
+static struct attribute *iio_evgen_attrs[] = {
+       &iio_dev_attr_poke_ev0.dev_attr.attr,
+       &iio_dev_attr_poke_ev1.dev_attr.attr,
+       &iio_dev_attr_poke_ev2.dev_attr.attr,
+       &iio_dev_attr_poke_ev3.dev_attr.attr,
+       &iio_dev_attr_poke_ev4.dev_attr.attr,
+       &iio_dev_attr_poke_ev5.dev_attr.attr,
+       &iio_dev_attr_poke_ev6.dev_attr.attr,
+       &iio_dev_attr_poke_ev7.dev_attr.attr,
+       &iio_dev_attr_poke_ev8.dev_attr.attr,
+       &iio_dev_attr_poke_ev9.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group iio_evgen_group = {
+       .attrs = iio_evgen_attrs,
+};
+
+static const struct attribute_group *iio_evgen_groups[] = {
+       &iio_evgen_group,
+       NULL
+};
+
+static struct device iio_evgen_dev = {
+       .bus = &iio_bus_type,
+       .groups = iio_evgen_groups,
+       .release = &iio_evgen_release,
+};
+
+static __init int iio_dummy_evgen_init(void)
+{
+       int ret = iio_dummy_evgen_create();
+
+       if (ret < 0)
+               return ret;
+       device_initialize(&iio_evgen_dev);
+       dev_set_name(&iio_evgen_dev, "iio_evgen");
+       return device_add(&iio_evgen_dev);
+}
+module_init(iio_dummy_evgen_init);
+
+static __exit void iio_dummy_evgen_exit(void)
+{
+       device_unregister(&iio_evgen_dev);
+}
+module_exit(iio_dummy_evgen_exit);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("IIO dummy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dummy/iio_dummy_evgen.h b/drivers/iio/dummy/iio_dummy_evgen.h
new file mode 100644 (file)
index 0000000..d044b94
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _IIO_DUMMY_EVGEN_H_
+#define _IIO_DUMMY_EVGEN_H_
+
+struct iio_dummy_regs {
+       u32 reg_id;
+       u32 reg_data;
+};
+
+struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq);
+int iio_dummy_evgen_get_irq(void);
+void iio_dummy_evgen_release_irq(int irq);
+
+#endif /* _IIO_DUMMY_EVGEN_H_ */
diff --git a/drivers/iio/dummy/iio_simple_dummy.c b/drivers/iio/dummy/iio_simple_dummy.c
new file mode 100644 (file)
index 0000000..43fe4ba
--- /dev/null
@@ -0,0 +1,747 @@
+/**
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ *
+ * A reference industrial I/O driver to illustrate the functionality available.
+ *
+ * There are numerous real drivers to illustrate the finer points.
+ * The purpose of this driver is to provide a driver with far more comments
+ * and explanatory notes than any 'real' driver would have.
+ * Anyone starting out writing an IIO driver should first make sure they
+ * understand all of this driver except those bits specifically marked
+ * as being present to allow us to 'fake' the presence of hardware.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include "iio_simple_dummy.h"
+
+/*
+ * A few elements needed to fake a bus for this driver
+ * Note instances parameter controls how many of these
+ * dummy devices are registered.
+ */
+static unsigned instances = 1;
+module_param(instances, uint, 0);
+
+/* Pointer array used to fake bus elements */
+static struct iio_dev **iio_dummy_devs;
+
+/* Fake a name for the part number, usually obtained from the id table */
+static const char *iio_dummy_part_number = "iio_dummy_part_no";
+
+/**
+ * struct iio_dummy_accel_calibscale - realworld to register mapping
+ * @val: first value in read_raw - here integer part.
+ * @val2: second value in read_raw etc - here micro part.
+ * @regval: register value - magic device specific numbers.
+ */
+struct iio_dummy_accel_calibscale {
+       int val;
+       int val2;
+       int regval; /* what would be written to hardware */
+};
+
+static const struct iio_dummy_accel_calibscale dummy_scales[] = {
+       { 0, 100, 0x8 }, /* 0.000100 */
+       { 0, 133, 0x7 }, /* 0.000133 */
+       { 733, 13, 0x9 }, /* 733.000013 */
+};
+
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+
+/*
+ * simple event - triggered when value rises above
+ * a threshold
+ */
+static const struct iio_event_spec iio_dummy_event = {
+       .type = IIO_EV_TYPE_THRESH,
+       .dir = IIO_EV_DIR_RISING,
+       .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple step detect event - triggered when a step is detected
+ */
+static const struct iio_event_spec step_detect_event = {
+       .type = IIO_EV_TYPE_CHANGE,
+       .dir = IIO_EV_DIR_NONE,
+       .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple transition event - triggered when the reported running confidence
+ * value rises above a threshold value
+ */
+static const struct iio_event_spec iio_running_event = {
+       .type = IIO_EV_TYPE_THRESH,
+       .dir = IIO_EV_DIR_RISING,
+       .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple transition event - triggered when the reported walking confidence
+ * value falls under a threshold value
+ */
+static const struct iio_event_spec iio_walking_event = {
+       .type = IIO_EV_TYPE_THRESH,
+       .dir = IIO_EV_DIR_FALLING,
+       .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
+#endif
+
+/*
+ * iio_dummy_channels - Description of available channels
+ *
+ * This array of structures tells the IIO core about what the device
+ * actually provides for a given channel.
+ */
+static const struct iio_chan_spec iio_dummy_channels[] = {
+       /* indexed ADC channel in_voltage0_raw etc */
+       {
+               .type = IIO_VOLTAGE,
+               /* Channel has a numeric index of 0 */
+               .indexed = 1,
+               .channel = 0,
+               /* What other information is available? */
+               .info_mask_separate =
+               /*
+                * in_voltage0_raw
+                * Raw (unscaled no bias removal etc) measurement
+                * from the device.
+                */
+               BIT(IIO_CHAN_INFO_RAW) |
+               /*
+                * in_voltage0_offset
+                * Offset for userspace to apply prior to scale
+                * when converting to standard units (microvolts)
+                */
+               BIT(IIO_CHAN_INFO_OFFSET) |
+               /*
+                * in_voltage0_scale
+                * Multipler for userspace to apply post offset
+                * when converting to standard units (microvolts)
+                */
+               BIT(IIO_CHAN_INFO_SCALE),
+               /*
+                * sampling_frequency
+                * The frequency in Hz at which the channels are sampled
+                */
+               .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               /* The ordering of elements in the buffer via an enum */
+               .scan_index = DUMMY_INDEX_VOLTAGE_0,
+               .scan_type = { /* Description of storage in buffer */
+                       .sign = 'u', /* unsigned */
+                       .realbits = 13, /* 13 bits */
+                       .storagebits = 16, /* 16 bits used for storage */
+                       .shift = 0, /* zero shift */
+               },
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+               .event_spec = &iio_dummy_event,
+               .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+       },
+       /* Differential ADC channel in_voltage1-voltage2_raw etc*/
+       {
+               .type = IIO_VOLTAGE,
+               .differential = 1,
+               /*
+                * Indexing for differential channels uses channel
+                * for the positive part, channel2 for the negative.
+                */
+               .indexed = 1,
+               .channel = 1,
+               .channel2 = 2,
+               /*
+                * in_voltage1-voltage2_raw
+                * Raw (unscaled no bias removal etc) measurement
+                * from the device.
+                */
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               /*
+                * in_voltage-voltage_scale
+                * Shared version of scale - shared by differential
+                * input channels of type IIO_VOLTAGE.
+                */
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+               /*
+                * sampling_frequency
+                * The frequency in Hz at which the channels are sampled
+                */
+               .scan_index = DUMMY_INDEX_DIFFVOLTAGE_1M2,
+               .scan_type = { /* Description of storage in buffer */
+                       .sign = 's', /* signed */
+                       .realbits = 12, /* 12 bits */
+                       .storagebits = 16, /* 16 bits used for storage */
+                       .shift = 0, /* zero shift */
+               },
+       },
+       /* Differential ADC channel in_voltage3-voltage4_raw etc*/
+       {
+               .type = IIO_VOLTAGE,
+               .differential = 1,
+               .indexed = 1,
+               .channel = 3,
+               .channel2 = 4,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+               .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .scan_index = DUMMY_INDEX_DIFFVOLTAGE_3M4,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 11,
+                       .storagebits = 16,
+                       .shift = 0,
+               },
+       },
+       /*
+        * 'modified' (i.e. axis specified) acceleration channel
+        * in_accel_z_raw
+        */
+       {
+               .type = IIO_ACCEL,
+               .modified = 1,
+               /* Channel 2 is use for modifiers */
+               .channel2 = IIO_MOD_X,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+               /*
+                * Internal bias and gain correction values. Applied
+                * by the hardware or driver prior to userspace
+                * seeing the readings. Typically part of hardware
+                * calibration.
+                */
+               BIT(IIO_CHAN_INFO_CALIBSCALE) |
+               BIT(IIO_CHAN_INFO_CALIBBIAS),
+               .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .scan_index = DUMMY_INDEX_ACCELX,
+               .scan_type = { /* Description of storage in buffer */
+                       .sign = 's', /* signed */
+                       .realbits = 16, /* 16 bits */
+                       .storagebits = 16, /* 16 bits used for storage */
+                       .shift = 0, /* zero shift */
+               },
+       },
+       /*
+        * Convenience macro for timestamps. 4 is the index in
+        * the buffer.
+        */
+       IIO_CHAN_SOFT_TIMESTAMP(4),
+       /* DAC channel out_voltage0_raw */
+       {
+               .type = IIO_VOLTAGE,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .scan_index = -1, /* No buffer support */
+               .output = 1,
+               .indexed = 1,
+               .channel = 0,
+       },
+       {
+               .type = IIO_STEPS,
+               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_ENABLE) |
+                       BIT(IIO_CHAN_INFO_CALIBHEIGHT),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+               .event_spec = &step_detect_event,
+               .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+       },
+       {
+               .type = IIO_ACTIVITY,
+               .modified = 1,
+               .channel2 = IIO_MOD_RUNNING,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+               .event_spec = &iio_running_event,
+               .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+       },
+       {
+               .type = IIO_ACTIVITY,
+               .modified = 1,
+               .channel2 = IIO_MOD_WALKING,
+               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+               .scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+               .event_spec = &iio_walking_event,
+               .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+       },
+};
+
+/**
+ * iio_dummy_read_raw() - data read function.
+ * @indio_dev: the struct iio_dev associated with this device instance
+ * @chan:      the channel whose data is to be read
+ * @val:       first element of returned value (typically INT)
+ * @val2:      second element of returned value (typically MICRO)
+ * @mask:      what we actually want to read as per the info_mask_*
+ *             in iio_chan_spec.
+ */
+static int iio_dummy_read_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int *val,
+                             int *val2,
+                             long mask)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+       int ret = -EINVAL;
+
+       mutex_lock(&st->lock);
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       if (chan->output) {
+                               /* Set integer part to cached value */
+                               *val = st->dac_val;
+                               ret = IIO_VAL_INT;
+                       } else if (chan->differential) {
+                               if (chan->channel == 1)
+                                       *val = st->differential_adc_val[0];
+                               else
+                                       *val = st->differential_adc_val[1];
+                               ret = IIO_VAL_INT;
+                       } else {
+                               *val = st->single_ended_adc_val;
+                               ret = IIO_VAL_INT;
+                       }
+                       break;
+               case IIO_ACCEL:
+                       *val = st->accel_val;
+                       ret = IIO_VAL_INT;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case IIO_CHAN_INFO_PROCESSED:
+               switch (chan->type) {
+               case IIO_STEPS:
+                       *val = st->steps;
+                       ret = IIO_VAL_INT;
+                       break;
+               case IIO_ACTIVITY:
+                       switch (chan->channel2) {
+                       case IIO_MOD_RUNNING:
+                               *val = st->activity_running;
+                               ret = IIO_VAL_INT;
+                               break;
+                       case IIO_MOD_WALKING:
+                               *val = st->activity_walking;
+                               ret = IIO_VAL_INT;
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case IIO_CHAN_INFO_OFFSET:
+               /* only single ended adc -> 7 */
+               *val = 7;
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_SCALE:
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       switch (chan->differential) {
+                       case 0:
+                               /* only single ended adc -> 0.001333 */
+                               *val = 0;
+                               *val2 = 1333;
+                               ret = IIO_VAL_INT_PLUS_MICRO;
+                               break;
+                       case 1:
+                               /* all differential adc -> 0.000001344 */
+                               *val = 0;
+                               *val2 = 1344;
+                               ret = IIO_VAL_INT_PLUS_NANO;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               /* only the acceleration axis - read from cache */
+               *val = st->accel_calibbias;
+               ret = IIO_VAL_INT;
+               break;
+       case IIO_CHAN_INFO_CALIBSCALE:
+               *val = st->accel_calibscale->val;
+               *val2 = st->accel_calibscale->val2;
+               ret = IIO_VAL_INT_PLUS_MICRO;
+               break;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *val = 3;
+               *val2 = 33;
+               ret = IIO_VAL_INT_PLUS_NANO;
+               break;
+       case IIO_CHAN_INFO_ENABLE:
+               switch (chan->type) {
+               case IIO_STEPS:
+                       *val = st->steps_enabled;
+                       ret = IIO_VAL_INT;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case IIO_CHAN_INFO_CALIBHEIGHT:
+               switch (chan->type) {
+               case IIO_STEPS:
+                       *val = st->height;
+                       ret = IIO_VAL_INT;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+/**
+ * iio_dummy_write_raw() - data write function.
+ * @indio_dev: the struct iio_dev associated with this device instance
+ * @chan:      the channel whose data is to be written
+ * @val:       first element of value to set (typically INT)
+ * @val2:      second element of value to set (typically MICRO)
+ * @mask:      what we actually want to write as per the info_mask_*
+ *             in iio_chan_spec.
+ *
+ * Note that all raw writes are assumed IIO_VAL_INT and info mask elements
+ * are assumed to be IIO_INT_PLUS_MICRO unless the callback write_raw_get_fmt
+ * in struct iio_info is provided by the driver.
+ */
+static int iio_dummy_write_raw(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              int val,
+                              int val2,
+                              long mask)
+{
+       int i;
+       int ret = 0;
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       if (chan->output == 0)
+                               return -EINVAL;
+
+                       /* Locking not required as writing single value */
+                       mutex_lock(&st->lock);
+                       st->dac_val = val;
+                       mutex_unlock(&st->lock);
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_PROCESSED:
+               switch (chan->type) {
+               case IIO_STEPS:
+                       mutex_lock(&st->lock);
+                       st->steps = val;
+                       mutex_unlock(&st->lock);
+                       return 0;
+               case IIO_ACTIVITY:
+                       if (val < 0)
+                               val = 0;
+                       if (val > 100)
+                               val = 100;
+                       switch (chan->channel2) {
+                       case IIO_MOD_RUNNING:
+                               st->activity_running = val;
+                               return 0;
+                       case IIO_MOD_WALKING:
+                               st->activity_walking = val;
+                               return 0;
+                       default:
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_CALIBSCALE:
+               mutex_lock(&st->lock);
+               /* Compare against table - hard matching here */
+               for (i = 0; i < ARRAY_SIZE(dummy_scales); i++)
+                       if (val == dummy_scales[i].val &&
+                           val2 == dummy_scales[i].val2)
+                               break;
+               if (i == ARRAY_SIZE(dummy_scales))
+                       ret = -EINVAL;
+               else
+                       st->accel_calibscale = &dummy_scales[i];
+               mutex_unlock(&st->lock);
+               return ret;
+       case IIO_CHAN_INFO_CALIBBIAS:
+               mutex_lock(&st->lock);
+               st->accel_calibbias = val;
+               mutex_unlock(&st->lock);
+               return 0;
+       case IIO_CHAN_INFO_ENABLE:
+               switch (chan->type) {
+               case IIO_STEPS:
+                       mutex_lock(&st->lock);
+                       st->steps_enabled = val;
+                       mutex_unlock(&st->lock);
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+       case IIO_CHAN_INFO_CALIBHEIGHT:
+               switch (chan->type) {
+               case IIO_STEPS:
+                       st->height = val;
+                       return 0;
+               default:
+                       return -EINVAL;
+               }
+
+       default:
+               return -EINVAL;
+       }
+}
+
+/*
+ * Device type specific information.
+ */
+static const struct iio_info iio_dummy_info = {
+       .driver_module = THIS_MODULE,
+       .read_raw = &iio_dummy_read_raw,
+       .write_raw = &iio_dummy_write_raw,
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+       .read_event_config = &iio_simple_dummy_read_event_config,
+       .write_event_config = &iio_simple_dummy_write_event_config,
+       .read_event_value = &iio_simple_dummy_read_event_value,
+       .write_event_value = &iio_simple_dummy_write_event_value,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+};
+
+/**
+ * iio_dummy_init_device() - device instance specific init
+ * @indio_dev: the iio device structure
+ *
+ * Most drivers have one of these to set up default values,
+ * reset the device to known state etc.
+ */
+static int iio_dummy_init_device(struct iio_dev *indio_dev)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       st->dac_val = 0;
+       st->single_ended_adc_val = 73;
+       st->differential_adc_val[0] = 33;
+       st->differential_adc_val[1] = -34;
+       st->accel_val = 34;
+       st->accel_calibbias = -7;
+       st->accel_calibscale = &dummy_scales[0];
+       st->steps = 47;
+       st->activity_running = 98;
+       st->activity_walking = 4;
+
+       return 0;
+}
+
+/**
+ * iio_dummy_probe() - device instance probe
+ * @index: an id number for this instance.
+ *
+ * Arguments are bus type specific.
+ * I2C: iio_dummy_probe(struct i2c_client *client,
+ *                      const struct i2c_device_id *id)
+ * SPI: iio_dummy_probe(struct spi_device *spi)
+ */
+static int iio_dummy_probe(int index)
+{
+       int ret;
+       struct iio_dev *indio_dev;
+       struct iio_dummy_state *st;
+
+       /*
+        * Allocate an IIO device.
+        *
+        * This structure contains all generic state
+        * information about the device instance.
+        * It also has a region (accessed by iio_priv()
+        * for chip specific state information.
+        */
+       indio_dev = iio_device_alloc(sizeof(*st));
+       if (!indio_dev) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       st = iio_priv(indio_dev);
+       mutex_init(&st->lock);
+
+       iio_dummy_init_device(indio_dev);
+       /*
+        * With hardware: Set the parent device.
+        * indio_dev->dev.parent = &spi->dev;
+        * indio_dev->dev.parent = &client->dev;
+        */
+
+        /*
+        * Make the iio_dev struct available to remove function.
+        * Bus equivalents
+        * i2c_set_clientdata(client, indio_dev);
+        * spi_set_drvdata(spi, indio_dev);
+        */
+       iio_dummy_devs[index] = indio_dev;
+
+       /*
+        * Set the device name.
+        *
+        * This is typically a part number and obtained from the module
+        * id table.
+        * e.g. for i2c and spi:
+        *    indio_dev->name = id->name;
+        *    indio_dev->name = spi_get_device_id(spi)->name;
+        */
+       indio_dev->name = iio_dummy_part_number;
+
+       /* Provide description of available channels */
+       indio_dev->channels = iio_dummy_channels;
+       indio_dev->num_channels = ARRAY_SIZE(iio_dummy_channels);
+
+       /*
+        * Provide device type specific interface functions and
+        * constant data.
+        */
+       indio_dev->info = &iio_dummy_info;
+
+       /* Specify that device provides sysfs type interfaces */
+       indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_simple_dummy_events_register(indio_dev);
+       if (ret < 0)
+               goto error_free_device;
+
+       ret = iio_simple_dummy_configure_buffer(indio_dev);
+       if (ret < 0)
+               goto error_unregister_events;
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0)
+               goto error_unconfigure_buffer;
+
+       return 0;
+error_unconfigure_buffer:
+       iio_simple_dummy_unconfigure_buffer(indio_dev);
+error_unregister_events:
+       iio_simple_dummy_events_unregister(indio_dev);
+error_free_device:
+       iio_device_free(indio_dev);
+error_ret:
+       return ret;
+}
+
+/**
+ * iio_dummy_remove() - device instance removal function
+ * @index: device index.
+ *
+ * Parameters follow those of iio_dummy_probe for buses.
+ */
+static void iio_dummy_remove(int index)
+{
+       /*
+        * Get a pointer to the device instance iio_dev structure
+        * from the bus subsystem. E.g.
+        * struct iio_dev *indio_dev = i2c_get_clientdata(client);
+        * struct iio_dev *indio_dev = spi_get_drvdata(spi);
+        */
+       struct iio_dev *indio_dev = iio_dummy_devs[index];
+
+       /* Unregister the device */
+       iio_device_unregister(indio_dev);
+
+       /* Device specific code to power down etc */
+
+       /* Buffered capture related cleanup */
+       iio_simple_dummy_unconfigure_buffer(indio_dev);
+
+       iio_simple_dummy_events_unregister(indio_dev);
+
+       /* Free all structures */
+       iio_device_free(indio_dev);
+}
+
+/**
+ * iio_dummy_init() -  device driver registration
+ *
+ * Varies depending on bus type of the device. As there is no device
+ * here, call probe directly. For information on device registration
+ * i2c:
+ * Documentation/i2c/writing-clients
+ * spi:
+ * Documentation/spi/spi-summary
+ */
+static __init int iio_dummy_init(void)
+{
+       int i, ret;
+
+       if (instances > 10) {
+               instances = 1;
+               return -EINVAL;
+       }
+
+       /* Fake a bus */
+       iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs),
+                                GFP_KERNEL);
+       /* Here we have no actual device so call probe */
+       for (i = 0; i < instances; i++) {
+               ret = iio_dummy_probe(i);
+               if (ret < 0)
+                       goto error_remove_devs;
+       }
+       return 0;
+
+error_remove_devs:
+       while (i--)
+               iio_dummy_remove(i);
+
+       kfree(iio_dummy_devs);
+       return ret;
+}
+module_init(iio_dummy_init);
+
+/**
+ * iio_dummy_exit() - device driver removal
+ *
+ * Varies depending on bus type of the device.
+ * As there is no device here, call remove directly.
+ */
+static __exit void iio_dummy_exit(void)
+{
+       int i;
+
+       for (i = 0; i < instances; i++)
+               iio_dummy_remove(i);
+       kfree(iio_dummy_devs);
+}
+module_exit(iio_dummy_exit);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("IIO dummy driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/dummy/iio_simple_dummy.h b/drivers/iio/dummy/iio_simple_dummy.h
new file mode 100644 (file)
index 0000000..b9069a1
--- /dev/null
@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Join together the various functionality of iio_simple_dummy driver
+ */
+
+#ifndef _IIO_SIMPLE_DUMMY_H_
+#define _IIO_SIMPLE_DUMMY_H_
+#include <linux/kernel.h>
+
+struct iio_dummy_accel_calibscale;
+struct iio_dummy_regs;
+
+/**
+ * struct iio_dummy_state - device instance specific state.
+ * @dac_val:                   cache for dac value
+ * @single_ended_adc_val:      cache for single ended adc value
+ * @differential_adc_val:      cache for differential adc value
+ * @accel_val:                 cache for acceleration value
+ * @accel_calibbias:           cache for acceleration calibbias
+ * @accel_calibscale:          cache for acceleration calibscale
+ * @lock:                      lock to ensure state is consistent
+ * @event_irq:                 irq number for event line (faked)
+ * @event_val:                 cache for event threshold value
+ * @event_en:                  cache of whether event is enabled
+ */
+struct iio_dummy_state {
+       int dac_val;
+       int single_ended_adc_val;
+       int differential_adc_val[2];
+       int accel_val;
+       int accel_calibbias;
+       int activity_running;
+       int activity_walking;
+       const struct iio_dummy_accel_calibscale *accel_calibscale;
+       struct mutex lock;
+       struct iio_dummy_regs *regs;
+       int steps_enabled;
+       int steps;
+       int height;
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+       int event_irq;
+       int event_val;
+       bool event_en;
+       s64 event_timestamp;
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+};
+
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+
+struct iio_dev;
+
+int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
+                                      const struct iio_chan_spec *chan,
+                                      enum iio_event_type type,
+                                      enum iio_event_direction dir);
+
+int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan,
+                                       enum iio_event_type type,
+                                       enum iio_event_direction dir,
+                                       int state);
+
+int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
+                                     const struct iio_chan_spec *chan,
+                                     enum iio_event_type type,
+                                     enum iio_event_direction dir,
+                                     enum iio_event_info info, int *val,
+                                     int *val2);
+
+int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
+                                      const struct iio_chan_spec *chan,
+                                      enum iio_event_type type,
+                                      enum iio_event_direction dir,
+                                      enum iio_event_info info, int val,
+                                      int val2);
+
+int iio_simple_dummy_events_register(struct iio_dev *indio_dev);
+void iio_simple_dummy_events_unregister(struct iio_dev *indio_dev);
+
+#else /* Stubs for when events are disabled at compile time */
+
+static inline int
+iio_simple_dummy_events_register(struct iio_dev *indio_dev)
+{
+       return 0;
+};
+
+static inline void
+iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
+{ };
+
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS*/
+
+/**
+ * enum iio_simple_dummy_scan_elements - scan index enum
+ * @DUMMY_INDEX_VOLTAGE_0:         the single ended voltage channel
+ * @DUMMY_INDEX_DIFFVOLTAGE_1M2:   first differential channel
+ * @DUMMY_INDEX_DIFFVOLTAGE_3M4:   second differential channel
+ * @DUMMY_INDEX_ACCELX:            acceleration channel
+ *
+ * Enum provides convenient numbering for the scan index.
+ */
+enum iio_simple_dummy_scan_elements {
+       DUMMY_INDEX_VOLTAGE_0,
+       DUMMY_INDEX_DIFFVOLTAGE_1M2,
+       DUMMY_INDEX_DIFFVOLTAGE_3M4,
+       DUMMY_INDEX_ACCELX,
+};
+
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
+void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
+#else
+static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
+{
+       return 0;
+};
+
+static inline
+void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
+{};
+
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_BUFFER */
+#endif /* _IIO_SIMPLE_DUMMY_H_ */
diff --git a/drivers/iio/dummy/iio_simple_dummy_buffer.c b/drivers/iio/dummy/iio_simple_dummy_buffer.c
new file mode 100644 (file)
index 0000000..cf44a6f
--- /dev/null
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Buffer handling elements of industrial I/O reference driver.
+ * Uses the kfifo buffer.
+ *
+ * To test without hardware use the sysfs trigger.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/bitmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/kfifo_buf.h>
+
+#include "iio_simple_dummy.h"
+
+/* Some fake data */
+
+static const s16 fakedata[] = {
+       [DUMMY_INDEX_VOLTAGE_0] = 7,
+       [DUMMY_INDEX_DIFFVOLTAGE_1M2] = -33,
+       [DUMMY_INDEX_DIFFVOLTAGE_3M4] = -2,
+       [DUMMY_INDEX_ACCELX] = 344,
+};
+
+/**
+ * iio_simple_dummy_trigger_h() - the trigger handler function
+ * @irq: the interrupt number
+ * @p: private data - always a pointer to the poll func.
+ *
+ * This is the guts of buffered capture. On a trigger event occurring,
+ * if the pollfunc is attached then this handler is called as a threaded
+ * interrupt (and hence may sleep). It is responsible for grabbing data
+ * from the device and pushing it into the associated buffer.
+ */
+static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       int len = 0;
+       u16 *data;
+
+       data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+       if (!data)
+               goto done;
+
+       if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) {
+               /*
+                * Three common options here:
+                * hardware scans: certain combinations of channels make
+                *   up a fast read.  The capture will consist of all of them.
+                *   Hence we just call the grab data function and fill the
+                *   buffer without processing.
+                * software scans: can be considered to be random access
+                *   so efficient reading is just a case of minimal bus
+                *   transactions.
+                * software culled hardware scans:
+                *   occasionally a driver may process the nearest hardware
+                *   scan to avoid storing elements that are not desired. This
+                *   is the fiddliest option by far.
+                * Here let's pretend we have random access. And the values are
+                * in the constant table fakedata.
+                */
+               int i, j;
+
+               for (i = 0, j = 0;
+                    i < bitmap_weight(indio_dev->active_scan_mask,
+                                      indio_dev->masklength);
+                    i++, j++) {
+                       j = find_next_bit(indio_dev->active_scan_mask,
+                                         indio_dev->masklength, j);
+                       /* random access read from the 'device' */
+                       data[i] = fakedata[j];
+                       len += 2;
+               }
+       }
+
+       iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns());
+
+       kfree(data);
+
+done:
+       /*
+        * Tell the core we are done with this trigger and ready for the
+        * next one.
+        */
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
+       /*
+        * iio_triggered_buffer_postenable:
+        * Generic function that simply attaches the pollfunc to the trigger.
+        * Replace this to mess with hardware state before we attach the
+        * trigger.
+        */
+       .postenable = &iio_triggered_buffer_postenable,
+       /*
+        * iio_triggered_buffer_predisable:
+        * Generic function that simple detaches the pollfunc from the trigger.
+        * Replace this to put hardware state back again after the trigger is
+        * detached but before userspace knows we have disabled the ring.
+        */
+       .predisable = &iio_triggered_buffer_predisable,
+};
+
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct iio_buffer *buffer;
+
+       /* Allocate a buffer to use - here a kfifo */
+       buffer = iio_kfifo_allocate();
+       if (!buffer) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       iio_device_attach_buffer(indio_dev, buffer);
+
+       /* Enable timestamps by default */
+       buffer->scan_timestamp = true;
+
+       /*
+        * Tell the core what device type specific functions should
+        * be run on either side of buffer capture enable / disable.
+        */
+       indio_dev->setup_ops = &iio_simple_dummy_buffer_setup_ops;
+
+       /*
+        * Configure a polling function.
+        * When a trigger event with this polling function connected
+        * occurs, this function is run. Typically this grabs data
+        * from the device.
+        *
+        * NULL for the bottom half. This is normally implemented only if we
+        * either want to ping a capture now pin (no sleeping) or grab
+        * a timestamp as close as possible to a data ready trigger firing.
+        *
+        * IRQF_ONESHOT ensures irqs are masked such that only one instance
+        * of the handler can run at a time.
+        *
+        * "iio_simple_dummy_consumer%d" formatting string for the irq 'name'
+        * as seen under /proc/interrupts. Remaining parameters as per printk.
+        */
+       indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
+                                                &iio_simple_dummy_trigger_h,
+                                                IRQF_ONESHOT,
+                                                indio_dev,
+                                                "iio_simple_dummy_consumer%d",
+                                                indio_dev->id);
+
+       if (!indio_dev->pollfunc) {
+               ret = -ENOMEM;
+               goto error_free_buffer;
+       }
+
+       /*
+        * Notify the core that this device is capable of buffered capture
+        * driven by a trigger.
+        */
+       indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+       return 0;
+
+error_free_buffer:
+       iio_kfifo_free(indio_dev->buffer);
+error_ret:
+       return ret;
+}
+
+/**
+ * iio_simple_dummy_unconfigure_buffer() - release buffer resources
+ * @indo_dev: device instance state
+ */
+void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
+{
+       iio_dealloc_pollfunc(indio_dev->pollfunc);
+       iio_kfifo_free(indio_dev->buffer);
+}
diff --git a/drivers/iio/dummy/iio_simple_dummy_events.c b/drivers/iio/dummy/iio_simple_dummy_events.c
new file mode 100644 (file)
index 0000000..bfbf1c5
--- /dev/null
@@ -0,0 +1,276 @@
+/**
+ * Copyright (c) 2011 Jonathan Cameron
+ *
+ * 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.
+ *
+ * Event handling elements of industrial I/O reference driver.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include "iio_simple_dummy.h"
+
+/* Evgen 'fakes' interrupt events for this example */
+#include "iio_dummy_evgen.h"
+
+/**
+ * iio_simple_dummy_read_event_config() - is event enabled?
+ * @indio_dev: the device instance data
+ * @chan: channel for the event whose state is being queried
+ * @type: type of the event whose state is being queried
+ * @dir: direction of the vent whose state is being queried
+ *
+ * This function would normally query the relevant registers or a cache to
+ * discover if the event generation is enabled on the device.
+ */
+int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
+                                      const struct iio_chan_spec *chan,
+                                      enum iio_event_type type,
+                                      enum iio_event_direction dir)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       return st->event_en;
+}
+
+/**
+ * iio_simple_dummy_write_event_config() - set whether event is enabled
+ * @indio_dev: the device instance data
+ * @chan: channel for the event whose state is being set
+ * @type: type of the event whose state is being set
+ * @dir: direction of the vent whose state is being set
+ * @state: whether to enable or disable the device.
+ *
+ * This function would normally set the relevant registers on the devices
+ * so that it generates the specified event. Here it just sets up a cached
+ * value.
+ */
+int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
+                                       const struct iio_chan_spec *chan,
+                                       enum iio_event_type type,
+                                       enum iio_event_direction dir,
+                                       int state)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       /*
+        *  Deliberately over the top code splitting to illustrate
+        * how this is done when multiple events exist.
+        */
+       switch (chan->type) {
+       case IIO_VOLTAGE:
+               switch (type) {
+               case IIO_EV_TYPE_THRESH:
+                       if (dir == IIO_EV_DIR_RISING)
+                               st->event_en = state;
+                       else
+                               return -EINVAL;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_ACTIVITY:
+               switch (type) {
+               case IIO_EV_TYPE_THRESH:
+                       st->event_en = state;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case IIO_STEPS:
+               switch (type) {
+               case IIO_EV_TYPE_CHANGE:
+                       st->event_en = state;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * iio_simple_dummy_read_event_value() - get value associated with event
+ * @indio_dev: device instance specific data
+ * @chan: channel for the event whose value is being read
+ * @type: type of the event whose value is being read
+ * @dir: direction of the vent whose value is being read
+ * @info: info type of the event whose value is being read
+ * @val: value for the event code.
+ *
+ * Many devices provide a large set of events of which only a subset may
+ * be enabled at a time, with value registers whose meaning changes depending
+ * on the event enabled. This often means that the driver must cache the values
+ * associated with each possible events so that the right value is in place when
+ * the enabled event is changed.
+ */
+int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
+                                     const struct iio_chan_spec *chan,
+                                     enum iio_event_type type,
+                                     enum iio_event_direction dir,
+                                     enum iio_event_info info,
+                                     int *val, int *val2)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       *val = st->event_val;
+
+       return IIO_VAL_INT;
+}
+
+/**
+ * iio_simple_dummy_write_event_value() - set value associate with event
+ * @indio_dev: device instance specific data
+ * @chan: channel for the event whose value is being set
+ * @type: type of the event whose value is being set
+ * @dir: direction of the vent whose value is being set
+ * @info: info type of the event whose value is being set
+ * @val: the value to be set.
+ */
+int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
+                                      const struct iio_chan_spec *chan,
+                                      enum iio_event_type type,
+                                      enum iio_event_direction dir,
+                                      enum iio_event_info info,
+                                      int val, int val2)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       st->event_val = val;
+
+       return 0;
+}
+
+static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       st->event_timestamp = iio_get_time_ns();
+       return IRQ_HANDLED;
+}
+
+/**
+ * iio_simple_dummy_event_handler() - identify and pass on event
+ * @irq: irq of event line
+ * @private: pointer to device instance state.
+ *
+ * This handler is responsible for querying the device to find out what
+ * event occurred and for then pushing that event towards userspace.
+ * Here only one event occurs so we push that directly on with locally
+ * grabbed timestamp.
+ */
+static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
+{
+       struct iio_dev *indio_dev = private;
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       dev_dbg(&indio_dev->dev, "id %x event %x\n",
+               st->regs->reg_id, st->regs->reg_data);
+
+       switch (st->regs->reg_data) {
+       case 0:
+               iio_push_event(indio_dev,
+                              IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
+                                             IIO_EV_DIR_RISING,
+                                             IIO_EV_TYPE_THRESH, 0, 0, 0),
+                              st->event_timestamp);
+               break;
+       case 1:
+               if (st->activity_running > st->event_val)
+                       iio_push_event(indio_dev,
+                                      IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+                                                     IIO_MOD_RUNNING,
+                                                     IIO_EV_DIR_RISING,
+                                                     IIO_EV_TYPE_THRESH,
+                                                     0, 0, 0),
+                                      st->event_timestamp);
+               break;
+       case 2:
+               if (st->activity_walking < st->event_val)
+                       iio_push_event(indio_dev,
+                                      IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+                                                     IIO_MOD_WALKING,
+                                                     IIO_EV_DIR_FALLING,
+                                                     IIO_EV_TYPE_THRESH,
+                                                     0, 0, 0),
+                                      st->event_timestamp);
+               break;
+       case 3:
+               iio_push_event(indio_dev,
+                              IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
+                                             IIO_EV_DIR_NONE,
+                                             IIO_EV_TYPE_CHANGE, 0, 0, 0),
+                              st->event_timestamp);
+               break;
+       default:
+               break;
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * iio_simple_dummy_events_register() - setup interrupt handling for events
+ * @indio_dev: device instance data
+ *
+ * This function requests the threaded interrupt to handle the events.
+ * Normally the irq is a hardware interrupt and the number comes
+ * from board configuration files.  Here we get it from a companion
+ * module that fakes the interrupt for us. Note that module in
+ * no way forms part of this example. Just assume that events magically
+ * appear via the provided interrupt.
+ */
+int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+       int ret;
+
+       /* Fire up event source - normally not present */
+       st->event_irq = iio_dummy_evgen_get_irq();
+       if (st->event_irq < 0) {
+               ret = st->event_irq;
+               goto error_ret;
+       }
+       st->regs = iio_dummy_evgen_get_regs(st->event_irq);
+
+       ret = request_threaded_irq(st->event_irq,
+                                  &iio_simple_dummy_get_timestamp,
+                                  &iio_simple_dummy_event_handler,
+                                  IRQF_ONESHOT,
+                                  "iio_simple_event",
+                                  indio_dev);
+       if (ret < 0)
+               goto error_free_evgen;
+       return 0;
+
+error_free_evgen:
+       iio_dummy_evgen_release_irq(st->event_irq);
+error_ret:
+       return ret;
+}
+
+/**
+ * iio_simple_dummy_events_unregister() - tidy up interrupt handling on remove
+ * @indio_dev: device instance data
+ */
+void iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
+{
+       struct iio_dummy_state *st = iio_priv(indio_dev);
+
+       free_irq(st->event_irq, indio_dev);
+       /* Not part of normal driver */
+       iio_dummy_evgen_release_irq(st->event_irq);
+}
index f8d1c22100660d752c0b1d192291f76b6675f4d5..b04faf93e1bc610e9df282ff78ce7ceef18d968d 100644 (file)
@@ -435,7 +435,9 @@ static int adis16136_initial_setup(struct iio_dev *indio_dev)
        if (ret)
                return ret;
 
-       sscanf(indio_dev->name, "adis%u\n", &device_id);
+       ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+       if (ret != 1)
+               return -EINVAL;
 
        if (prod_id != device_id)
                dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
index 02ff789852a05b411d20aaa7b89e92039305e6cd..bbce3b09ac45abdbc3491fee51d74bcfbab9eb87 100644 (file)
@@ -1077,25 +1077,23 @@ int bmg160_core_probe(struct device *dev, struct regmap *regmap, int irq,
                goto err_trigger_unregister;
        }
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(dev, "unable to register iio device\n");
-               goto err_buffer_cleanup;
-       }
-
        ret = pm_runtime_set_active(dev);
        if (ret)
-               goto err_iio_unregister;
+               goto err_buffer_cleanup;
 
        pm_runtime_enable(dev);
        pm_runtime_set_autosuspend_delay(dev,
                                         BMG160_AUTO_SUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(dev);
 
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(dev, "unable to register iio device\n");
+               goto err_buffer_cleanup;
+       }
+
        return 0;
 
-err_iio_unregister:
-       iio_device_unregister(indio_dev);
 err_buffer_cleanup:
        iio_triggered_buffer_cleanup(indio_dev);
 err_trigger_unregister:
@@ -1113,11 +1111,12 @@ void bmg160_core_remove(struct device *dev)
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct bmg160_data *data = iio_priv(indio_dev);
 
+       iio_device_unregister(indio_dev);
+
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
        pm_runtime_put_noidle(dev);
 
-       iio_device_unregister(indio_dev);
        iio_triggered_buffer_cleanup(indio_dev);
 
        if (data->dready_trig) {
index 0618f831ecd49fdb7dce287ffacb34928595c556..fb7c0dbed51cb9b78872949a1807c1e610d8a056 100644 (file)
@@ -288,7 +288,11 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev)
                if (ret)
                        goto err_ret;
 
-               sscanf(indio_dev->name, "adis%u\n", &device_id);
+               ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+               if (ret != 1) {
+                       ret = -EINVAL;
+                       goto err_ret;
+               }
 
                if (prod_id != device_id)
                        dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
index 2485b88ee1b654d4753e889aaec1376cc1e5d06d..8cf84d3488b2650c0ca2f265e8dc58f1b10efc0b 100644 (file)
@@ -765,7 +765,9 @@ static int adis16480_initial_setup(struct iio_dev *indio_dev)
        if (ret)
                return ret;
 
-       sscanf(indio_dev->name, "adis%u\n", &device_id);
+       ret = sscanf(indio_dev->name, "adis%u\n", &device_id);
+       if (ret != 1)
+               return -EINVAL;
 
        if (prod_id != device_id)
                dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
index dbf5e99366358815cd3d840440d6d8cc3adf8b54..e5306b4e020efca5ea45b7e20698d07053ef160d 100644 (file)
@@ -1390,6 +1390,14 @@ static int kmx61_probe(struct i2c_client *client,
                }
        }
 
+       ret = pm_runtime_set_active(&client->dev);
+       if (ret < 0)
+               goto err_buffer_cleanup_mag;
+
+       pm_runtime_enable(&client->dev);
+       pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
+       pm_runtime_use_autosuspend(&client->dev);
+
        ret = iio_device_register(data->acc_indio_dev);
        if (ret < 0) {
                dev_err(&client->dev, "Failed to register acc iio device\n");
@@ -1402,18 +1410,8 @@ static int kmx61_probe(struct i2c_client *client,
                goto err_iio_unregister_acc;
        }
 
-       ret = pm_runtime_set_active(&client->dev);
-       if (ret < 0)
-               goto err_iio_unregister_mag;
-
-       pm_runtime_enable(&client->dev);
-       pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
-       pm_runtime_use_autosuspend(&client->dev);
-
        return 0;
 
-err_iio_unregister_mag:
-       iio_device_unregister(data->mag_indio_dev);
 err_iio_unregister_acc:
        iio_device_unregister(data->acc_indio_dev);
 err_buffer_cleanup_mag:
@@ -1437,13 +1435,13 @@ static int kmx61_remove(struct i2c_client *client)
 {
        struct kmx61_data *data = i2c_get_clientdata(client);
 
+       iio_device_unregister(data->acc_indio_dev);
+       iio_device_unregister(data->mag_indio_dev);
+
        pm_runtime_disable(&client->dev);
        pm_runtime_set_suspended(&client->dev);
        pm_runtime_put_noidle(&client->dev);
 
-       iio_device_unregister(data->acc_indio_dev);
-       iio_device_unregister(data->mag_indio_dev);
-
        if (client->irq > 0) {
                iio_triggered_buffer_cleanup(data->acc_indio_dev);
                iio_triggered_buffer_cleanup(data->mag_indio_dev);
index d7e908acb48020b3f5390030e5a3687b03ba9878..a4b164a478c434c92927b28567d2f17f788f78cb 100644 (file)
@@ -193,7 +193,8 @@ void iio_buffer_init(struct iio_buffer *buffer)
        INIT_LIST_HEAD(&buffer->buffer_list);
        init_waitqueue_head(&buffer->pollq);
        kref_init(&buffer->ref);
-       buffer->watermark = 1;
+       if (!buffer->watermark)
+               buffer->watermark = 1;
 }
 EXPORT_SYMBOL(iio_buffer_init);
 
@@ -567,6 +568,22 @@ static void iio_buffer_deactivate_all(struct iio_dev *indio_dev)
                iio_buffer_deactivate(buffer);
 }
 
+static int iio_buffer_enable(struct iio_buffer *buffer,
+       struct iio_dev *indio_dev)
+{
+       if (!buffer->access->enable)
+               return 0;
+       return buffer->access->enable(buffer, indio_dev);
+}
+
+static int iio_buffer_disable(struct iio_buffer *buffer,
+       struct iio_dev *indio_dev)
+{
+       if (!buffer->access->disable)
+               return 0;
+       return buffer->access->disable(buffer, indio_dev);
+}
+
 static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
        struct iio_buffer *buffer)
 {
@@ -610,6 +627,7 @@ static void iio_free_scan_mask(struct iio_dev *indio_dev,
 
 struct iio_device_config {
        unsigned int mode;
+       unsigned int watermark;
        const unsigned long *scan_mask;
        unsigned int scan_bytes;
        bool scan_timestamp;
@@ -642,10 +660,14 @@ static int iio_verify_update(struct iio_dev *indio_dev,
                if (buffer == remove_buffer)
                        continue;
                modes &= buffer->access->modes;
+               config->watermark = min(config->watermark, buffer->watermark);
        }
 
-       if (insert_buffer)
+       if (insert_buffer) {
                modes &= insert_buffer->access->modes;
+               config->watermark = min(config->watermark,
+                       insert_buffer->watermark);
+       }
 
        /* Definitely possible for devices to support both of these. */
        if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
@@ -713,6 +735,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
 static int iio_enable_buffers(struct iio_dev *indio_dev,
        struct iio_device_config *config)
 {
+       struct iio_buffer *buffer;
        int ret;
 
        indio_dev->active_scan_mask = config->scan_mask;
@@ -743,6 +766,16 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
                }
        }
 
+       if (indio_dev->info->hwfifo_set_watermark)
+               indio_dev->info->hwfifo_set_watermark(indio_dev,
+                       config->watermark);
+
+       list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+               ret = iio_buffer_enable(buffer, indio_dev);
+               if (ret)
+                       goto err_disable_buffers;
+       }
+
        indio_dev->currentmode = config->mode;
 
        if (indio_dev->setup_ops->postenable) {
@@ -750,12 +783,16 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
                if (ret) {
                        dev_dbg(&indio_dev->dev,
                               "Buffer not started: postenable failed (%d)\n", ret);
-                       goto err_run_postdisable;
+                       goto err_disable_buffers;
                }
        }
 
        return 0;
 
+err_disable_buffers:
+       list_for_each_entry_continue_reverse(buffer, &indio_dev->buffer_list,
+                                            buffer_list)
+               iio_buffer_disable(buffer, indio_dev);
 err_run_postdisable:
        indio_dev->currentmode = INDIO_DIRECT_MODE;
        if (indio_dev->setup_ops->postdisable)
@@ -768,6 +805,7 @@ err_undo_config:
 
 static int iio_disable_buffers(struct iio_dev *indio_dev)
 {
+       struct iio_buffer *buffer;
        int ret = 0;
        int ret2;
 
@@ -788,6 +826,12 @@ static int iio_disable_buffers(struct iio_dev *indio_dev)
                        ret = ret2;
        }
 
+       list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+               ret2 = iio_buffer_disable(buffer, indio_dev);
+               if (ret2 && !ret)
+                       ret = ret2;
+       }
+
        indio_dev->currentmode = INDIO_DIRECT_MODE;
 
        if (indio_dev->setup_ops->postdisable) {
@@ -974,9 +1018,6 @@ static ssize_t iio_buffer_store_watermark(struct device *dev,
        }
 
        buffer->watermark = val;
-
-       if (indio_dev->info->hwfifo_set_watermark)
-               indio_dev->info->hwfifo_set_watermark(indio_dev, val);
 out:
        mutex_unlock(&indio_dev->mlock);
 
@@ -991,6 +1032,8 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
                   iio_buffer_show_enable, iio_buffer_store_enable);
 static DEVICE_ATTR(watermark, S_IRUGO | S_IWUSR,
                   iio_buffer_show_watermark, iio_buffer_store_watermark);
+static struct device_attribute dev_attr_watermark_ro = __ATTR(watermark,
+       S_IRUGO, iio_buffer_show_watermark, NULL);
 
 static struct attribute *iio_buffer_attrs[] = {
        &dev_attr_length.attr,
@@ -1033,6 +1076,9 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
        if (!buffer->access->set_length)
                attr[0] = &dev_attr_length_ro.attr;
 
+       if (buffer->access->flags & INDIO_BUFFER_FLAG_FIXED_WATERMARK)
+               attr[2] = &dev_attr_watermark_ro.attr;
+
        if (buffer->attrs)
                memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs,
                       sizeof(struct attribute *) * attrcount);
index 208358f9e7e36582152cad8c4f4924d9667a58cc..d0a84febd435ac14aa4123c07f6d6c68323a0d98 100644 (file)
@@ -512,6 +512,12 @@ int iio_str_to_fixpoint(const char *str, int fract_mult,
        int i = 0, f = 0;
        bool integer_part = true, negative = false;
 
+       if (fract_mult == 0) {
+               *fract = 0;
+
+               return kstrtoint(str, 0, integer);
+       }
+
        if (str[0] == '-') {
                negative = true;
                str++;
@@ -571,6 +577,9 @@ static ssize_t iio_write_channel_info(struct device *dev,
        if (indio_dev->info->write_raw_get_fmt)
                switch (indio_dev->info->write_raw_get_fmt(indio_dev,
                        this_attr->c, this_attr->address)) {
+               case IIO_VAL_INT:
+                       fract_mult = 0;
+                       break;
                case IIO_VAL_INT_PLUS_MICRO:
                        fract_mult = 100000;
                        break;
index 076bc46fad034fae0d2e9c99ae40ae0923987d09..e56937c40a189a8f076440c9e2f361755a81cbc8 100644 (file)
@@ -743,8 +743,10 @@ static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
 {
        int ret;
 
-       if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX)
+       if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) {
+               dev_err(&als->pdev->dev, "invalid resistor value\n");
                return -EINVAL;
+       };
 
        ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
        if (ret) {
index 45f7bde02bbf7fc78c7887f0b4a27adb078f035b..76a9e12b46bc45e50896b2abfb1513b577560667 100644 (file)
@@ -381,17 +381,23 @@ static int pa12203001_probe(struct i2c_client *client,
                return ret;
 
        ret = pm_runtime_set_active(&client->dev);
-       if (ret < 0) {
-               pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
-               return ret;
-       }
+       if (ret < 0)
+               goto out_err;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev,
                                         PA12203001_SLEEP_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
-       return iio_device_register(indio_dev);
+       ret = iio_device_register(indio_dev);
+       if (ret < 0)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE);
+       return ret;
 }
 
 static int pa12203001_remove(struct i2c_client *client)
index 4b75bb0998b3bb26a857084a1787821790a5e6c2..7de0f397194b0b858bfe229cb88d47a45d87b979 100644 (file)
@@ -507,34 +507,28 @@ static int rpr0521_probe(struct i2c_client *client,
                dev_err(&client->dev, "rpr0521 chip init failed\n");
                return ret;
        }
-       ret = iio_device_register(indio_dev);
-       if (ret < 0)
-               return ret;
 
        ret = pm_runtime_set_active(&client->dev);
        if (ret < 0)
-               goto err_iio_unregister;
+               return ret;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
-       return 0;
-
-err_iio_unregister:
-       iio_device_unregister(indio_dev);
-       return ret;
+       return iio_device_register(indio_dev);
 }
 
 static int rpr0521_remove(struct i2c_client *client)
 {
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
+       iio_device_unregister(indio_dev);
+
        pm_runtime_disable(&client->dev);
        pm_runtime_set_suspended(&client->dev);
        pm_runtime_put_noidle(&client->dev);
 
-       iio_device_unregister(indio_dev);
        rpr0521_poweroff(iio_priv(indio_dev));
 
        return 0;
index 1615b23d7b2a64019c474ac566b5713bf587e29b..ffcb75ea64fb0ae8dd0d8dda28387c72d279862e 100644 (file)
@@ -928,27 +928,24 @@ static int bmc150_magn_probe(struct i2c_client *client,
                goto err_free_irq;
        }
 
-       ret = iio_device_register(indio_dev);
-       if (ret < 0) {
-               dev_err(&client->dev, "unable to register iio device\n");
-               goto err_buffer_cleanup;
-       }
-
        ret = pm_runtime_set_active(&client->dev);
        if (ret)
-               goto err_iio_unregister;
+               goto err_buffer_cleanup;
 
        pm_runtime_enable(&client->dev);
        pm_runtime_set_autosuspend_delay(&client->dev,
                                         BMC150_MAGN_AUTO_SUSPEND_DELAY_MS);
        pm_runtime_use_autosuspend(&client->dev);
 
-       dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "unable to register iio device\n");
+               goto err_buffer_cleanup;
+       }
 
+       dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
        return 0;
 
-err_iio_unregister:
-       iio_device_unregister(indio_dev);
 err_buffer_cleanup:
        iio_triggered_buffer_cleanup(indio_dev);
 err_free_irq:
@@ -967,11 +964,12 @@ static int bmc150_magn_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
        struct bmc150_magn_data *data = 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);
 
-       iio_device_unregister(indio_dev);
        iio_triggered_buffer_cleanup(indio_dev);
 
        if (client->irq > 0)
index 961f9f990faffa67fccf54dfa01118ce4339f3b9..be8ccef735f8b45e1462d1838356932333a44932 100644 (file)
@@ -13,7 +13,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  * GNU General Public License for more details.
  *
- * TODO: runtime pm, interrupt mode, and signal strength reporting
+ * TODO: interrupt mode, and signal strength reporting
  */
 
 #include <linux/err.h>
@@ -21,6 +21,7 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/buffer.h>
@@ -37,6 +38,7 @@
 
 #define LIDAR_REG_DATA_HBYTE   0x0f
 #define LIDAR_REG_DATA_LBYTE   0x10
+#define LIDAR_REG_PWR_CONTROL  0x65
 
 #define LIDAR_DRV_NAME "lidar"
 
@@ -90,6 +92,12 @@ static inline int lidar_write_control(struct lidar_data *data, int val)
        return i2c_smbus_write_byte_data(data->client, LIDAR_REG_CONTROL, val);
 }
 
+static inline int lidar_write_power(struct lidar_data *data, int val)
+{
+       return i2c_smbus_write_byte_data(data->client,
+                                        LIDAR_REG_PWR_CONTROL, val);
+}
+
 static int lidar_read_measurement(struct lidar_data *data, u16 *reg)
 {
        int ret;
@@ -116,6 +124,8 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
        int tries = 10;
        int ret;
 
+       pm_runtime_get_sync(&client->dev);
+
        /* start sample */
        ret = lidar_write_control(data, LIDAR_REG_CONTROL_ACQUIRE);
        if (ret < 0) {
@@ -144,6 +154,8 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
                }
                ret = -EIO;
        }
+       pm_runtime_mark_last_busy(&client->dev);
+       pm_runtime_put_autosuspend(&client->dev);
 
        return ret;
 }
@@ -243,6 +255,17 @@ static int lidar_probe(struct i2c_client *client,
        if (ret)
                goto error_unreg_buffer;
 
+       pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+       pm_runtime_use_autosuspend(&client->dev);
+
+       ret = pm_runtime_set_active(&client->dev);
+       if (ret)
+               goto error_unreg_buffer;
+       pm_runtime_enable(&client->dev);
+
+       pm_runtime_mark_last_busy(&client->dev);
+       pm_runtime_idle(&client->dev);
+
        return 0;
 
 error_unreg_buffer:
@@ -258,6 +281,9 @@ static int lidar_remove(struct i2c_client *client)
        iio_device_unregister(indio_dev);
        iio_triggered_buffer_cleanup(indio_dev);
 
+       pm_runtime_disable(&client->dev);
+       pm_runtime_set_suspended(&client->dev);
+
        return 0;
 }
 
@@ -273,10 +299,38 @@ static const struct of_device_id lidar_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, lidar_dt_ids);
 
+#ifdef CONFIG_PM
+static int lidar_pm_runtime_suspend(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct lidar_data *data = iio_priv(indio_dev);
+
+       return lidar_write_power(data, 0x0f);
+}
+
+static int lidar_pm_runtime_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+       struct lidar_data *data = iio_priv(indio_dev);
+       int ret = lidar_write_power(data, 0);
+
+       /* regulator and FPGA needs settling time */
+       usleep_range(15000, 20000);
+
+       return ret;
+}
+#endif
+
+static const struct dev_pm_ops lidar_pm_ops = {
+       SET_RUNTIME_PM_OPS(lidar_pm_runtime_suspend,
+                          lidar_pm_runtime_resume, NULL)
+};
+
 static struct i2c_driver lidar_driver = {
        .driver = {
                .name   = LIDAR_DRV_NAME,
                .of_match_table = of_match_ptr(lidar_dt_ids),
+               .pm     = &lidar_pm_ops,
        },
        .probe          = lidar_probe,
        .remove         = lidar_remove,
index 9d7f0004d2d7b25bcd7e67b345aaa4f3ad407d32..0e044cb0def8a456440f2008d43dc89a7060f1a6 100644 (file)
@@ -17,33 +17,4 @@ source "drivers/staging/iio/meter/Kconfig"
 source "drivers/staging/iio/resolver/Kconfig"
 source "drivers/staging/iio/trigger/Kconfig"
 
-config IIO_DUMMY_EVGEN
-       tristate
-       select IRQ_WORK
-
-config IIO_SIMPLE_DUMMY
-       tristate "An example driver with no hardware requirements"
-       help
-        Driver intended mainly as documentation for how to write
-        a driver. May also be useful for testing userspace code
-        without hardware.
-
-if IIO_SIMPLE_DUMMY
-
-config IIO_SIMPLE_DUMMY_EVENTS
-       bool "Event generation support"
-       select IIO_DUMMY_EVGEN
-       help
-         Add some dummy events to the simple dummy driver.
-
-config IIO_SIMPLE_DUMMY_BUFFER
-       bool "Buffered capture support"
-       select IIO_BUFFER
-       select IIO_TRIGGER
-       select IIO_KFIFO_BUF
-       help
-         Add buffered data capture to the simple dummy driver.
-
-endif # IIO_SIMPLE_DUMMY
-
 endmenu
index d87106135b270133a50067a07f31f9459a8a6776..3e616b4437f54c5d1be0687e72953ed7c0499898 100644 (file)
@@ -2,13 +2,6 @@
 # Makefile for the industrial I/O core.
 #
 
-obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
-iio_dummy-y := iio_simple_dummy.o
-iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_EVENTS) += iio_simple_dummy_events.o
-iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
-
-obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
-
 obj-y += accel/
 obj-y += adc/
 obj-y += addac/
index 3abc7789237f7220945e3df0df0b9f837e7d0c88..1439cfdbb09c8981ada13d2b6aba213ac7dd9748 100644 (file)
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
 #include <linux/sched.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/iio/adc/ad_sigma_delta.h>
 
-#include "ad7780.h"
-
 #define AD7780_RDY     BIT(7)
 #define AD7780_FILTER  BIT(6)
 #define AD7780_ERR     BIT(5)
@@ -42,7 +40,7 @@ struct ad7780_chip_info {
 struct ad7780_state {
        const struct ad7780_chip_info   *chip_info;
        struct regulator                *reg;
-       int                             powerdown_gpio;
+       struct gpio_desc                *powerdown_gpio;
        unsigned int    gain;
        u16                             int_vref_mv;
 
@@ -77,8 +75,7 @@ static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta,
                break;
        }
 
-       if (gpio_is_valid(st->powerdown_gpio))
-               gpio_set_value(st->powerdown_gpio, val);
+       gpiod_set_value(st->powerdown_gpio, val);
 
        return 0;
 }
@@ -163,7 +160,6 @@ static const struct iio_info ad7780_info = {
 
 static int ad7780_probe(struct spi_device *spi)
 {
-       struct ad7780_platform_data *pdata = spi->dev.platform_data;
        struct ad7780_state *st;
        struct iio_dev *indio_dev;
        int ret, voltage_uv = 0;
@@ -189,12 +185,10 @@ static int ad7780_probe(struct spi_device *spi)
        st->chip_info =
                &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data];
 
-       if (pdata && pdata->vref_mv)
-               st->int_vref_mv = pdata->vref_mv;
-       else if (voltage_uv)
+       if (voltage_uv)
                st->int_vref_mv = voltage_uv / 1000;
        else
-               dev_warn(&spi->dev, "reference voltage unspecified\n");
+               dev_warn(&spi->dev, "Reference voltage unspecified\n");
 
        spi_set_drvdata(spi, indio_dev);
 
@@ -205,18 +199,14 @@ static int ad7780_probe(struct spi_device *spi)
        indio_dev->num_channels = 1;
        indio_dev->info = &ad7780_info;
 
-       if (pdata && gpio_is_valid(pdata->gpio_pdrst)) {
-               ret = devm_gpio_request_one(&spi->dev,
-                                           pdata->gpio_pdrst,
-                                           GPIOF_OUT_INIT_LOW,
-                                           "AD7780 /PDRST");
-               if (ret) {
-                       dev_err(&spi->dev, "failed to request GPIO PDRST\n");
-                       goto error_disable_reg;
-               }
-               st->powerdown_gpio = pdata->gpio_pdrst;
-       } else {
-               st->powerdown_gpio = -1;
+       st->powerdown_gpio = devm_gpiod_get_optional(&spi->dev,
+                                                    "powerdown",
+                                                    GPIOD_OUT_LOW);
+       if (IS_ERR(st->powerdown_gpio)) {
+               ret = PTR_ERR(st->powerdown_gpio);
+               dev_err(&spi->dev, "Failed to request powerdown GPIO: %d\n",
+                       ret);
+               goto error_disable_reg;
        }
 
        ret = ad_sd_setup_buffer_and_trigger(indio_dev);
diff --git a/drivers/staging/iio/adc/ad7780.h b/drivers/staging/iio/adc/ad7780.h
deleted file mode 100644 (file)
index 67e511c..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * AD7780/AD7781 SPI ADC driver
- *
- * Copyright 2011 Analog Devices Inc.
- *
- * Licensed under the GPL-2.
- */
-#ifndef IIO_ADC_AD7780_H_
-#define IIO_ADC_AD7780_H_
-
-/*
- * TODO: struct ad7780_platform_data needs to go into include/linux/iio
- */
-
-/* NOTE:
- * The AD7780 doesn't feature a dedicated SPI chip select, in addition it
- * features a dual use data out ready DOUT/RDY output.
- * In order to avoid contentions on the SPI bus, it's therefore necessary
- * to use spi bus locking combined with a dedicated GPIO to control the
- * power down reset signal of the AD7780.
- *
- * The DOUT/RDY output must also be wired to an interrupt capable GPIO.
- */
-
-struct ad7780_platform_data {
-       u16                             vref_mv;
-       int                             gpio_pdrst;
-};
-
-#endif /* IIO_ADC_AD7780_H_ */
index d997d9c74ca824740a825cc5399c12be5d491875..5f1375c465e614390ca6ebacca245122d2d4cf34 100644 (file)
@@ -324,7 +324,7 @@ struct mxs_lradc {
 #define        LRADC_DELAY_TRIGGER(x) \
                                (((x) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) & \
                                LRADC_DELAY_TRIGGER_LRADCS_MASK)
-#define        LRADC_DELAY_KICK                        (1 << 20)
+#define        LRADC_DELAY_KICK                        BIT(20)
 #define        LRADC_DELAY_TRIGGER_DELAYS_MASK         (0xf << 16)
 #define        LRADC_DELAY_TRIGGER_DELAYS_OFFSET       16
 #define        LRADC_DELAY_TRIGGER_DELAYS(x) \
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
deleted file mode 100644 (file)
index 9e83f34..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- *
- * Companion module to the iio simple dummy example driver.
- * The purpose of this is to generate 'fake' event interrupts thus
- * allowing that driver's code to be as close as possible to that of
- * a normal driver talking to hardware.  The approach used here
- * is not intended to be general and just happens to work for this
- * particular use case.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/sysfs.h>
-
-#include "iio_dummy_evgen.h"
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/irq_work.h>
-
-/* Fiddly bit of faking and irq without hardware */
-#define IIO_EVENTGEN_NO 10
-
-/**
- * struct iio_dummy_handle_irq - helper struct to simulate interrupt generation
- * @work: irq_work used to run handlers from hardirq context
- * @irq: fake irq line number to trigger an interrupt
- */
-struct iio_dummy_handle_irq {
-       struct irq_work work;
-       int irq;
-};
-
-/**
- * struct iio_dummy_evgen - evgen state
- * @chip: irq chip we are faking
- * @base: base of irq range
- * @enabled: mask of which irqs are enabled
- * @inuse: mask of which irqs are connected
- * @regs: irq regs we are faking
- * @lock: protect the evgen state
- * @handler: helper for a 'hardware-like' interrupt simulation
- */
-struct iio_dummy_eventgen {
-       struct irq_chip chip;
-       int base;
-       bool enabled[IIO_EVENTGEN_NO];
-       bool inuse[IIO_EVENTGEN_NO];
-       struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
-       struct mutex lock;
-       struct iio_dummy_handle_irq handler;
-};
-
-/* We can only ever have one instance of this 'device' */
-static struct iio_dummy_eventgen *iio_evgen;
-static const char *iio_evgen_name = "iio_dummy_evgen";
-
-static void iio_dummy_event_irqmask(struct irq_data *d)
-{
-       struct irq_chip *chip = irq_data_get_irq_chip(d);
-       struct iio_dummy_eventgen *evgen =
-               container_of(chip, struct iio_dummy_eventgen, chip);
-
-       evgen->enabled[d->irq - evgen->base] = false;
-}
-
-static void iio_dummy_event_irqunmask(struct irq_data *d)
-{
-       struct irq_chip *chip = irq_data_get_irq_chip(d);
-       struct iio_dummy_eventgen *evgen =
-               container_of(chip, struct iio_dummy_eventgen, chip);
-
-       evgen->enabled[d->irq - evgen->base] = true;
-}
-
-static void iio_dummy_work_handler(struct irq_work *work)
-{
-       struct iio_dummy_handle_irq *irq_handler;
-
-       irq_handler = container_of(work, struct iio_dummy_handle_irq, work);
-       handle_simple_irq(irq_to_desc(irq_handler->irq));
-}
-
-static int iio_dummy_evgen_create(void)
-{
-       int ret, i;
-
-       iio_evgen = kzalloc(sizeof(*iio_evgen), GFP_KERNEL);
-       if (!iio_evgen)
-               return -ENOMEM;
-
-       iio_evgen->base = irq_alloc_descs(-1, 0, IIO_EVENTGEN_NO, 0);
-       if (iio_evgen->base < 0) {
-               ret = iio_evgen->base;
-               kfree(iio_evgen);
-               return ret;
-       }
-       iio_evgen->chip.name = iio_evgen_name;
-       iio_evgen->chip.irq_mask = &iio_dummy_event_irqmask;
-       iio_evgen->chip.irq_unmask = &iio_dummy_event_irqunmask;
-       for (i = 0; i < IIO_EVENTGEN_NO; i++) {
-               irq_set_chip(iio_evgen->base + i, &iio_evgen->chip);
-               irq_set_handler(iio_evgen->base + i, &handle_simple_irq);
-               irq_modify_status(iio_evgen->base + i,
-                                 IRQ_NOREQUEST | IRQ_NOAUTOEN,
-                                 IRQ_NOPROBE);
-       }
-       init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
-       mutex_init(&iio_evgen->lock);
-       return 0;
-}
-
-/**
- * iio_dummy_evgen_get_irq() - get an evgen provided irq for a device
- *
- * This function will give a free allocated irq to a client device.
- * That irq can then be caused to 'fire' by using the associated sysfs file.
- */
-int iio_dummy_evgen_get_irq(void)
-{
-       int i, ret = 0;
-
-       if (!iio_evgen)
-               return -ENODEV;
-
-       mutex_lock(&iio_evgen->lock);
-       for (i = 0; i < IIO_EVENTGEN_NO; i++)
-               if (!iio_evgen->inuse[i]) {
-                       ret = iio_evgen->base + i;
-                       iio_evgen->inuse[i] = true;
-                       break;
-               }
-       mutex_unlock(&iio_evgen->lock);
-       if (i == IIO_EVENTGEN_NO)
-               return -ENOMEM;
-       return ret;
-}
-EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
-
-/**
- * iio_dummy_evgen_release_irq() - give the irq back.
- * @irq: irq being returned to the pool
- *
- * Used by client driver instances to give the irqs back when they disconnect
- */
-void iio_dummy_evgen_release_irq(int irq)
-{
-       mutex_lock(&iio_evgen->lock);
-       iio_evgen->inuse[irq - iio_evgen->base] = false;
-       mutex_unlock(&iio_evgen->lock);
-}
-EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
-
-struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq)
-{
-       return &iio_evgen->regs[irq - iio_evgen->base];
-}
-EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
-
-static void iio_dummy_evgen_free(void)
-{
-       irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
-       kfree(iio_evgen);
-}
-
-static void iio_evgen_release(struct device *dev)
-{
-       iio_dummy_evgen_free();
-}
-
-static ssize_t iio_evgen_poke(struct device *dev,
-                             struct device_attribute *attr,
-                             const char *buf,
-                             size_t len)
-{
-       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
-       unsigned long event;
-       int ret;
-
-       ret = kstrtoul(buf, 10, &event);
-       if (ret)
-               return ret;
-
-       iio_evgen->regs[this_attr->address].reg_id   = this_attr->address;
-       iio_evgen->regs[this_attr->address].reg_data = event;
-
-       iio_evgen->handler.irq = iio_evgen->base + this_attr->address;
-       if (iio_evgen->enabled[this_attr->address])
-               irq_work_queue(&iio_evgen->handler.work);
-
-       return len;
-}
-
-static IIO_DEVICE_ATTR(poke_ev0, S_IWUSR, NULL, &iio_evgen_poke, 0);
-static IIO_DEVICE_ATTR(poke_ev1, S_IWUSR, NULL, &iio_evgen_poke, 1);
-static IIO_DEVICE_ATTR(poke_ev2, S_IWUSR, NULL, &iio_evgen_poke, 2);
-static IIO_DEVICE_ATTR(poke_ev3, S_IWUSR, NULL, &iio_evgen_poke, 3);
-static IIO_DEVICE_ATTR(poke_ev4, S_IWUSR, NULL, &iio_evgen_poke, 4);
-static IIO_DEVICE_ATTR(poke_ev5, S_IWUSR, NULL, &iio_evgen_poke, 5);
-static IIO_DEVICE_ATTR(poke_ev6, S_IWUSR, NULL, &iio_evgen_poke, 6);
-static IIO_DEVICE_ATTR(poke_ev7, S_IWUSR, NULL, &iio_evgen_poke, 7);
-static IIO_DEVICE_ATTR(poke_ev8, S_IWUSR, NULL, &iio_evgen_poke, 8);
-static IIO_DEVICE_ATTR(poke_ev9, S_IWUSR, NULL, &iio_evgen_poke, 9);
-
-static struct attribute *iio_evgen_attrs[] = {
-       &iio_dev_attr_poke_ev0.dev_attr.attr,
-       &iio_dev_attr_poke_ev1.dev_attr.attr,
-       &iio_dev_attr_poke_ev2.dev_attr.attr,
-       &iio_dev_attr_poke_ev3.dev_attr.attr,
-       &iio_dev_attr_poke_ev4.dev_attr.attr,
-       &iio_dev_attr_poke_ev5.dev_attr.attr,
-       &iio_dev_attr_poke_ev6.dev_attr.attr,
-       &iio_dev_attr_poke_ev7.dev_attr.attr,
-       &iio_dev_attr_poke_ev8.dev_attr.attr,
-       &iio_dev_attr_poke_ev9.dev_attr.attr,
-       NULL,
-};
-
-static const struct attribute_group iio_evgen_group = {
-       .attrs = iio_evgen_attrs,
-};
-
-static const struct attribute_group *iio_evgen_groups[] = {
-       &iio_evgen_group,
-       NULL
-};
-
-static struct device iio_evgen_dev = {
-       .bus = &iio_bus_type,
-       .groups = iio_evgen_groups,
-       .release = &iio_evgen_release,
-};
-
-static __init int iio_dummy_evgen_init(void)
-{
-       int ret = iio_dummy_evgen_create();
-
-       if (ret < 0)
-               return ret;
-       device_initialize(&iio_evgen_dev);
-       dev_set_name(&iio_evgen_dev, "iio_evgen");
-       return device_add(&iio_evgen_dev);
-}
-module_init(iio_dummy_evgen_init);
-
-static __exit void iio_dummy_evgen_exit(void)
-{
-       device_unregister(&iio_evgen_dev);
-}
-module_exit(iio_dummy_evgen_exit);
-
-MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
-MODULE_DESCRIPTION("IIO dummy driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_dummy_evgen.h b/drivers/staging/iio/iio_dummy_evgen.h
deleted file mode 100644 (file)
index d044b94..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _IIO_DUMMY_EVGEN_H_
-#define _IIO_DUMMY_EVGEN_H_
-
-struct iio_dummy_regs {
-       u32 reg_id;
-       u32 reg_data;
-};
-
-struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq);
-int iio_dummy_evgen_get_irq(void);
-void iio_dummy_evgen_release_irq(int irq);
-
-#endif /* _IIO_DUMMY_EVGEN_H_ */
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
deleted file mode 100644 (file)
index 43fe4ba..0000000
+++ /dev/null
@@ -1,747 +0,0 @@
-/**
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- *
- * A reference industrial I/O driver to illustrate the functionality available.
- *
- * There are numerous real drivers to illustrate the finer points.
- * The purpose of this driver is to provide a driver with far more comments
- * and explanatory notes than any 'real' driver would have.
- * Anyone starting out writing an IIO driver should first make sure they
- * understand all of this driver except those bits specifically marked
- * as being present to allow us to 'fake' the presence of hardware.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include <linux/iio/buffer.h>
-#include "iio_simple_dummy.h"
-
-/*
- * A few elements needed to fake a bus for this driver
- * Note instances parameter controls how many of these
- * dummy devices are registered.
- */
-static unsigned instances = 1;
-module_param(instances, uint, 0);
-
-/* Pointer array used to fake bus elements */
-static struct iio_dev **iio_dummy_devs;
-
-/* Fake a name for the part number, usually obtained from the id table */
-static const char *iio_dummy_part_number = "iio_dummy_part_no";
-
-/**
- * struct iio_dummy_accel_calibscale - realworld to register mapping
- * @val: first value in read_raw - here integer part.
- * @val2: second value in read_raw etc - here micro part.
- * @regval: register value - magic device specific numbers.
- */
-struct iio_dummy_accel_calibscale {
-       int val;
-       int val2;
-       int regval; /* what would be written to hardware */
-};
-
-static const struct iio_dummy_accel_calibscale dummy_scales[] = {
-       { 0, 100, 0x8 }, /* 0.000100 */
-       { 0, 133, 0x7 }, /* 0.000133 */
-       { 733, 13, 0x9 }, /* 733.000013 */
-};
-
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-
-/*
- * simple event - triggered when value rises above
- * a threshold
- */
-static const struct iio_event_spec iio_dummy_event = {
-       .type = IIO_EV_TYPE_THRESH,
-       .dir = IIO_EV_DIR_RISING,
-       .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
-};
-
-/*
- * simple step detect event - triggered when a step is detected
- */
-static const struct iio_event_spec step_detect_event = {
-       .type = IIO_EV_TYPE_CHANGE,
-       .dir = IIO_EV_DIR_NONE,
-       .mask_separate = BIT(IIO_EV_INFO_ENABLE),
-};
-
-/*
- * simple transition event - triggered when the reported running confidence
- * value rises above a threshold value
- */
-static const struct iio_event_spec iio_running_event = {
-       .type = IIO_EV_TYPE_THRESH,
-       .dir = IIO_EV_DIR_RISING,
-       .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
-};
-
-/*
- * simple transition event - triggered when the reported walking confidence
- * value falls under a threshold value
- */
-static const struct iio_event_spec iio_walking_event = {
-       .type = IIO_EV_TYPE_THRESH,
-       .dir = IIO_EV_DIR_FALLING,
-       .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
-};
-#endif
-
-/*
- * iio_dummy_channels - Description of available channels
- *
- * This array of structures tells the IIO core about what the device
- * actually provides for a given channel.
- */
-static const struct iio_chan_spec iio_dummy_channels[] = {
-       /* indexed ADC channel in_voltage0_raw etc */
-       {
-               .type = IIO_VOLTAGE,
-               /* Channel has a numeric index of 0 */
-               .indexed = 1,
-               .channel = 0,
-               /* What other information is available? */
-               .info_mask_separate =
-               /*
-                * in_voltage0_raw
-                * Raw (unscaled no bias removal etc) measurement
-                * from the device.
-                */
-               BIT(IIO_CHAN_INFO_RAW) |
-               /*
-                * in_voltage0_offset
-                * Offset for userspace to apply prior to scale
-                * when converting to standard units (microvolts)
-                */
-               BIT(IIO_CHAN_INFO_OFFSET) |
-               /*
-                * in_voltage0_scale
-                * Multipler for userspace to apply post offset
-                * when converting to standard units (microvolts)
-                */
-               BIT(IIO_CHAN_INFO_SCALE),
-               /*
-                * sampling_frequency
-                * The frequency in Hz at which the channels are sampled
-                */
-               .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
-               /* The ordering of elements in the buffer via an enum */
-               .scan_index = DUMMY_INDEX_VOLTAGE_0,
-               .scan_type = { /* Description of storage in buffer */
-                       .sign = 'u', /* unsigned */
-                       .realbits = 13, /* 13 bits */
-                       .storagebits = 16, /* 16 bits used for storage */
-                       .shift = 0, /* zero shift */
-               },
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-               .event_spec = &iio_dummy_event,
-               .num_event_specs = 1,
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
-       },
-       /* Differential ADC channel in_voltage1-voltage2_raw etc*/
-       {
-               .type = IIO_VOLTAGE,
-               .differential = 1,
-               /*
-                * Indexing for differential channels uses channel
-                * for the positive part, channel2 for the negative.
-                */
-               .indexed = 1,
-               .channel = 1,
-               .channel2 = 2,
-               /*
-                * in_voltage1-voltage2_raw
-                * Raw (unscaled no bias removal etc) measurement
-                * from the device.
-                */
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-               /*
-                * in_voltage-voltage_scale
-                * Shared version of scale - shared by differential
-                * input channels of type IIO_VOLTAGE.
-                */
-               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
-               /*
-                * sampling_frequency
-                * The frequency in Hz at which the channels are sampled
-                */
-               .scan_index = DUMMY_INDEX_DIFFVOLTAGE_1M2,
-               .scan_type = { /* Description of storage in buffer */
-                       .sign = 's', /* signed */
-                       .realbits = 12, /* 12 bits */
-                       .storagebits = 16, /* 16 bits used for storage */
-                       .shift = 0, /* zero shift */
-               },
-       },
-       /* Differential ADC channel in_voltage3-voltage4_raw etc*/
-       {
-               .type = IIO_VOLTAGE,
-               .differential = 1,
-               .indexed = 1,
-               .channel = 3,
-               .channel2 = 4,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
-               .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
-               .scan_index = DUMMY_INDEX_DIFFVOLTAGE_3M4,
-               .scan_type = {
-                       .sign = 's',
-                       .realbits = 11,
-                       .storagebits = 16,
-                       .shift = 0,
-               },
-       },
-       /*
-        * 'modified' (i.e. axis specified) acceleration channel
-        * in_accel_z_raw
-        */
-       {
-               .type = IIO_ACCEL,
-               .modified = 1,
-               /* Channel 2 is use for modifiers */
-               .channel2 = IIO_MOD_X,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-               /*
-                * Internal bias and gain correction values. Applied
-                * by the hardware or driver prior to userspace
-                * seeing the readings. Typically part of hardware
-                * calibration.
-                */
-               BIT(IIO_CHAN_INFO_CALIBSCALE) |
-               BIT(IIO_CHAN_INFO_CALIBBIAS),
-               .info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ),
-               .scan_index = DUMMY_INDEX_ACCELX,
-               .scan_type = { /* Description of storage in buffer */
-                       .sign = 's', /* signed */
-                       .realbits = 16, /* 16 bits */
-                       .storagebits = 16, /* 16 bits used for storage */
-                       .shift = 0, /* zero shift */
-               },
-       },
-       /*
-        * Convenience macro for timestamps. 4 is the index in
-        * the buffer.
-        */
-       IIO_CHAN_SOFT_TIMESTAMP(4),
-       /* DAC channel out_voltage0_raw */
-       {
-               .type = IIO_VOLTAGE,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
-               .scan_index = -1, /* No buffer support */
-               .output = 1,
-               .indexed = 1,
-               .channel = 0,
-       },
-       {
-               .type = IIO_STEPS,
-               .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_ENABLE) |
-                       BIT(IIO_CHAN_INFO_CALIBHEIGHT),
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
-               .scan_index = -1, /* No buffer support */
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-               .event_spec = &step_detect_event,
-               .num_event_specs = 1,
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
-       },
-       {
-               .type = IIO_ACTIVITY,
-               .modified = 1,
-               .channel2 = IIO_MOD_RUNNING,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
-               .scan_index = -1, /* No buffer support */
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-               .event_spec = &iio_running_event,
-               .num_event_specs = 1,
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
-       },
-       {
-               .type = IIO_ACTIVITY,
-               .modified = 1,
-               .channel2 = IIO_MOD_WALKING,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
-               .scan_index = -1, /* No buffer support */
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-               .event_spec = &iio_walking_event,
-               .num_event_specs = 1,
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
-       },
-};
-
-/**
- * iio_dummy_read_raw() - data read function.
- * @indio_dev: the struct iio_dev associated with this device instance
- * @chan:      the channel whose data is to be read
- * @val:       first element of returned value (typically INT)
- * @val2:      second element of returned value (typically MICRO)
- * @mask:      what we actually want to read as per the info_mask_*
- *             in iio_chan_spec.
- */
-static int iio_dummy_read_raw(struct iio_dev *indio_dev,
-                             struct iio_chan_spec const *chan,
-                             int *val,
-                             int *val2,
-                             long mask)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-       int ret = -EINVAL;
-
-       mutex_lock(&st->lock);
-       switch (mask) {
-       case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       if (chan->output) {
-                               /* Set integer part to cached value */
-                               *val = st->dac_val;
-                               ret = IIO_VAL_INT;
-                       } else if (chan->differential) {
-                               if (chan->channel == 1)
-                                       *val = st->differential_adc_val[0];
-                               else
-                                       *val = st->differential_adc_val[1];
-                               ret = IIO_VAL_INT;
-                       } else {
-                               *val = st->single_ended_adc_val;
-                               ret = IIO_VAL_INT;
-                       }
-                       break;
-               case IIO_ACCEL:
-                       *val = st->accel_val;
-                       ret = IIO_VAL_INT;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case IIO_CHAN_INFO_PROCESSED:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       *val = st->steps;
-                       ret = IIO_VAL_INT;
-                       break;
-               case IIO_ACTIVITY:
-                       switch (chan->channel2) {
-                       case IIO_MOD_RUNNING:
-                               *val = st->activity_running;
-                               ret = IIO_VAL_INT;
-                               break;
-                       case IIO_MOD_WALKING:
-                               *val = st->activity_walking;
-                               ret = IIO_VAL_INT;
-                               break;
-                       default:
-                               break;
-                       }
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case IIO_CHAN_INFO_OFFSET:
-               /* only single ended adc -> 7 */
-               *val = 7;
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_SCALE:
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       switch (chan->differential) {
-                       case 0:
-                               /* only single ended adc -> 0.001333 */
-                               *val = 0;
-                               *val2 = 1333;
-                               ret = IIO_VAL_INT_PLUS_MICRO;
-                               break;
-                       case 1:
-                               /* all differential adc -> 0.000001344 */
-                               *val = 0;
-                               *val2 = 1344;
-                               ret = IIO_VAL_INT_PLUS_NANO;
-                       }
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case IIO_CHAN_INFO_CALIBBIAS:
-               /* only the acceleration axis - read from cache */
-               *val = st->accel_calibbias;
-               ret = IIO_VAL_INT;
-               break;
-       case IIO_CHAN_INFO_CALIBSCALE:
-               *val = st->accel_calibscale->val;
-               *val2 = st->accel_calibscale->val2;
-               ret = IIO_VAL_INT_PLUS_MICRO;
-               break;
-       case IIO_CHAN_INFO_SAMP_FREQ:
-               *val = 3;
-               *val2 = 33;
-               ret = IIO_VAL_INT_PLUS_NANO;
-               break;
-       case IIO_CHAN_INFO_ENABLE:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       *val = st->steps_enabled;
-                       ret = IIO_VAL_INT;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case IIO_CHAN_INFO_CALIBHEIGHT:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       *val = st->height;
-                       ret = IIO_VAL_INT;
-                       break;
-               default:
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-       mutex_unlock(&st->lock);
-       return ret;
-}
-
-/**
- * iio_dummy_write_raw() - data write function.
- * @indio_dev: the struct iio_dev associated with this device instance
- * @chan:      the channel whose data is to be written
- * @val:       first element of value to set (typically INT)
- * @val2:      second element of value to set (typically MICRO)
- * @mask:      what we actually want to write as per the info_mask_*
- *             in iio_chan_spec.
- *
- * Note that all raw writes are assumed IIO_VAL_INT and info mask elements
- * are assumed to be IIO_INT_PLUS_MICRO unless the callback write_raw_get_fmt
- * in struct iio_info is provided by the driver.
- */
-static int iio_dummy_write_raw(struct iio_dev *indio_dev,
-                              struct iio_chan_spec const *chan,
-                              int val,
-                              int val2,
-                              long mask)
-{
-       int i;
-       int ret = 0;
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       switch (mask) {
-       case IIO_CHAN_INFO_RAW:
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       if (chan->output == 0)
-                               return -EINVAL;
-
-                       /* Locking not required as writing single value */
-                       mutex_lock(&st->lock);
-                       st->dac_val = val;
-                       mutex_unlock(&st->lock);
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-       case IIO_CHAN_INFO_PROCESSED:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       mutex_lock(&st->lock);
-                       st->steps = val;
-                       mutex_unlock(&st->lock);
-                       return 0;
-               case IIO_ACTIVITY:
-                       if (val < 0)
-                               val = 0;
-                       if (val > 100)
-                               val = 100;
-                       switch (chan->channel2) {
-                       case IIO_MOD_RUNNING:
-                               st->activity_running = val;
-                               return 0;
-                       case IIO_MOD_WALKING:
-                               st->activity_walking = val;
-                               return 0;
-                       default:
-                               return -EINVAL;
-                       }
-                       break;
-               default:
-                       return -EINVAL;
-               }
-       case IIO_CHAN_INFO_CALIBSCALE:
-               mutex_lock(&st->lock);
-               /* Compare against table - hard matching here */
-               for (i = 0; i < ARRAY_SIZE(dummy_scales); i++)
-                       if (val == dummy_scales[i].val &&
-                           val2 == dummy_scales[i].val2)
-                               break;
-               if (i == ARRAY_SIZE(dummy_scales))
-                       ret = -EINVAL;
-               else
-                       st->accel_calibscale = &dummy_scales[i];
-               mutex_unlock(&st->lock);
-               return ret;
-       case IIO_CHAN_INFO_CALIBBIAS:
-               mutex_lock(&st->lock);
-               st->accel_calibbias = val;
-               mutex_unlock(&st->lock);
-               return 0;
-       case IIO_CHAN_INFO_ENABLE:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       mutex_lock(&st->lock);
-                       st->steps_enabled = val;
-                       mutex_unlock(&st->lock);
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-       case IIO_CHAN_INFO_CALIBHEIGHT:
-               switch (chan->type) {
-               case IIO_STEPS:
-                       st->height = val;
-                       return 0;
-               default:
-                       return -EINVAL;
-               }
-
-       default:
-               return -EINVAL;
-       }
-}
-
-/*
- * Device type specific information.
- */
-static const struct iio_info iio_dummy_info = {
-       .driver_module = THIS_MODULE,
-       .read_raw = &iio_dummy_read_raw,
-       .write_raw = &iio_dummy_write_raw,
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-       .read_event_config = &iio_simple_dummy_read_event_config,
-       .write_event_config = &iio_simple_dummy_write_event_config,
-       .read_event_value = &iio_simple_dummy_read_event_value,
-       .write_event_value = &iio_simple_dummy_write_event_value,
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
-};
-
-/**
- * iio_dummy_init_device() - device instance specific init
- * @indio_dev: the iio device structure
- *
- * Most drivers have one of these to set up default values,
- * reset the device to known state etc.
- */
-static int iio_dummy_init_device(struct iio_dev *indio_dev)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       st->dac_val = 0;
-       st->single_ended_adc_val = 73;
-       st->differential_adc_val[0] = 33;
-       st->differential_adc_val[1] = -34;
-       st->accel_val = 34;
-       st->accel_calibbias = -7;
-       st->accel_calibscale = &dummy_scales[0];
-       st->steps = 47;
-       st->activity_running = 98;
-       st->activity_walking = 4;
-
-       return 0;
-}
-
-/**
- * iio_dummy_probe() - device instance probe
- * @index: an id number for this instance.
- *
- * Arguments are bus type specific.
- * I2C: iio_dummy_probe(struct i2c_client *client,
- *                      const struct i2c_device_id *id)
- * SPI: iio_dummy_probe(struct spi_device *spi)
- */
-static int iio_dummy_probe(int index)
-{
-       int ret;
-       struct iio_dev *indio_dev;
-       struct iio_dummy_state *st;
-
-       /*
-        * Allocate an IIO device.
-        *
-        * This structure contains all generic state
-        * information about the device instance.
-        * It also has a region (accessed by iio_priv()
-        * for chip specific state information.
-        */
-       indio_dev = iio_device_alloc(sizeof(*st));
-       if (!indio_dev) {
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-
-       st = iio_priv(indio_dev);
-       mutex_init(&st->lock);
-
-       iio_dummy_init_device(indio_dev);
-       /*
-        * With hardware: Set the parent device.
-        * indio_dev->dev.parent = &spi->dev;
-        * indio_dev->dev.parent = &client->dev;
-        */
-
-        /*
-        * Make the iio_dev struct available to remove function.
-        * Bus equivalents
-        * i2c_set_clientdata(client, indio_dev);
-        * spi_set_drvdata(spi, indio_dev);
-        */
-       iio_dummy_devs[index] = indio_dev;
-
-       /*
-        * Set the device name.
-        *
-        * This is typically a part number and obtained from the module
-        * id table.
-        * e.g. for i2c and spi:
-        *    indio_dev->name = id->name;
-        *    indio_dev->name = spi_get_device_id(spi)->name;
-        */
-       indio_dev->name = iio_dummy_part_number;
-
-       /* Provide description of available channels */
-       indio_dev->channels = iio_dummy_channels;
-       indio_dev->num_channels = ARRAY_SIZE(iio_dummy_channels);
-
-       /*
-        * Provide device type specific interface functions and
-        * constant data.
-        */
-       indio_dev->info = &iio_dummy_info;
-
-       /* Specify that device provides sysfs type interfaces */
-       indio_dev->modes = INDIO_DIRECT_MODE;
-
-       ret = iio_simple_dummy_events_register(indio_dev);
-       if (ret < 0)
-               goto error_free_device;
-
-       ret = iio_simple_dummy_configure_buffer(indio_dev);
-       if (ret < 0)
-               goto error_unregister_events;
-
-       ret = iio_device_register(indio_dev);
-       if (ret < 0)
-               goto error_unconfigure_buffer;
-
-       return 0;
-error_unconfigure_buffer:
-       iio_simple_dummy_unconfigure_buffer(indio_dev);
-error_unregister_events:
-       iio_simple_dummy_events_unregister(indio_dev);
-error_free_device:
-       iio_device_free(indio_dev);
-error_ret:
-       return ret;
-}
-
-/**
- * iio_dummy_remove() - device instance removal function
- * @index: device index.
- *
- * Parameters follow those of iio_dummy_probe for buses.
- */
-static void iio_dummy_remove(int index)
-{
-       /*
-        * Get a pointer to the device instance iio_dev structure
-        * from the bus subsystem. E.g.
-        * struct iio_dev *indio_dev = i2c_get_clientdata(client);
-        * struct iio_dev *indio_dev = spi_get_drvdata(spi);
-        */
-       struct iio_dev *indio_dev = iio_dummy_devs[index];
-
-       /* Unregister the device */
-       iio_device_unregister(indio_dev);
-
-       /* Device specific code to power down etc */
-
-       /* Buffered capture related cleanup */
-       iio_simple_dummy_unconfigure_buffer(indio_dev);
-
-       iio_simple_dummy_events_unregister(indio_dev);
-
-       /* Free all structures */
-       iio_device_free(indio_dev);
-}
-
-/**
- * iio_dummy_init() -  device driver registration
- *
- * Varies depending on bus type of the device. As there is no device
- * here, call probe directly. For information on device registration
- * i2c:
- * Documentation/i2c/writing-clients
- * spi:
- * Documentation/spi/spi-summary
- */
-static __init int iio_dummy_init(void)
-{
-       int i, ret;
-
-       if (instances > 10) {
-               instances = 1;
-               return -EINVAL;
-       }
-
-       /* Fake a bus */
-       iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs),
-                                GFP_KERNEL);
-       /* Here we have no actual device so call probe */
-       for (i = 0; i < instances; i++) {
-               ret = iio_dummy_probe(i);
-               if (ret < 0)
-                       goto error_remove_devs;
-       }
-       return 0;
-
-error_remove_devs:
-       while (i--)
-               iio_dummy_remove(i);
-
-       kfree(iio_dummy_devs);
-       return ret;
-}
-module_init(iio_dummy_init);
-
-/**
- * iio_dummy_exit() - device driver removal
- *
- * Varies depending on bus type of the device.
- * As there is no device here, call remove directly.
- */
-static __exit void iio_dummy_exit(void)
-{
-       int i;
-
-       for (i = 0; i < instances; i++)
-               iio_dummy_remove(i);
-       kfree(iio_dummy_devs);
-}
-module_exit(iio_dummy_exit);
-
-MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
-MODULE_DESCRIPTION("IIO dummy driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h
deleted file mode 100644 (file)
index b9069a1..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- *
- * Join together the various functionality of iio_simple_dummy driver
- */
-
-#ifndef _IIO_SIMPLE_DUMMY_H_
-#define _IIO_SIMPLE_DUMMY_H_
-#include <linux/kernel.h>
-
-struct iio_dummy_accel_calibscale;
-struct iio_dummy_regs;
-
-/**
- * struct iio_dummy_state - device instance specific state.
- * @dac_val:                   cache for dac value
- * @single_ended_adc_val:      cache for single ended adc value
- * @differential_adc_val:      cache for differential adc value
- * @accel_val:                 cache for acceleration value
- * @accel_calibbias:           cache for acceleration calibbias
- * @accel_calibscale:          cache for acceleration calibscale
- * @lock:                      lock to ensure state is consistent
- * @event_irq:                 irq number for event line (faked)
- * @event_val:                 cache for event threshold value
- * @event_en:                  cache of whether event is enabled
- */
-struct iio_dummy_state {
-       int dac_val;
-       int single_ended_adc_val;
-       int differential_adc_val[2];
-       int accel_val;
-       int accel_calibbias;
-       int activity_running;
-       int activity_walking;
-       const struct iio_dummy_accel_calibscale *accel_calibscale;
-       struct mutex lock;
-       struct iio_dummy_regs *regs;
-       int steps_enabled;
-       int steps;
-       int height;
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-       int event_irq;
-       int event_val;
-       bool event_en;
-       s64 event_timestamp;
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
-};
-
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
-
-struct iio_dev;
-
-int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
-                                      const struct iio_chan_spec *chan,
-                                      enum iio_event_type type,
-                                      enum iio_event_direction dir);
-
-int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
-                                       const struct iio_chan_spec *chan,
-                                       enum iio_event_type type,
-                                       enum iio_event_direction dir,
-                                       int state);
-
-int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
-                                     const struct iio_chan_spec *chan,
-                                     enum iio_event_type type,
-                                     enum iio_event_direction dir,
-                                     enum iio_event_info info, int *val,
-                                     int *val2);
-
-int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
-                                      const struct iio_chan_spec *chan,
-                                      enum iio_event_type type,
-                                      enum iio_event_direction dir,
-                                      enum iio_event_info info, int val,
-                                      int val2);
-
-int iio_simple_dummy_events_register(struct iio_dev *indio_dev);
-void iio_simple_dummy_events_unregister(struct iio_dev *indio_dev);
-
-#else /* Stubs for when events are disabled at compile time */
-
-static inline int
-iio_simple_dummy_events_register(struct iio_dev *indio_dev)
-{
-       return 0;
-};
-
-static inline void
-iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
-{ };
-
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS*/
-
-/**
- * enum iio_simple_dummy_scan_elements - scan index enum
- * @DUMMY_INDEX_VOLTAGE_0:         the single ended voltage channel
- * @DUMMY_INDEX_DIFFVOLTAGE_1M2:   first differential channel
- * @DUMMY_INDEX_DIFFVOLTAGE_3M4:   second differential channel
- * @DUMMY_INDEX_ACCELX:            acceleration channel
- *
- * Enum provides convenient numbering for the scan index.
- */
-enum iio_simple_dummy_scan_elements {
-       DUMMY_INDEX_VOLTAGE_0,
-       DUMMY_INDEX_DIFFVOLTAGE_1M2,
-       DUMMY_INDEX_DIFFVOLTAGE_3M4,
-       DUMMY_INDEX_ACCELX,
-};
-
-#ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
-void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
-#else
-static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
-{
-       return 0;
-};
-
-static inline
-void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
-{};
-
-#endif /* CONFIG_IIO_SIMPLE_DUMMY_BUFFER */
-#endif /* _IIO_SIMPLE_DUMMY_H_ */
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
deleted file mode 100644 (file)
index cf44a6f..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- *
- * Buffer handling elements of industrial I/O reference driver.
- * Uses the kfifo buffer.
- *
- * To test without hardware use the sysfs trigger.
- */
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/bitmap.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/trigger_consumer.h>
-#include <linux/iio/kfifo_buf.h>
-
-#include "iio_simple_dummy.h"
-
-/* Some fake data */
-
-static const s16 fakedata[] = {
-       [DUMMY_INDEX_VOLTAGE_0] = 7,
-       [DUMMY_INDEX_DIFFVOLTAGE_1M2] = -33,
-       [DUMMY_INDEX_DIFFVOLTAGE_3M4] = -2,
-       [DUMMY_INDEX_ACCELX] = 344,
-};
-
-/**
- * iio_simple_dummy_trigger_h() - the trigger handler function
- * @irq: the interrupt number
- * @p: private data - always a pointer to the poll func.
- *
- * This is the guts of buffered capture. On a trigger event occurring,
- * if the pollfunc is attached then this handler is called as a threaded
- * interrupt (and hence may sleep). It is responsible for grabbing data
- * from the device and pushing it into the associated buffer.
- */
-static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
-{
-       struct iio_poll_func *pf = p;
-       struct iio_dev *indio_dev = pf->indio_dev;
-       int len = 0;
-       u16 *data;
-
-       data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
-       if (!data)
-               goto done;
-
-       if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) {
-               /*
-                * Three common options here:
-                * hardware scans: certain combinations of channels make
-                *   up a fast read.  The capture will consist of all of them.
-                *   Hence we just call the grab data function and fill the
-                *   buffer without processing.
-                * software scans: can be considered to be random access
-                *   so efficient reading is just a case of minimal bus
-                *   transactions.
-                * software culled hardware scans:
-                *   occasionally a driver may process the nearest hardware
-                *   scan to avoid storing elements that are not desired. This
-                *   is the fiddliest option by far.
-                * Here let's pretend we have random access. And the values are
-                * in the constant table fakedata.
-                */
-               int i, j;
-
-               for (i = 0, j = 0;
-                    i < bitmap_weight(indio_dev->active_scan_mask,
-                                      indio_dev->masklength);
-                    i++, j++) {
-                       j = find_next_bit(indio_dev->active_scan_mask,
-                                         indio_dev->masklength, j);
-                       /* random access read from the 'device' */
-                       data[i] = fakedata[j];
-                       len += 2;
-               }
-       }
-
-       iio_push_to_buffers_with_timestamp(indio_dev, data, iio_get_time_ns());
-
-       kfree(data);
-
-done:
-       /*
-        * Tell the core we are done with this trigger and ready for the
-        * next one.
-        */
-       iio_trigger_notify_done(indio_dev->trig);
-
-       return IRQ_HANDLED;
-}
-
-static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
-       /*
-        * iio_triggered_buffer_postenable:
-        * Generic function that simply attaches the pollfunc to the trigger.
-        * Replace this to mess with hardware state before we attach the
-        * trigger.
-        */
-       .postenable = &iio_triggered_buffer_postenable,
-       /*
-        * iio_triggered_buffer_predisable:
-        * Generic function that simple detaches the pollfunc from the trigger.
-        * Replace this to put hardware state back again after the trigger is
-        * detached but before userspace knows we have disabled the ring.
-        */
-       .predisable = &iio_triggered_buffer_predisable,
-};
-
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
-{
-       int ret;
-       struct iio_buffer *buffer;
-
-       /* Allocate a buffer to use - here a kfifo */
-       buffer = iio_kfifo_allocate();
-       if (!buffer) {
-               ret = -ENOMEM;
-               goto error_ret;
-       }
-
-       iio_device_attach_buffer(indio_dev, buffer);
-
-       /* Enable timestamps by default */
-       buffer->scan_timestamp = true;
-
-       /*
-        * Tell the core what device type specific functions should
-        * be run on either side of buffer capture enable / disable.
-        */
-       indio_dev->setup_ops = &iio_simple_dummy_buffer_setup_ops;
-
-       /*
-        * Configure a polling function.
-        * When a trigger event with this polling function connected
-        * occurs, this function is run. Typically this grabs data
-        * from the device.
-        *
-        * NULL for the bottom half. This is normally implemented only if we
-        * either want to ping a capture now pin (no sleeping) or grab
-        * a timestamp as close as possible to a data ready trigger firing.
-        *
-        * IRQF_ONESHOT ensures irqs are masked such that only one instance
-        * of the handler can run at a time.
-        *
-        * "iio_simple_dummy_consumer%d" formatting string for the irq 'name'
-        * as seen under /proc/interrupts. Remaining parameters as per printk.
-        */
-       indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
-                                                &iio_simple_dummy_trigger_h,
-                                                IRQF_ONESHOT,
-                                                indio_dev,
-                                                "iio_simple_dummy_consumer%d",
-                                                indio_dev->id);
-
-       if (!indio_dev->pollfunc) {
-               ret = -ENOMEM;
-               goto error_free_buffer;
-       }
-
-       /*
-        * Notify the core that this device is capable of buffered capture
-        * driven by a trigger.
-        */
-       indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-
-       return 0;
-
-error_free_buffer:
-       iio_kfifo_free(indio_dev->buffer);
-error_ret:
-       return ret;
-}
-
-/**
- * iio_simple_dummy_unconfigure_buffer() - release buffer resources
- * @indo_dev: device instance state
- */
-void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
-{
-       iio_dealloc_pollfunc(indio_dev->pollfunc);
-       iio_kfifo_free(indio_dev->buffer);
-}
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
deleted file mode 100644 (file)
index bfbf1c5..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/**
- * Copyright (c) 2011 Jonathan Cameron
- *
- * 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.
- *
- * Event handling elements of industrial I/O reference driver.
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
-#include <linux/iio/events.h>
-#include "iio_simple_dummy.h"
-
-/* Evgen 'fakes' interrupt events for this example */
-#include "iio_dummy_evgen.h"
-
-/**
- * iio_simple_dummy_read_event_config() - is event enabled?
- * @indio_dev: the device instance data
- * @chan: channel for the event whose state is being queried
- * @type: type of the event whose state is being queried
- * @dir: direction of the vent whose state is being queried
- *
- * This function would normally query the relevant registers or a cache to
- * discover if the event generation is enabled on the device.
- */
-int iio_simple_dummy_read_event_config(struct iio_dev *indio_dev,
-                                      const struct iio_chan_spec *chan,
-                                      enum iio_event_type type,
-                                      enum iio_event_direction dir)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       return st->event_en;
-}
-
-/**
- * iio_simple_dummy_write_event_config() - set whether event is enabled
- * @indio_dev: the device instance data
- * @chan: channel for the event whose state is being set
- * @type: type of the event whose state is being set
- * @dir: direction of the vent whose state is being set
- * @state: whether to enable or disable the device.
- *
- * This function would normally set the relevant registers on the devices
- * so that it generates the specified event. Here it just sets up a cached
- * value.
- */
-int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
-                                       const struct iio_chan_spec *chan,
-                                       enum iio_event_type type,
-                                       enum iio_event_direction dir,
-                                       int state)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       /*
-        *  Deliberately over the top code splitting to illustrate
-        * how this is done when multiple events exist.
-        */
-       switch (chan->type) {
-       case IIO_VOLTAGE:
-               switch (type) {
-               case IIO_EV_TYPE_THRESH:
-                       if (dir == IIO_EV_DIR_RISING)
-                               st->event_en = state;
-                       else
-                               return -EINVAL;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case IIO_ACTIVITY:
-               switch (type) {
-               case IIO_EV_TYPE_THRESH:
-                       st->event_en = state;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       case IIO_STEPS:
-               switch (type) {
-               case IIO_EV_TYPE_CHANGE:
-                       st->event_en = state;
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/**
- * iio_simple_dummy_read_event_value() - get value associated with event
- * @indio_dev: device instance specific data
- * @chan: channel for the event whose value is being read
- * @type: type of the event whose value is being read
- * @dir: direction of the vent whose value is being read
- * @info: info type of the event whose value is being read
- * @val: value for the event code.
- *
- * Many devices provide a large set of events of which only a subset may
- * be enabled at a time, with value registers whose meaning changes depending
- * on the event enabled. This often means that the driver must cache the values
- * associated with each possible events so that the right value is in place when
- * the enabled event is changed.
- */
-int iio_simple_dummy_read_event_value(struct iio_dev *indio_dev,
-                                     const struct iio_chan_spec *chan,
-                                     enum iio_event_type type,
-                                     enum iio_event_direction dir,
-                                     enum iio_event_info info,
-                                     int *val, int *val2)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       *val = st->event_val;
-
-       return IIO_VAL_INT;
-}
-
-/**
- * iio_simple_dummy_write_event_value() - set value associate with event
- * @indio_dev: device instance specific data
- * @chan: channel for the event whose value is being set
- * @type: type of the event whose value is being set
- * @dir: direction of the vent whose value is being set
- * @info: info type of the event whose value is being set
- * @val: the value to be set.
- */
-int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
-                                      const struct iio_chan_spec *chan,
-                                      enum iio_event_type type,
-                                      enum iio_event_direction dir,
-                                      enum iio_event_info info,
-                                      int val, int val2)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       st->event_val = val;
-
-       return 0;
-}
-
-static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
-{
-       struct iio_dev *indio_dev = private;
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       st->event_timestamp = iio_get_time_ns();
-       return IRQ_HANDLED;
-}
-
-/**
- * iio_simple_dummy_event_handler() - identify and pass on event
- * @irq: irq of event line
- * @private: pointer to device instance state.
- *
- * This handler is responsible for querying the device to find out what
- * event occurred and for then pushing that event towards userspace.
- * Here only one event occurs so we push that directly on with locally
- * grabbed timestamp.
- */
-static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
-{
-       struct iio_dev *indio_dev = private;
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       dev_dbg(&indio_dev->dev, "id %x event %x\n",
-               st->regs->reg_id, st->regs->reg_data);
-
-       switch (st->regs->reg_data) {
-       case 0:
-               iio_push_event(indio_dev,
-                              IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
-                                             IIO_EV_DIR_RISING,
-                                             IIO_EV_TYPE_THRESH, 0, 0, 0),
-                              st->event_timestamp);
-               break;
-       case 1:
-               if (st->activity_running > st->event_val)
-                       iio_push_event(indio_dev,
-                                      IIO_EVENT_CODE(IIO_ACTIVITY, 0,
-                                                     IIO_MOD_RUNNING,
-                                                     IIO_EV_DIR_RISING,
-                                                     IIO_EV_TYPE_THRESH,
-                                                     0, 0, 0),
-                                      st->event_timestamp);
-               break;
-       case 2:
-               if (st->activity_walking < st->event_val)
-                       iio_push_event(indio_dev,
-                                      IIO_EVENT_CODE(IIO_ACTIVITY, 0,
-                                                     IIO_MOD_WALKING,
-                                                     IIO_EV_DIR_FALLING,
-                                                     IIO_EV_TYPE_THRESH,
-                                                     0, 0, 0),
-                                      st->event_timestamp);
-               break;
-       case 3:
-               iio_push_event(indio_dev,
-                              IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
-                                             IIO_EV_DIR_NONE,
-                                             IIO_EV_TYPE_CHANGE, 0, 0, 0),
-                              st->event_timestamp);
-               break;
-       default:
-               break;
-       }
-
-       return IRQ_HANDLED;
-}
-
-/**
- * iio_simple_dummy_events_register() - setup interrupt handling for events
- * @indio_dev: device instance data
- *
- * This function requests the threaded interrupt to handle the events.
- * Normally the irq is a hardware interrupt and the number comes
- * from board configuration files.  Here we get it from a companion
- * module that fakes the interrupt for us. Note that module in
- * no way forms part of this example. Just assume that events magically
- * appear via the provided interrupt.
- */
-int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-       int ret;
-
-       /* Fire up event source - normally not present */
-       st->event_irq = iio_dummy_evgen_get_irq();
-       if (st->event_irq < 0) {
-               ret = st->event_irq;
-               goto error_ret;
-       }
-       st->regs = iio_dummy_evgen_get_regs(st->event_irq);
-
-       ret = request_threaded_irq(st->event_irq,
-                                  &iio_simple_dummy_get_timestamp,
-                                  &iio_simple_dummy_event_handler,
-                                  IRQF_ONESHOT,
-                                  "iio_simple_event",
-                                  indio_dev);
-       if (ret < 0)
-               goto error_free_evgen;
-       return 0;
-
-error_free_evgen:
-       iio_dummy_evgen_release_irq(st->event_irq);
-error_ret:
-       return ret;
-}
-
-/**
- * iio_simple_dummy_events_unregister() - tidy up interrupt handling on remove
- * @indio_dev: device instance data
- */
-void iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
-{
-       struct iio_dummy_state *st = iio_priv(indio_dev);
-
-       free_irq(st->event_irq, indio_dev);
-       /* Not part of normal driver */
-       iio_dummy_evgen_release_irq(st->event_irq);
-}
diff --git a/include/linux/iio/buffer-dma.h b/include/linux/iio/buffer-dma.h
new file mode 100644 (file)
index 0000000..767467d
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2013-2015 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef __INDUSTRIALIO_DMA_BUFFER_H__
+#define __INDUSTRIALIO_DMA_BUFFER_H__
+
+#include <linux/list.h>
+#include <linux/kref.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/iio/buffer.h>
+
+struct iio_dma_buffer_queue;
+struct iio_dma_buffer_ops;
+struct device;
+
+struct iio_buffer_block {
+       u32 size;
+       u32 bytes_used;
+};
+
+/**
+ * enum iio_block_state - State of a struct iio_dma_buffer_block
+ * @IIO_BLOCK_STATE_DEQUEUED: Block is not queued
+ * @IIO_BLOCK_STATE_QUEUED: Block is on the incoming queue
+ * @IIO_BLOCK_STATE_ACTIVE: Block is currently being processed by the DMA
+ * @IIO_BLOCK_STATE_DONE: Block is on the outgoing queue
+ * @IIO_BLOCK_STATE_DEAD: Block has been marked as to be freed
+ */
+enum iio_block_state {
+       IIO_BLOCK_STATE_DEQUEUED,
+       IIO_BLOCK_STATE_QUEUED,
+       IIO_BLOCK_STATE_ACTIVE,
+       IIO_BLOCK_STATE_DONE,
+       IIO_BLOCK_STATE_DEAD,
+};
+
+/**
+ * struct iio_dma_buffer_block - IIO buffer block
+ * @head: List head
+ * @size: Total size of the block in bytes
+ * @bytes_used: Number of bytes that contain valid data
+ * @vaddr: Virutal address of the blocks memory
+ * @phys_addr: Physical address of the blocks memory
+ * @queue: Parent DMA buffer queue
+ * @kref: kref used to manage the lifetime of block
+ * @state: Current state of the block
+ */
+struct iio_dma_buffer_block {
+       /* May only be accessed by the owner of the block */
+       struct list_head head;
+       size_t bytes_used;
+
+       /*
+        * Set during allocation, constant thereafter. May be accessed read-only
+        * by anybody holding a reference to the block.
+        */
+       void *vaddr;
+       dma_addr_t phys_addr;
+       size_t size;
+       struct iio_dma_buffer_queue *queue;
+
+       /* Must not be accessed outside the core. */
+       struct kref kref;
+       /*
+        * Must not be accessed outside the core. Access needs to hold
+        * queue->list_lock if the block is not owned by the core.
+        */
+       enum iio_block_state state;
+};
+
+/**
+ * struct iio_dma_buffer_queue_fileio - FileIO state for the DMA buffer
+ * @blocks: Buffer blocks used for fileio
+ * @active_block: Block being used in read()
+ * @pos: Read offset in the active block
+ * @block_size: Size of each block
+ */
+struct iio_dma_buffer_queue_fileio {
+       struct iio_dma_buffer_block *blocks[2];
+       struct iio_dma_buffer_block *active_block;
+       size_t pos;
+       size_t block_size;
+};
+
+/**
+ * struct iio_dma_buffer_queue - DMA buffer base structure
+ * @buffer: IIO buffer base structure
+ * @dev: Parent device
+ * @ops: DMA buffer callbacks
+ * @lock: Protects the incoming list, active and the fields in the fileio
+ *   substruct
+ * @list_lock: Protects lists that contain blocks which can be modified in
+ *   atomic context as well as blocks on those lists. This is the outgoing queue
+ *   list and typically also a list of active blocks in the part that handles
+ *   the DMA controller
+ * @incoming: List of buffers on the incoming queue
+ * @outgoing: List of buffers on the outgoing queue
+ * @active: Whether the buffer is currently active
+ * @fileio: FileIO state
+ */
+struct iio_dma_buffer_queue {
+       struct iio_buffer buffer;
+       struct device *dev;
+       const struct iio_dma_buffer_ops *ops;
+
+       struct mutex lock;
+       spinlock_t list_lock;
+       struct list_head incoming;
+       struct list_head outgoing;
+
+       bool active;
+
+       struct iio_dma_buffer_queue_fileio fileio;
+};
+
+/**
+ * struct iio_dma_buffer_ops - DMA buffer callback operations
+ * @submit: Called when a block is submitted to the DMA controller
+ * @abort: Should abort all pending transfers
+ */
+struct iio_dma_buffer_ops {
+       int (*submit)(struct iio_dma_buffer_queue *queue,
+               struct iio_dma_buffer_block *block);
+       void (*abort)(struct iio_dma_buffer_queue *queue);
+};
+
+void iio_dma_buffer_block_done(struct iio_dma_buffer_block *block);
+void iio_dma_buffer_block_list_abort(struct iio_dma_buffer_queue *queue,
+       struct list_head *list);
+
+int iio_dma_buffer_enable(struct iio_buffer *buffer,
+       struct iio_dev *indio_dev);
+int iio_dma_buffer_disable(struct iio_buffer *buffer,
+       struct iio_dev *indio_dev);
+int iio_dma_buffer_read(struct iio_buffer *buffer, size_t n,
+       char __user *user_buffer);
+size_t iio_dma_buffer_data_available(struct iio_buffer *buffer);
+int iio_dma_buffer_set_bytes_per_datum(struct iio_buffer *buffer, size_t bpd);
+int iio_dma_buffer_set_length(struct iio_buffer *buffer, int length);
+int iio_dma_buffer_request_update(struct iio_buffer *buffer);
+
+int iio_dma_buffer_init(struct iio_dma_buffer_queue *queue,
+       struct device *dma_dev, const struct iio_dma_buffer_ops *ops);
+void iio_dma_buffer_exit(struct iio_dma_buffer_queue *queue);
+void iio_dma_buffer_release(struct iio_dma_buffer_queue *queue);
+
+#endif
diff --git a/include/linux/iio/buffer-dmaengine.h b/include/linux/iio/buffer-dmaengine.h
new file mode 100644 (file)
index 0000000..5dcddf4
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2014-2015 Analog Devices Inc.
+ *  Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __IIO_DMAENGINE_H__
+#define __IIO_DMAENGINE_H__
+
+struct iio_buffer;
+struct device;
+
+struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev,
+       const char *channel);
+void iio_dmaengine_buffer_free(struct iio_buffer *buffer);
+
+#endif
index 1600c55828e0faa463d48509ff86ed22cb71d327..2ec3ad58e8a06e42f8764d2fa8e18cb14fdc67a2 100644 (file)
 
 struct iio_buffer;
 
+/**
+ * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be
+ *   configured. It has a fixed value which will be buffer specific.
+ */
+#define INDIO_BUFFER_FLAG_FIXED_WATERMARK BIT(0)
+
 /**
  * struct iio_buffer_access_funcs - access functions for buffers.
  * @store_to:          actually store stuff to the buffer
@@ -27,9 +33,15 @@ struct iio_buffer;
  *                     storage.
  * @set_bytes_per_datum:set number of bytes per datum
  * @set_length:                set number of datums in buffer
+ * @enable:             called if the buffer is attached to a device and the
+ *                      device starts sampling. Calls are balanced with
+ *                      @disable.
+ * @disable:            called if the buffer is attached to a device and the
+ *                      device stops sampling. Calles are balanced with @enable.
  * @release:           called when the last reference to the buffer is dropped,
  *                     should free all resources allocated by the buffer.
  * @modes:             Supported operating modes by this buffer type
+ * @flags:             A bitmask combination of INDIO_BUFFER_FLAG_*
  *
  * The purpose of this structure is to make the buffer element
  * modular as event for a given driver, different usecases may require
@@ -51,9 +63,13 @@ struct iio_buffer_access_funcs {
        int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
        int (*set_length)(struct iio_buffer *buffer, int length);
 
+       int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
+       int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
+
        void (*release)(struct iio_buffer *buffer);
 
        unsigned int modes;
+       unsigned int flags;
 };
 
 /**
index 13e1d96935ed7248a645b9b207ef64577a4b2653..c800dbc420795c37c78b2008b4cbe5991d90b881 100644 (file)
@@ -134,21 +134,32 @@ struct palmas_pmic_driver_data {
                            struct regulator_config config);
 };
 
+struct palmas_adc_wakeup_property {
+       int adc_channel_number;
+       int adc_high_threshold;
+       int adc_low_threshold;
+};
+
 struct palmas_gpadc_platform_data {
        /* Channel 3 current source is only enabled during conversion */
-       int ch3_current;
+       int ch3_current;        /* 0: off; 1: 10uA; 2: 400uA; 3: 800 uA */
 
        /* Channel 0 current source can be used for battery detection.
         * If used for battery detection this will cause a permanent current
         * consumption depending on current level set here.
         */
-       int ch0_current;
+       int ch0_current;        /* 0: off; 1: 5uA; 2: 15uA; 3: 20 uA */
+       bool extended_delay;    /* use extended delay for conversion */
 
        /* default BAT_REMOVAL_DAT setting on device probe */
        int bat_removal;
 
        /* Sets the START_POLARITY bit in the RT_CTRL register */
        int start_polarity;
+
+       int auto_conversion_period_ms;
+       struct palmas_adc_wakeup_property *adc_wakeup1_data;
+       struct palmas_adc_wakeup_property *adc_wakeup2_data;
 };
 
 struct palmas_reg_init {
@@ -405,28 +416,7 @@ struct palmas_gpadc_calibration {
        s32 offset_error;
 };
 
-struct palmas_gpadc {
-       struct device *dev;
-       struct palmas *palmas;
-
-       int ch3_current;
-       int ch0_current;
-
-       int gpadc_force;
-
-       int bat_removal;
-
-       struct mutex reading_lock;
-       struct completion irq_complete;
-
-       int eoc_sw_irq;
-
-       struct palmas_gpadc_calibration *palmas_cal_tbl;
-
-       int conv0_channel;
-       int conv1_channel;
-       int rt_channel;
-};
+#define PALMAS_DATASHEET_NAME(_name)   "palmas-gpadc-chan-"#_name
 
 struct palmas_gpadc_result {
        s32 raw_code;
@@ -520,6 +510,43 @@ enum palmas_irqs {
        PALMAS_NUM_IRQ,
 };
 
+/* Palmas GPADC Channels */
+enum {
+       PALMAS_ADC_CH_IN0,
+       PALMAS_ADC_CH_IN1,
+       PALMAS_ADC_CH_IN2,
+       PALMAS_ADC_CH_IN3,
+       PALMAS_ADC_CH_IN4,
+       PALMAS_ADC_CH_IN5,
+       PALMAS_ADC_CH_IN6,
+       PALMAS_ADC_CH_IN7,
+       PALMAS_ADC_CH_IN8,
+       PALMAS_ADC_CH_IN9,
+       PALMAS_ADC_CH_IN10,
+       PALMAS_ADC_CH_IN11,
+       PALMAS_ADC_CH_IN12,
+       PALMAS_ADC_CH_IN13,
+       PALMAS_ADC_CH_IN14,
+       PALMAS_ADC_CH_IN15,
+       PALMAS_ADC_CH_MAX,
+};
+
+/* Palmas GPADC Channel0 Current Source */
+enum {
+       PALMAS_ADC_CH0_CURRENT_SRC_0,
+       PALMAS_ADC_CH0_CURRENT_SRC_5,
+       PALMAS_ADC_CH0_CURRENT_SRC_15,
+       PALMAS_ADC_CH0_CURRENT_SRC_20,
+};
+
+/* Palmas GPADC Channel3 Current Source */
+enum {
+       PALMAS_ADC_CH3_CURRENT_SRC_0,
+       PALMAS_ADC_CH3_CURRENT_SRC_10,
+       PALMAS_ADC_CH3_CURRENT_SRC_400,
+       PALMAS_ADC_CH3_CURRENT_SRC_800,
+};
+
 struct palmas_pmic {
        struct palmas *palmas;
        struct device *dev;