Commit | Line | Data |
---|---|---|
aacff892 LPC |
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 | ||
ccd2b52f LPC |
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> | |
ccd2b52f | 19 | #include <linux/iio/trigger_consumer.h> |
a458c55c | 20 | #include <linux/iio/triggered_buffer.h> |
ec04cb04 | 21 | #include <linux/iio/imu/adis.h> |
ccd2b52f | 22 | |
aacff892 LPC |
23 | int adis_update_scan_mode(struct iio_dev *indio_dev, |
24 | const unsigned long *scan_mask) | |
ccd2b52f | 25 | { |
aacff892 LPC |
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; | |
ccd2b52f | 31 | |
aacff892 LPC |
32 | kfree(adis->xfer); |
33 | kfree(adis->buffer); | |
ccd2b52f | 34 | |
aacff892 | 35 | scan_count = indio_dev->scan_bytes / 2; |
ccd2b52f | 36 | |
aacff892 LPC |
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; | |
d590faf9 | 46 | tx = rx + scan_count; |
aacff892 LPC |
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; | |
57a1228a LPC |
67 | if (chan->scan_type.storagebits == 32) |
68 | *tx++ = cpu_to_be16((chan->address + 2) << 8); | |
aacff892 LPC |
69 | *tx++ = cpu_to_be16(chan->address << 8); |
70 | } | |
71 | ||
72 | return 0; | |
ccd2b52f | 73 | } |
aacff892 | 74 | EXPORT_SYMBOL_GPL(adis_update_scan_mode); |
ccd2b52f LPC |
75 | |
76 | static irqreturn_t adis_trigger_handler(int irq, void *p) | |
77 | { | |
78 | struct iio_poll_func *pf = p; | |
79 | struct iio_dev *indio_dev = pf->indio_dev; | |
80 | struct adis *adis = iio_device_get_drvdata(indio_dev); | |
aacff892 | 81 | int ret; |
ccd2b52f | 82 | |
aacff892 | 83 | if (!adis->buffer) |
ccd2b52f | 84 | return -ENOMEM; |
ccd2b52f | 85 | |
484a0bf0 LPC |
86 | if (adis->data->has_paging) { |
87 | mutex_lock(&adis->txrx_lock); | |
88 | if (adis->current_page != 0) { | |
89 | adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); | |
90 | adis->tx[1] = 0; | |
91 | spi_write(adis->spi, adis->tx, 2); | |
92 | } | |
93 | } | |
94 | ||
aacff892 LPC |
95 | ret = spi_sync(adis->spi, &adis->msg); |
96 | if (ret) | |
97 | dev_err(&adis->spi->dev, "Failed to read data: %d", ret); | |
ccd2b52f | 98 | |
484a0bf0 LPC |
99 | |
100 | if (adis->data->has_paging) { | |
101 | adis->current_page = 0; | |
102 | mutex_unlock(&adis->txrx_lock); | |
103 | } | |
104 | ||
419d8ce4 LPC |
105 | iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, |
106 | pf->timestamp); | |
ccd2b52f LPC |
107 | |
108 | iio_trigger_notify_done(indio_dev->trig); | |
ccd2b52f LPC |
109 | |
110 | return IRQ_HANDLED; | |
111 | } | |
112 | ||
ccd2b52f LPC |
113 | /** |
114 | * adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device | |
115 | * @adis: The adis device. | |
116 | * @indio_dev: The IIO device. | |
117 | * @trigger_handler: Optional trigger handler, may be NULL. | |
118 | * | |
119 | * Returns 0 on success, a negative error code otherwise. | |
120 | * | |
121 | * This function sets up the buffer and trigger for a adis devices. If | |
122 | * 'trigger_handler' is NULL the default trigger handler will be used. The | |
123 | * default trigger handler will simply read the registers assigned to the | |
124 | * currently active channels. | |
125 | * | |
126 | * adis_cleanup_buffer_and_trigger() should be called to free the resources | |
127 | * allocated by this function. | |
128 | */ | |
129 | int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, | |
130 | irqreturn_t (*trigger_handler)(int, void *)) | |
131 | { | |
132 | int ret; | |
133 | ||
a458c55c LPC |
134 | if (!trigger_handler) |
135 | trigger_handler = adis_trigger_handler; | |
136 | ||
137 | ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | |
138 | trigger_handler, NULL); | |
ccd2b52f LPC |
139 | if (ret) |
140 | return ret; | |
141 | ||
ccd2b52f LPC |
142 | if (adis->spi->irq) { |
143 | ret = adis_probe_trigger(adis, indio_dev); | |
144 | if (ret) | |
a458c55c | 145 | goto error_buffer_cleanup; |
ccd2b52f LPC |
146 | } |
147 | return 0; | |
148 | ||
a458c55c LPC |
149 | error_buffer_cleanup: |
150 | iio_triggered_buffer_cleanup(indio_dev); | |
ccd2b52f LPC |
151 | return ret; |
152 | } | |
153 | EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger); | |
154 | ||
155 | /** | |
156 | * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources | |
157 | * @adis: The adis device. | |
158 | * @indio_dev: The IIO device. | |
159 | * | |
160 | * Frees resources allocated by adis_setup_buffer_and_trigger() | |
161 | */ | |
162 | void adis_cleanup_buffer_and_trigger(struct adis *adis, | |
163 | struct iio_dev *indio_dev) | |
164 | { | |
165 | if (adis->spi->irq) | |
166 | adis_remove_trigger(adis); | |
aacff892 LPC |
167 | kfree(adis->buffer); |
168 | kfree(adis->xfer); | |
a458c55c | 169 | iio_triggered_buffer_cleanup(indio_dev); |
ccd2b52f LPC |
170 | } |
171 | EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger); |