aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/imu/adis_buffer.c
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2012-11-13 08:28:00 -0500
committerJonathan Cameron <jic23@kernel.org>2012-11-19 17:22:12 -0500
commitec04cb048d79cd778c06e28f34395a46d774800d (patch)
treeb6c0a01dc7fc137ceeb256381b2f4e96cdc1d59d /drivers/iio/imu/adis_buffer.c
parentaacff892cbd5c6b1904a3906219548a65018d750 (diff)
staging:iio: Move adis library out of staging
Now that the adis library no longer depends on the sw_ring buffer implementation we can move it out of staging. While we are at it also sort the entries in the iio Kconfig and Makefile to be in alphabetical order. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/imu/adis_buffer.c')
-rw-r--r--drivers/iio/imu/adis_buffer.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c
new file mode 100644
index 000000000000..a91b4cbdc73a
--- /dev/null
+++ b/drivers/iio/imu/adis_buffer.c
@@ -0,0 +1,159 @@
1/*
2 * Common library for ADIS16XXX devices
3 *
4 * Copyright 2012 Analog Devices Inc.
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
6 *
7 * Licensed under the GPL-2 or later.
8 */
9
10#include <linux/export.h>
11#include <linux/interrupt.h>
12#include <linux/mutex.h>
13#include <linux/kernel.h>
14#include <linux/spi/spi.h>
15#include <linux/slab.h>
16
17#include <linux/iio/iio.h>
18#include <linux/iio/buffer.h>
19#include <linux/iio/trigger_consumer.h>
20#include <linux/iio/triggered_buffer.h>
21#include <linux/iio/imu/adis.h>
22
23int adis_update_scan_mode(struct iio_dev *indio_dev,
24 const unsigned long *scan_mask)
25{
26 struct adis *adis = iio_device_get_drvdata(indio_dev);
27 const struct iio_chan_spec *chan;
28 unsigned int scan_count;
29 unsigned int i, j;
30 __be16 *tx, *rx;
31
32 kfree(adis->xfer);
33 kfree(adis->buffer);
34
35 scan_count = indio_dev->scan_bytes / 2;
36
37 adis->xfer = kcalloc(scan_count + 1, sizeof(*adis->xfer), GFP_KERNEL);
38 if (!adis->xfer)
39 return -ENOMEM;
40
41 adis->buffer = kzalloc(indio_dev->scan_bytes * 2, GFP_KERNEL);
42 if (!adis->buffer)
43 return -ENOMEM;
44
45 rx = adis->buffer;
46 tx = rx + indio_dev->scan_bytes;
47
48 spi_message_init(&adis->msg);
49
50 for (j = 0; j <= scan_count; j++) {
51 adis->xfer[j].bits_per_word = 8;
52 if (j != scan_count)
53 adis->xfer[j].cs_change = 1;
54 adis->xfer[j].len = 2;
55 adis->xfer[j].delay_usecs = adis->data->read_delay;
56 if (j < scan_count)
57 adis->xfer[j].tx_buf = &tx[j];
58 if (j >= 1)
59 adis->xfer[j].rx_buf = &rx[j - 1];
60 spi_message_add_tail(&adis->xfer[j], &adis->msg);
61 }
62
63 chan = indio_dev->channels;
64 for (i = 0; i < indio_dev->num_channels; i++, chan++) {
65 if (!test_bit(chan->scan_index, scan_mask))
66 continue;
67 *tx++ = cpu_to_be16(chan->address << 8);
68 }
69
70 return 0;
71}
72EXPORT_SYMBOL_GPL(adis_update_scan_mode);
73
74static irqreturn_t adis_trigger_handler(int irq, void *p)
75{
76 struct iio_poll_func *pf = p;
77 struct iio_dev *indio_dev = pf->indio_dev;
78 struct adis *adis = iio_device_get_drvdata(indio_dev);
79 int ret;
80
81 if (!adis->buffer)
82 return -ENOMEM;
83
84 ret = spi_sync(adis->spi, &adis->msg);
85 if (ret)
86 dev_err(&adis->spi->dev, "Failed to read data: %d", ret);
87
88 /* Guaranteed to be aligned with 8 byte boundary */
89 if (indio_dev->scan_timestamp) {
90 void *b = adis->buffer + indio_dev->scan_bytes - sizeof(s64);
91 *(s64 *)b = pf->timestamp;
92 }
93
94 iio_push_to_buffers(indio_dev, adis->buffer);
95
96 iio_trigger_notify_done(indio_dev->trig);
97
98 return IRQ_HANDLED;
99}
100
101/**
102 * adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device
103 * @adis: The adis device.
104 * @indio_dev: The IIO device.
105 * @trigger_handler: Optional trigger handler, may be NULL.
106 *
107 * Returns 0 on success, a negative error code otherwise.
108 *
109 * This function sets up the buffer and trigger for a adis devices. If
110 * 'trigger_handler' is NULL the default trigger handler will be used. The
111 * default trigger handler will simply read the registers assigned to the
112 * currently active channels.
113 *
114 * adis_cleanup_buffer_and_trigger() should be called to free the resources
115 * allocated by this function.
116 */
117int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev,
118 irqreturn_t (*trigger_handler)(int, void *))
119{
120 int ret;
121
122 if (!trigger_handler)
123 trigger_handler = adis_trigger_handler;
124
125 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
126 trigger_handler, NULL);
127 if (ret)
128 return ret;
129
130 if (adis->spi->irq) {
131 ret = adis_probe_trigger(adis, indio_dev);
132 if (ret)
133 goto error_buffer_cleanup;
134 }
135 return 0;
136
137error_buffer_cleanup:
138 iio_triggered_buffer_cleanup(indio_dev);
139 return ret;
140}
141EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger);
142
143/**
144 * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources
145 * @adis: The adis device.
146 * @indio_dev: The IIO device.
147 *
148 * Frees resources allocated by adis_setup_buffer_and_trigger()
149 */
150void adis_cleanup_buffer_and_trigger(struct adis *adis,
151 struct iio_dev *indio_dev)
152{
153 if (adis->spi->irq)
154 adis_remove_trigger(adis);
155 kfree(adis->buffer);
156 kfree(adis->xfer);
157 iio_triggered_buffer_cleanup(indio_dev);
158}
159EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger);