staging:iio:adis: Preallocate transfer message
authorLars-Peter Clausen <lars@metafoo.de>
Tue, 13 Nov 2012 13:28:00 +0000 (13:28 +0000)
committerJonathan Cameron <jic23@kernel.org>
Mon, 19 Nov 2012 22:22:11 +0000 (22:22 +0000)
Currently the driver reads out all sample registers of the device and throws
away those which it does not need. Furthermore the SPI message is constructed
each time the trigger handler is run, although it will be the same each time.
This patch preallocates and pre-constructs the SPI message in the
"update_scan_mode" callback. Only those register which are actually selected for
sampling are included in the message. The patch also gets rid of the conversion
of the sample data from big endian to the native endianness and instead marks
the channel as big endian in its scan type. This allows to directly push the
SPI transfer buffer to the IIO buffer without the need to post-process it.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/staging/iio/accel/adis16201_core.c
drivers/staging/iio/accel/adis16203_core.c
drivers/staging/iio/accel/adis16204_core.c
drivers/staging/iio/accel/adis16209_core.c
drivers/staging/iio/accel/adis16240_core.c
drivers/staging/iio/gyro/adis16260_core.c
drivers/staging/iio/imu/adis.h
drivers/staging/iio/imu/adis_buffer.c

index 0121501dc6344514d982efbde8418017ff43ef5a..833dd6b73bc3d6a79dd17db56891c5c85ec412e5 100644 (file)
@@ -148,6 +148,7 @@ static const struct iio_chan_spec adis16201_channels[] = {
 static const struct iio_info adis16201_info = {
        .read_raw = &adis16201_read_raw,
        .write_raw = &adis16201_write_raw,
+       .update_scan_mode = adis_update_scan_mode,
        .driver_module = THIS_MODULE,
 };
 
index 326b1067543e41f9a494f6a8302384087c03f7e6..f631e578fbd104ee24cf3059985e083f8ffb0a31 100644 (file)
@@ -112,6 +112,7 @@ static const struct iio_chan_spec adis16203_channels[] = {
 static const struct iio_info adis16203_info = {
        .read_raw = &adis16203_read_raw,
        .write_raw = &adis16203_write_raw,
+       .update_scan_mode = adis_update_scan_mode,
        .driver_module = THIS_MODULE,
 };
 
index 4f69ead1ae819599176de64ba48f0f03089f8e37..dbec841ce30c4fcdf2cd44d4c6c97bad220bc950 100644 (file)
@@ -153,6 +153,7 @@ static const struct iio_chan_spec adis16204_channels[] = {
 static const struct iio_info adis16204_info = {
        .read_raw = &adis16204_read_raw,
        .write_raw = &adis16204_write_raw,
+       .update_scan_mode = adis_update_scan_mode,
        .driver_module = THIS_MODULE,
 };
 
index e203e96a5663ab2923816498ac3d5be9329137c6..f9f9d582b32d90d73298733833c3b775733da9a5 100644 (file)
@@ -146,6 +146,7 @@ static const struct iio_chan_spec adis16209_channels[] = {
 static const struct iio_info adis16209_info = {
        .read_raw = &adis16209_read_raw,
        .write_raw = &adis16209_write_raw,
+       .update_scan_mode = adis_update_scan_mode,
        .driver_module = THIS_MODULE,
 };
 
index 019a31e220388d988c45dc757ae14314479b0330..3d1a8a9921ad9d6b28db046aa4110ac1734a75ad 100644 (file)
@@ -202,6 +202,7 @@ static const struct iio_info adis16240_info = {
        .attrs = &adis16240_attribute_group,
        .read_raw = &adis16240_read_raw,
        .write_raw = &adis16240_write_raw,
+       .update_scan_mode = adis_update_scan_mode,
        .driver_module = THIS_MODULE,
 };
 
index 820547baae3070e13087202df0b49280fedc44a5..b988b4f5bdda7be7e3c7a4f8856d976ba6e7dbb5 100644 (file)
@@ -267,6 +267,7 @@ static const struct iio_info adis16260_info = {
        .attrs = &adis16260_attribute_group,
        .read_raw = &adis16260_read_raw,
        .write_raw = &adis16260_write_raw,
+       .update_scan_mode = adis_update_scan_mode,
        .driver_module = THIS_MODULE,
 };
 
index c84da7afe14692b5adfcde79541269100267f02d..8c3304d44b978d1ecb3c73f4740be867c2c1aba0 100644 (file)
@@ -87,6 +87,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
                .sign = 'u', \
                .realbits = (bits), \
                .storagebits = 16, \
+               .endianness = IIO_BE, \
        }, \
 }
 
@@ -109,6 +110,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
                .sign = 'u', \
                .realbits = (bits), \
                .storagebits = 16, \
+               .endianness = IIO_BE, \
        }, \
 }
 
@@ -125,6 +127,7 @@ int adis_single_conversion(struct iio_dev *indio_dev,
                .sign = 's', \
                .realbits = (bits), \
                .storagebits = 16, \
+               .endianness = IIO_BE, \
        }, \
 }
 
@@ -150,6 +153,9 @@ void adis_cleanup_buffer_and_trigger(struct adis *adis,
 int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev);
 void adis_remove_trigger(struct adis *adis);
 
