summaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio/imu/adis16400_ring.c
diff options
context:
space:
mode:
authorLars-Peter Clausen2013-01-16 13:48:00 +0100
committerJonathan Cameron2013-01-26 11:07:48 +0100
commit5eda3550a3cc1987a495e9f85e5998a76d15a0aa (patch)
tree8e66ff7db268ffd869783a6fea0c5e27eae8bd5a /drivers/staging/iio/imu/adis16400_ring.c
parentstaging:iio:adis16400: Add helper macros for channel declaration (diff)
downloadkernel-qcow2-linux-5eda3550a3cc1987a495e9f85e5998a76d15a0aa.tar.gz
kernel-qcow2-linux-5eda3550a3cc1987a495e9f85e5998a76d15a0aa.tar.xz
kernel-qcow2-linux-5eda3550a3cc1987a495e9f85e5998a76d15a0aa.zip
staging:iio:adis16400: Preallocate transfer message
Similar to like we already did for the generic adis library preallocate and pre-construct the SPI transfer message for the adis16400. For devices which do not support burst mode sampling does not differ from other adis devices and so we use the generic functions of the adis library in this case. In burst mode we can only sample all channels at once, so use the IIO cores demux facility instead of doing this manually. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/staging/iio/imu/adis16400_ring.c')
-rw-r--r--drivers/staging/iio/imu/adis16400_ring.c192
1 files changed, 58 insertions, 134 deletions
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index e421278e8d79..054c01d6e73c 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -13,160 +13,84 @@
#include "adis16400.h"
-/**
- * adis16400_spi_read_burst() - read all data registers
- * @indio_dev: the IIO device
- * @rx: somewhere to pass back the value read (min size is 24 bytes)
- **/
-static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx)
+int adis16400_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
{
- struct spi_message msg;
struct adis16400_state *st = iio_priv(indio_dev);
- u32 old_speed_hz = st->adis.spi->max_speed_hz;
- int ret;
+ struct adis *adis = &st->adis;
+ uint16_t *tx, *rx;
- struct spi_transfer xfers[] = {
- {
- .tx_buf = st->adis.tx,
- .bits_per_word = 8,
- .len = 2,
- }, {
- .rx_buf = rx,
- .bits_per_word = 8,
- .len = 24,
- },
- };
-
- mutex_lock(&st->adis.txrx_lock);
- st->adis.tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
- st->adis.tx[1] = 0;
-
- spi_message_init(&msg);
- spi_message_add_tail(&xfers[0], &msg);
- spi_message_add_tail(&xfers[1], &msg);
-
- st->adis.spi->max_speed_hz = min(ADIS16400_SPI_BURST, old_speed_hz);
- spi_setup(st->adis.spi);
-
- ret = spi_sync(st->adis.spi, &msg);
- if (ret)
- dev_err(&st->adis.spi->dev, "problem when burst reading");
+ if (st->variant->flags & ADIS16400_NO_BURST)
+ return adis_update_scan_mode(indio_dev, scan_mask);
- st->adis.spi->max_speed_hz = old_speed_hz;
- spi_setup(st->adis.spi);
- mutex_unlock(&st->adis.txrx_lock);
- return ret;
-}
-
-static const u16 read_all_tx_array[] = {
- cpu_to_be16(ADIS_READ_REG(ADIS16400_SUPPLY_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_XGYRO_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_YGYRO_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_ZGYRO_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_XACCL_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_YACCL_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_ZACCL_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16350_XTEMP_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16350_YTEMP_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16350_ZTEMP_OUT)),
- cpu_to_be16(ADIS_READ_REG(ADIS16400_AUX_ADC)),
-};
-
-static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx)
-{
- struct adis16400_state *st = iio_priv(indio_dev);
+ kfree(adis->xfer);
+ kfree(adis->buffer);
- struct spi_message msg;
- int i, j = 0, ret;
- struct spi_transfer *xfers;
- int scan_count = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength);
+ adis->xfer = kcalloc(2, sizeof(*adis->xfer), GFP_KERNEL);
+ if (!adis->xfer)
+ return -ENOMEM;
- xfers = kzalloc(sizeof(*xfers)*(scan_count + 1),
- GFP_KERNEL);
- if (xfers == NULL)
+ adis->buffer = kzalloc(indio_dev->scan_bytes + sizeof(u16),
+ GFP_KERNEL);
+ if (!adis->buffer)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(read_all_tx_array); i++)
- if (test_bit(i, indio_dev->active_scan_mask)) {
- xfers[j].tx_buf = &read_all_tx_array[i];
- xfers[j].bits_per_word = 16;
- xfers[j].len = 2;
- xfers[j + 1].rx_buf = rx + j*2;
- j++;
- }
- xfers[j].bits_per_word = 16;
- xfers[j].len = 2;
-
- spi_message_init(&msg);
- for (j = 0; j < scan_count + 1; j++)
- spi_message_add_tail(&xfers[j], &msg);
-
- ret = spi_sync(st->adis.spi, &msg);
- kfree(xfers);
-
- return ret;
+ rx = adis->buffer;
+ tx = adis->buffer + indio_dev->scan_bytes;
+
+ tx[0] = ADIS_READ_REG(ADIS16400_GLOB_CMD);
+ tx[1] = 0;
+
+ adis->xfer[0].tx_buf = tx;
+ adis->xfer[0].bits_per_word = 8;
+ adis->xfer[0].len = 2;
+ adis->xfer[1].tx_buf = tx;
+ adis->xfer[1].bits_per_word = 8;
+ adis->xfer[1].len = indio_dev->scan_bytes;
+
+ spi_message_init(&adis->msg);
+ spi_message_add_tail(&adis->xfer[0], &adis->msg);
+ spi_message_add_tail(&adis->xfer[1], &adis->msg);
+
+ return 0;
}
-/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
- * specific to be rolled into the core.
- */
-static irqreturn_t adis16400_trigger_handler(int irq, void *p)
+irqreturn_t adis16400_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16400_state *st = iio_priv(indio_dev);
- int i = 0, j, ret = 0;
- s16 *data;
-
- /* Asumption that long is enough for maximum channels */
- unsigned long mask = *indio_dev->active_scan_mask;
- int scan_count = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength);
- data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
- if (data == NULL) {
- dev_err(&st->adis.spi->dev, "memory alloc failed in ring bh");
- goto done;
+ struct adis *adis = &st->adis;
+ u32 old_speed_hz = st->adis.spi->max_speed_hz;
+ int ret;
+
+ if (!adis->buffer)
+ return -ENOMEM;
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST) &&
+ st->adis.spi->max_speed_hz > ADIS16400_SPI_BURST) {
+ st->adis.spi->max_speed_hz = ADIS16400_SPI_BURST;
+ spi_setup(st->adis.spi);
}
- if (scan_count) {
- if (st->variant->flags & ADIS16400_NO_BURST) {
- ret = adis16350_spi_read_all(indio_dev, st->adis.rx);
- if (ret < 0)
- goto done;
- for (; i < scan_count; i++)
- data[i] = *(s16 *)(st->adis.rx + i*2);
- } else {
- ret = adis16400_spi_read_burst(indio_dev, st->adis.rx);
- if (ret < 0)
- goto done;
- for (; i < scan_count; i++) {
- j = __ffs(mask);
- mask &= ~(1 << j);
- data[i] = be16_to_cpup(
- (__be16 *)&(st->adis.rx[j*2]));
- }
- }
+ ret = spi_sync(adis->spi, &adis->msg);
+ if (ret)
+ dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
+
+ if (!(st->variant->flags & ADIS16400_NO_BURST)) {
+ st->adis.spi->max_speed_hz = old_speed_hz;
+ spi_setup(st->adis.spi);
}
+
/* Guaranteed to be aligned with 8 byte boundary */
- if (indio_dev->scan_timestamp)
- *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffers(indio_dev, (u8 *) data);
+ 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, adis->buffer);
-done:
- kfree(data);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
-
-int adis16400_configure_ring(struct iio_dev *indio_dev)
-{
- return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
- &adis16400_trigger_handler, NULL);
-}
-
-void adis16400_unconfigure_ring(struct iio_dev *indio_dev)
-{
- iio_triggered_buffer_cleanup(indio_dev);
-}