blob: 280a49584adf372f1d625b1a20838f698d535c4e [file] [log] [blame]
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +00001/*
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/delay.h>
11#include <linux/mutex.h>
12#include <linux/device.h>
13#include <linux/kernel.h>
14#include <linux/spi/spi.h>
15#include <linux/slab.h>
16#include <linux/sysfs.h>
17#include <linux/module.h>
18#include <asm/unaligned.h>
19
20#include <linux/iio/iio.h>
21#include <linux/iio/sysfs.h>
22#include <linux/iio/buffer.h>
Lars-Peter Clausenec04cb02012-11-13 13:28:00 +000023#include <linux/iio/imu/adis.h>
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000024
25#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2)
26#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1)
27#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
28#define ADIS_GLOB_CMD_SW_RESET BIT(7)
29
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000030int adis_write_reg(struct adis *adis, unsigned int reg,
31 unsigned int value, unsigned int size)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000032{
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000033 int ret, i;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000034 struct spi_message msg;
35 struct spi_transfer xfers[] = {
36 {
37 .tx_buf = adis->tx,
38 .bits_per_word = 8,
39 .len = 2,
40 .cs_change = 1,
41 .delay_usecs = adis->data->write_delay,
42 }, {
43 .tx_buf = adis->tx + 2,
44 .bits_per_word = 8,
45 .len = 2,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000046 .cs_change = 1,
47 .delay_usecs = adis->data->write_delay,
48 }, {
49 .tx_buf = adis->tx + 4,
50 .bits_per_word = 8,
51 .len = 2,
52 .cs_change = 1,
53 .delay_usecs = adis->data->write_delay,
54 }, {
55 .tx_buf = adis->tx + 6,
56 .bits_per_word = 8,
57 .len = 2,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000058 .delay_usecs = adis->data->write_delay,
59 },
60 };
61
62 mutex_lock(&adis->txrx_lock);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000063
64 spi_message_init(&msg);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000065 switch (size) {
66 case 4:
67 adis->tx[6] = ADIS_WRITE_REG(reg + 3);
68 adis->tx[7] = (value >> 24) & 0xff;
69 adis->tx[4] = ADIS_WRITE_REG(reg + 2);
70 adis->tx[5] = (value >> 16) & 0xff;
71 case 2:
72 adis->tx[2] = ADIS_WRITE_REG(reg + 1);
73 adis->tx[3] = (value >> 8) & 0xff;
74 case 1:
75 adis->tx[0] = ADIS_WRITE_REG(reg);
76 adis->tx[1] = value & 0xff;
77 break;
78 default:
79 ret = -EINVAL;
80 goto out_unlock;
81 }
82
83 xfers[size - 1].cs_change = 0;
84
85 for (i = 0; i < size; i++)
86 spi_message_add_tail(&xfers[i], &msg);
87
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000088 ret = spi_sync(adis->spi, &msg);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000089 if (ret) {
90 dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
91 reg, ret);
92 }
93
94out_unlock:
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000095 mutex_unlock(&adis->txrx_lock);
96
97 return ret;
98}
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000099EXPORT_SYMBOL_GPL(adis_write_reg);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000100
101/**
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000102 * adis_read_reg() - read 2 bytes from a 16-bit register
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000103 * @adis: The adis device
104 * @reg: The address of the lower of the two registers
105 * @val: The value read back from the device
106 */
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000107int adis_read_reg(struct adis *adis, unsigned int reg,
108 unsigned int *val, unsigned int size)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000109{
110 struct spi_message msg;
111 int ret;
112 struct spi_transfer xfers[] = {
113 {
114 .tx_buf = adis->tx,
115 .bits_per_word = 8,
116 .len = 2,
117 .cs_change = 1,
118 .delay_usecs = adis->data->read_delay,
119 }, {
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000120 .tx_buf = adis->tx + 2,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000121 .rx_buf = adis->rx,
122 .bits_per_word = 8,
123 .len = 2,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000124 .cs_change = 1,
125 .delay_usecs = adis->data->read_delay,
126 }, {
127 .rx_buf = adis->rx + 2,
128 .bits_per_word = 8,
129 .len = 2,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000130 .delay_usecs = adis->data->read_delay,
131 },
132 };
133
134 mutex_lock(&adis->txrx_lock);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000135 spi_message_init(&msg);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000136
137 switch (size) {
138 case 4:
139 adis->tx[0] = ADIS_READ_REG(reg + 2);
140 adis->tx[1] = 0;
141 spi_message_add_tail(&xfers[0], &msg);
142 case 2:
143 adis->tx[2] = ADIS_READ_REG(reg);
144 adis->tx[3] = 0;
145 spi_message_add_tail(&xfers[1], &msg);
146 spi_message_add_tail(&xfers[2], &msg);
147 break;
148 default:
149 ret = -EINVAL;
150 goto out_unlock;
151 }
152
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000153 ret = spi_sync(adis->spi, &msg);
154 if (ret) {
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000155 dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000156 reg, ret);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000157 goto out_unlock;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000158 }
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000159
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000160 switch (size) {
161 case 4:
162 *val = get_unaligned_be32(adis->rx);
163 break;
164 case 2:
165 *val = get_unaligned_be16(adis->rx + 2);
166 break;
167 }
168
169out_unlock:
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000170 mutex_unlock(&adis->txrx_lock);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000171
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000172 return ret;
173}
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000174EXPORT_SYMBOL_GPL(adis_read_reg);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000175
Lars-Peter Clausen78026a62012-11-20 13:36:00 +0000176#ifdef CONFIG_DEBUG_FS
177
178int adis_debugfs_reg_access(struct iio_dev *indio_dev,
179 unsigned int reg, unsigned int writeval, unsigned int *readval)
180{
181 struct adis *adis = iio_device_get_drvdata(indio_dev);
182
183 if (readval) {
184 uint16_t val16;
185 int ret;
186
187 ret = adis_read_reg_16(adis, reg, &val16);
188 *readval = val16;
189
190 return ret;
191 } else {
192 return adis_write_reg_16(adis, reg, writeval);
193 }
194}
195EXPORT_SYMBOL(adis_debugfs_reg_access);
196
197#endif
198
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000199/**
200 * adis_enable_irq() - Enable or disable data ready IRQ
201 * @adis: The adis device
202 * @enable: Whether to enable the IRQ
203 *
204 * Returns 0 on success, negative error code otherwise
205 */
206int adis_enable_irq(struct adis *adis, bool enable)
207{
208 int ret = 0;
209 uint16_t msc;
210
211 ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
212 if (ret)
213 goto error_ret;
214
215 msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
216 msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
217 if (enable)
218 msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
219 else
220 msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
221
222 ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
223
224error_ret:
225 return ret;
226}
227EXPORT_SYMBOL(adis_enable_irq);
228
229/**
230 * adis_check_status() - Check the device for error conditions
231 * @adis: The adis device
232 *
233 * Returns 0 on success, a negative error code otherwise
234 */
235int adis_check_status(struct adis *adis)
236{
237 uint16_t status;
238 int ret;
239 int i;
240
241 ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
242 if (ret < 0)
243 return ret;
244
245 status &= adis->data->status_error_mask;
246
247 if (status == 0)
248 return 0;
249
250 for (i = 0; i < 16; ++i) {
251 if (status & BIT(i)) {
252 dev_err(&adis->spi->dev, "%s.\n",
253 adis->data->status_error_msgs[i]);
254 }
255 }
256
257 return -EIO;
258}
259EXPORT_SYMBOL_GPL(adis_check_status);
260
261/**
262 * adis_reset() - Reset the device
263 * @adis: The adis device
264 *
265 * Returns 0 on success, a negative error code otherwise
266 */
267int adis_reset(struct adis *adis)
268{
269 int ret;
270
271 ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
272 ADIS_GLOB_CMD_SW_RESET);
273 if (ret)
274 dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
275
276 return ret;
277}
278EXPORT_SYMBOL_GPL(adis_reset);
279
280static int adis_self_test(struct adis *adis)
281{
282 int ret;
283
284 ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
285 adis->data->self_test_mask);
286 if (ret) {
287 dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
288 ret);
289 return ret;
290 }
291
292 msleep(adis->data->startup_delay);
293
294 return adis_check_status(adis);
295}
296
297/**
298 * adis_inital_startup() - Performs device self-test
299 * @adis: The adis device
300 *
301 * Returns 0 if the device is operational, a negative error code otherwise.
302 *
303 * This function should be called early on in the device initialization sequence
304 * to ensure that the device is in a sane and known state and that it is usable.
305 */
306int adis_initial_startup(struct adis *adis)
307{
308 int ret;
309
310 ret = adis_self_test(adis);
311 if (ret) {
312 dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
313 adis_reset(adis);
314 msleep(adis->data->startup_delay);
315 ret = adis_self_test(adis);
316 if (ret) {
317 dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
318 return ret;
319 }
320 }
321
322 return 0;
323}
324EXPORT_SYMBOL_GPL(adis_initial_startup);
325
326/**
327 * adis_single_conversion() - Performs a single sample conversion
328 * @indio_dev: The IIO device
329 * @chan: The IIO channel
330 * @error_mask: Mask for the error bit
331 * @val: Result of the conversion
332 *
333 * Returns IIO_VAL_INT on success, a negative error code otherwise.
334 *
335 * The function performs a single conversion on a given channel and post
336 * processes the value accordingly to the channel spec. If a error_mask is given
337 * the function will check if the mask is set in the returned raw value. If it
338 * is set the function will perform a self-check. If the device does not report
339 * a error bit in the channels raw value set error_mask to 0.
340 */
341int adis_single_conversion(struct iio_dev *indio_dev,
342 const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
343{
344 struct adis *adis = iio_device_get_drvdata(indio_dev);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000345 unsigned int uval;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000346 int ret;
347
348 mutex_lock(&indio_dev->mlock);
349
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000350 ret = adis_read_reg(adis, chan->address, &uval,
351 chan->scan_type.storagebits / 8);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000352 if (ret)
353 goto err_unlock;
354
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000355 if (uval & error_mask) {
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000356 ret = adis_check_status(adis);
357 if (ret)
358 goto err_unlock;
359 }
360
361 if (chan->scan_type.sign == 's')
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000362 *val = sign_extend32(uval, chan->scan_type.realbits - 1);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000363 else
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000364 *val = uval & ((1 << chan->scan_type.realbits) - 1);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000365
366 ret = IIO_VAL_INT;
367err_unlock:
368 mutex_unlock(&indio_dev->mlock);
369 return ret;
370}
371EXPORT_SYMBOL_GPL(adis_single_conversion);
372
373/**
374 * adis_init() - Initialize adis device structure
375 * @adis: The adis device
376 * @indio_dev: The iio device
377 * @spi: The spi device
378 * @data: Chip specific data
379 *
380 * Returns 0 on success, a negative error code otherwise.
381 *
382 * This function must be called, before any other adis helper function may be
383 * called.
384 */
385int adis_init(struct adis *adis, struct iio_dev *indio_dev,
386 struct spi_device *spi, const struct adis_data *data)
387{
388 mutex_init(&adis->txrx_lock);
389 adis->spi = spi;
390 adis->data = data;
391 iio_device_set_drvdata(indio_dev, adis);
392
393 return adis_enable_irq(adis, false);
394}
395EXPORT_SYMBOL_GPL(adis_init);
396
397MODULE_LICENSE("GPL");
398MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
399MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");