iio: mxc4005: add triggered buffer mode for mxc4005
authorTeodora Baluta <teodora.baluta@intel.com>
Thu, 20 Aug 2015 14:37:32 +0000 (17:37 +0300)
committerJonathan Cameron <jic23@kernel.org>
Mon, 31 Aug 2015 16:36:56 +0000 (17:36 +0100)
This patch adds support for buffered readings for the 3-axis
accelerometer mxc4005.

Signed-off-by: Teodora Baluta <teodora.baluta@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/accel/Kconfig
drivers/iio/accel/mxc4005.c

index 69302bed28609f6bcfffd3cb971ccff742f4bede..cd5cd246792df6e9d4f9b051dd7784e1d2af42cf 100644 (file)
@@ -140,6 +140,8 @@ config MMA9553
 config MXC4005
        tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver"
        depends on I2C
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        select REGMAP_I2C
        help
          Say yes here to build support for the Memsic MXC4005XC 3-axis
index e15c1bd26bd109ae81f0470b101c9f90aa36bf27..390eaf8cb2f8e6f2b23a6de0fef7559aaaeeee9f 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/acpi.h>
 #include <linux/regmap.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
 
 #define MXC4005_DRV_NAME               "mxc4005"
 #define MXC4005_REGMAP_NAME            "mxc4005_regmap"
@@ -52,6 +55,7 @@ struct mxc4005_data {
        struct device *dev;
        struct mutex mutex;
        struct regmap *regmap;
+       __be16 buffer[8];
 };
 
 /*
@@ -122,6 +126,20 @@ static const struct regmap_config mxc4005_regmap_config = {
        .writeable_reg = mxc4005_is_writeable_reg,
 };
 
+static int mxc4005_read_xyz(struct mxc4005_data *data)
+{
+       int ret;
+
+       ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER,
+                              (u8 *) data->buffer, sizeof(data->buffer));
+       if (ret < 0) {
+               dev_err(data->dev, "failed to read axes\n");
+               return ret;
+       }
+
+       return 0;
+}
+
 static int mxc4005_read_axis(struct mxc4005_data *data,
                             unsigned int addr)
 {
@@ -197,7 +215,8 @@ static int mxc4005_read_raw(struct iio_dev *indio_dev,
                        ret = mxc4005_read_axis(data, chan->address);
                        if (ret < 0)
                                return ret;
-                       *val = sign_extend32(ret >> 4, 11);
+                       *val = sign_extend32(ret >> chan->scan_type.shift,
+                                            chan->scan_type.realbits - 1);
                        return IIO_VAL_INT;
                default:
                        return -EINVAL;
@@ -239,6 +258,11 @@ static const struct iio_info mxc4005_info = {
        .attrs          = &mxc4005_attrs_group,
 };
 
+static const unsigned long mxc4005_scan_masks[] = {
+       BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z),
+       0
+};
+
 #define MXC4005_CHANNEL(_axis, _addr) {                                \
        .type = IIO_ACCEL,                                      \
        .modified = 1,                                          \
@@ -246,14 +270,43 @@ static const struct iio_info mxc4005_info = {
        .address = _addr,                                       \
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
        .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
+       .scan_index = AXIS_##_axis,                             \
+       .scan_type = {                                          \
+               .sign = 's',                                    \
+               .realbits = 12,                                 \
+               .storagebits = 16,                              \
+               .shift = 4,                                     \
+               .endianness = IIO_BE,                           \
+       },                                                      \
 }
 
 static const struct iio_chan_spec mxc4005_channels[] = {
        MXC4005_CHANNEL(X, MXC4005_REG_XOUT_UPPER),
        MXC4005_CHANNEL(Y, MXC4005_REG_YOUT_UPPER),
        MXC4005_CHANNEL(Z, MXC4005_REG_ZOUT_UPPER),
+       IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
+static irqreturn_t mxc4005_trigger_handler(int irq, void *private)
+{
+       struct iio_poll_func *pf = private;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct mxc4005_data *data = iio_priv(indio_dev);
+       int ret;
+
+       ret = mxc4005_read_xyz(data);
+       if (ret < 0)
+               goto err;
+
+       iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+                                          pf->timestamp);
+
+err:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
 static int mxc4005_chip_init(struct mxc4005_data *data)
 {
        int ret;
@@ -304,23 +357,43 @@ static int mxc4005_probe(struct i2c_client *client,
        indio_dev->dev.parent = &client->dev;
        indio_dev->channels = mxc4005_channels;
        indio_dev->num_channels = ARRAY_SIZE(mxc4005_channels);
+       indio_dev->available_scan_masks = mxc4005_scan_masks;
        indio_dev->name = MXC4005_DRV_NAME;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &mxc4005_info;
 
+       ret = iio_triggered_buffer_setup(indio_dev,
+                                        &iio_pollfunc_store_time,
+                                        mxc4005_trigger_handler,
+                                        NULL);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "failed to setup iio triggered buffer\n");
+               return ret;
+       }
+
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(&client->dev,
                        "unable to register iio device %d\n", ret);
-               return ret;
+               goto err_buffer_cleanup;
        }
 
        return 0;
+
+err_buffer_cleanup:
+       iio_triggered_buffer_cleanup(indio_dev);
+
+       return ret;
 }
 
 static int mxc4005_remove(struct i2c_client *client)
 {
-       iio_device_unregister(i2c_get_clientdata(client));
+       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+       iio_device_unregister(indio_dev);
+
+       iio_triggered_buffer_cleanup(indio_dev);
 
        return 0;
 }