+int adis_update_scan_mode(struct iio_dev *indio_dev,
+       const unsigned long *scan_mask);
+
 #else /* CONFIG_IIO_BUFFER */
 
 static inline int adis_setup_buffer_and_trigger(struct adis *adis,
@@ -173,6 +179,8 @@ static inline void adis_remove_trigger(struct adis *adis)
 {
 }
 
+#define adis_update_scan_mode NULL
+
 #endif /* CONFIG_IIO_BUFFER */
 
 #endif
index 0fa8e80a54b3920668e634cfec61061f4e0b946d..342758c14d2b89d9ab307333008031a23ef48d6a 100644 (file)
@@ -1,3 +1,12 @@
+/*
+ * Common library for ADIS16XXX devices
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *   Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
 #include  "adis.h"
 
-#define ADIS_MAX_OUTPUTS 12
-
-static int adis_read_buffer_data(struct adis *adis, struct iio_dev *indio_dev)
+int adis_update_scan_mode(struct iio_dev *indio_dev,
+       const unsigned long *scan_mask)
 {
-       int n_outputs = indio_dev->num_channels;
-       struct spi_transfer xfers[ADIS_MAX_OUTPUTS + 1];
-       struct spi_message msg;
-       int ret;
-       int i;
-
-       mutex_lock(&adis->txrx_lock);
-
-       spi_message_init(&msg);
-
-       memset(xfers, 0, sizeof(xfers));
-       for (i = 0; i <= n_outputs; i++) {
-               xfers[i].bits_per_word = 8;
-               xfers[i].cs_change = 1;
-               xfers[i].len = 2;
-               xfers[i].delay_usecs = adis->data->read_delay;
-               if (i < n_outputs) {
-                       xfers[i].tx_buf = adis->tx + 2 * i;
-                       adis->tx[2 * i] = indio_dev->channels[i].address;
-                       adis->tx[2 * i + 1] = 0;
-               }
-               if (i >= 1)
-                       xfers[i].rx_buf = adis->rx + 2 * (i - 1);
-               spi_message_add_tail(&xfers[i], &msg);
-       }
+       struct adis *adis = iio_device_get_drvdata(indio_dev);
+       const struct iio_chan_spec *chan;
+       unsigned int scan_count;
+       unsigned int i, j;
+       __be16 *tx, *rx;
 
-       ret = spi_sync(adis->spi, &msg);
-       if (ret)
-               dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
+       kfree(adis->xfer);
+       kfree(adis->buffer);
 
-       mutex_unlock(&adis->txrx_lock);
+       scan_count = indio_dev->scan_bytes / 2;
 
-       return ret;
+       adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL);
+       if (!adis->xfer)
+               return -ENOMEM;
+
+       adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL);
+       if (!adis->buffer)
+               return -ENOMEM;
+
+       rx = adis->buffer;
+       tx = rx + indio_dev->scan_bytes;
+
+       spi_message_init(&adis->msg);
+
+       for (j = 0; j <= scan_count; j++) {
+               adis->xfer[j].bits_per_word = 8;
+               if (j != scan_count)
+                       adis->xfer[j].cs_change = 1;
+               adis->xfer[j].len = 2;
+               adis->xfer[j].delay_usecs = adis->data->read_delay;
+               if (j < scan_count)
+                       adis->xfer[j].tx_buf = &tx[j];
+               if (j >= 1)
+                       adis->xfer[j].rx_buf = &rx[j - 1];
+               spi_message_add_tail(&adis->xfer[j], &adis->msg);
+       }
+
+       chan = indio_dev->channels;
+       for (i = 0; i < indio_dev->num_channels; i++, chan++) {
+               if (!test_bit(chan->scan_index, scan_mask))
+                       continue;
+               *tx++ = cpu_to_be16(chan->address << 8);
+       }
+
+       return 0;
 }
+EXPORT_SYMBOL_GPL(adis_update_scan_mode);
 
 static irqreturn_t adis_trigger_handler(int irq, void *p)
 {
        struct iio_poll_func *pf = p;
        struct iio_dev *indio_dev = pf->indio_dev;
        struct adis *adis = iio_device_get_drvdata(indio_dev);
-       u16 *data;
-       int i = 0;
+       int ret;
 
-       data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
-       if (data == NULL) {
-               dev_err(&adis->spi->dev, "Failed to allocate memory.");
+       if (!adis->buffer)
                return -ENOMEM;
-       }
 
-       if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)
-           && adis_read_buffer_data(adis, indio_dev) >= 0)
-               for (; i < bitmap_weight(indio_dev->active_scan_mask,
-                                        indio_dev->masklength); i++)
-                       data[i] = be16_to_cpup((__be16 *)&(adis->rx[i*2]));
+       ret = spi_sync(adis->spi, &adis->msg);
+       if (ret)
+               dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
 
        /* Guaranteed to be aligned with 8 byte boundary */
-       if (indio_dev->scan_timestamp)
-               *((s64 *)(PTR_ALIGN(data, sizeof(s64)))) = pf->timestamp;
+       if (indio_dev->scan_timestamp) {
+               void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);
+               *(s64 *)b = pf->timestamp;
+       }
 
-       iio_push_to_buffers(indio_dev, (u8 *)data);
+       iio_push_to_buffers(indio_dev, adis->buffer);
 
        iio_trigger_notify_done(indio_dev->trig);
-       kfree(data);
 
        return IRQ_HANDLED;
 }
@@ -137,6 +153,8 @@ void adis_cleanup_buffer_and_trigger(struct adis *adis,
 {
        if (adis->spi->irq)
                adis_remove_trigger(adis);
+       kfree(adis->buffer);
+       kfree(adis->xfer);
        iio_triggered_buffer_cleanup(indio_dev);
 }
 EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger);
This page took 0.029248 seconds and 5 git commands to generate.