linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lars-Peter Clausen <lars@metafoo.de>
To: Jonathan Cameron <jic23@cam.ac.uk>
Cc: linux-iio@vger.kernel.org, drivers@analog.com,
	Lars-Peter Clausen <lars@metafoo.de>
Subject: [PATCH 10/11] staging:iio:adis: Preallocate transfer message
Date: Tue, 13 Nov 2012 14:28:12 +0100	[thread overview]
Message-ID: <1352813293-17975-10-git-send-email-lars@metafoo.de> (raw)
In-Reply-To: <1352813293-17975-1-git-send-email-lars@metafoo.de>

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>
---
 drivers/staging/iio/accel/adis16201_core.c |   1 +
 drivers/staging/iio/accel/adis16203_core.c |   1 +
 drivers/staging/iio/accel/adis16204_core.c |   1 +
 drivers/staging/iio/accel/adis16209_core.c |   1 +
 drivers/staging/iio/accel/adis16240_core.c |   1 +
 drivers/staging/iio/gyro/adis16260_core.c  |   1 +
 drivers/staging/iio/imu/adis.h             |   8 ++
 drivers/staging/iio/imu/adis_buffer.c      | 114 +++++++++++++++++------------
 8 files changed, 80 insertions(+), 48 deletions(-)

diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index 0121501..833dd6b 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -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,
 };
 
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index 326b106..f631e57 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -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,
 };
 
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index 4f69ead..dbec841 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -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,
 };
 
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index e203e96..f9f9d58 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -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,
 };
 
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 019a31e..3d1a8a9 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -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,
 };
 
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 820547b..b988b4f 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -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,
 };
 
diff --git a/drivers/staging/iio/imu/adis.h b/drivers/staging/iio/imu/adis.h
index c84da7a..8c3304d 100644
--- a/drivers/staging/iio/imu/adis.h
+++ b/drivers/staging/iio/imu/adis.h
@@ -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
diff --git a/drivers/staging/iio/imu/adis_buffer.c b/drivers/staging/iio/imu/adis_buffer.c
index 0fa8e80a..342758c 100644
--- a/drivers/staging/iio/imu/adis_buffer.c
+++ b/drivers/staging/iio/imu/adis_buffer.c
@@ -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>
@@ -12,73 +21,80 @@
 
 #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);
-- 
1.8.0


  parent reply	other threads:[~2012-11-13 13:28 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-13 13:28 [PATCH 01/11] staging:iio: Add common ADIS library Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 02/11] staging:iio:adis16201: Use adis library Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 03/11] staging:iio:adis16203: " Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 04/11] staging:iio:adis16204: " Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 05/11] staging:iio:adis16209: " Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 06/11] staging:iio:adis16220: " Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 07/11] staging:iio:adis16240: " Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 08/11] staging:iio:adis16260: " Lars-Peter Clausen
2012-11-13 13:28 ` [PATCH 09/11] staging:iio:adis_lib: Use triggered buffer setup helper function Lars-Peter Clausen
2012-11-13 13:28 ` Lars-Peter Clausen [this message]
2012-11-13 13:28 ` [PATCH 11/11] staging:iio: Move adis library out of staging Lars-Peter Clausen
2012-11-17 11:00   ` Jonathan Cameron
2012-11-17 11:01 ` [PATCH 01/11] staging:iio: Add common ADIS library Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1352813293-17975-10-git-send-email-lars@metafoo.de \
    --to=lars@metafoo.de \
    --cc=drivers@analog.com \
    --cc=jic23@cam.ac.uk \
    --cc=linux-iio@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).