aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/imu
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2012-11-20 08:36:00 -0500
committerJonathan Cameron <jic23@kernel.org>2012-11-20 16:28:51 -0500
commit2f3abe6cbb6c963ac790b40936b6761c9f0497b4 (patch)
tree1050db75a5d9c8040c500e10e5a308ab5d2ed5df /drivers/iio/imu
parent6807d7211327dbdd8df3692f3d26ca711514ba71 (diff)
iio:imu: Add support for the ADIS16480 and similar IMUs
This patch adds support for the ADIS16375, ADIS16480, ADIS16485, ADIS16488 6 degree to 10 degree of freedom IMUs. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/imu')
-rw-r--r--drivers/iio/imu/Kconfig16
-rw-r--r--drivers/iio/imu/Makefile2
-rw-r--r--drivers/iio/imu/adis.c3
-rw-r--r--drivers/iio/imu/adis16480.c925
4 files changed, 946 insertions, 0 deletions
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index c24410c873c7..3d79a40e916b 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -1,3 +1,19 @@
1#
2# IIO imu drivers configuration
3#
4menu "Inertial measurement units"
5
6config ADIS16480
7 tristate "Analog Devices ADIS16480 and similar IMU driver"
8 depends on SPI
9 select IIO_ADIS_LIB
10 select IIO_ADIS_LIB_BUFFER if IIO_BUFFER
11 help
12 Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
13 ADIS16485, ADIS16488 inertial sensors.
14
15endmenu
16
1config IIO_ADIS_LIB 17config IIO_ADIS_LIB
2 tristate 18 tristate
3 help 19 help
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 97676ab5723d..cfe57638f6f9 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -2,6 +2,8 @@
2# Makefile for Inertial Measurement Units 2# Makefile for Inertial Measurement Units
3# 3#
4 4
5obj-$(CONFIG_ADIS16480) += adis16480.o
6
5adis_lib-y += adis.o 7adis_lib-y += adis.o
6adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o 8adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
7adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o 9adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c
index c4ea04ffa60e..911255d41c1a 100644
--- a/drivers/iio/imu/adis.c
+++ b/drivers/iio/imu/adis.c
@@ -238,6 +238,9 @@ int adis_enable_irq(struct adis *adis, bool enable)
238 int ret = 0; 238 int ret = 0;
239 uint16_t msc; 239 uint16_t msc;
240 240
241 if (adis->data->enable_irq)
242 return adis->data->enable_irq(adis, enable);
243
241 ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc); 244 ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
242 if (ret) 245 if (ret)
243 goto error_ret; 246 goto error_ret;
diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c
new file mode 100644
index 000000000000..a080b3515015
--- /dev/null
+++ b/drivers/iio/imu/adis16480.c
@@ -0,0 +1,925 @@
1/*
2 * ADIS16480 and similar IMUs driver
3 *
4 * Copyright 2012 Analog Devices Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/interrupt.h>
13#include <linux/delay.h>
14#include <linux/mutex.h>
15#include <linux/device.h>
16#include <linux/kernel.h>
17#include <linux/spi/spi.h>
18#include <linux/slab.h>
19#include <linux/sysfs.h>
20#include <linux/module.h>
21
22#include <linux/iio/iio.h>
23#include <linux/iio/sysfs.h>
24#include <linux/iio/buffer.h>
25#include <linux/iio/imu/adis.h>
26
27#include <linux/iio/iio.h>
28#include <linux/debugfs.h>
29
30#define ADIS16480_PAGE_SIZE 0x80
31
32#define ADIS16480_REG(page, reg) ((page) * ADIS16480_PAGE_SIZE + (reg))
33
34#define ADIS16480_REG_PAGE_ID 0x00 /* Same address on each page */
35#define ADIS16480_REG_SEQ_CNT ADIS16480_REG(0x00, 0x06)
36#define ADIS16480_REG_SYS_E_FLA ADIS16480_REG(0x00, 0x08)
37#define ADIS16480_REG_DIAG_STS ADIS16480_REG(0x00, 0x0A)
38#define ADIS16480_REG_ALM_STS ADIS16480_REG(0x00, 0x0C)
39#define ADIS16480_REG_TEMP_OUT ADIS16480_REG(0x00, 0x0E)
40#define ADIS16480_REG_X_GYRO_OUT ADIS16480_REG(0x00, 0x10)
41#define ADIS16480_REG_Y_GYRO_OUT ADIS16480_REG(0x00, 0x14)
42#define ADIS16480_REG_Z_GYRO_OUT ADIS16480_REG(0x00, 0x18)
43#define ADIS16480_REG_X_ACCEL_OUT ADIS16480_REG(0x00, 0x1C)
44#define ADIS16480_REG_Y_ACCEL_OUT ADIS16480_REG(0x00, 0x20)
45#define ADIS16480_REG_Z_ACCEL_OUT ADIS16480_REG(0x00, 0x24)
46#define ADIS16480_REG_X_MAGN_OUT ADIS16480_REG(0x00, 0x28)
47#define ADIS16480_REG_Y_MAGN_OUT ADIS16480_REG(0x00, 0x2A)
48#define ADIS16480_REG_Z_MAGN_OUT ADIS16480_REG(0x00, 0x2C)
49#define ADIS16480_REG_BAROM_OUT ADIS16480_REG(0x00, 0x2E)
50#define ADIS16480_REG_X_DELTAANG_OUT ADIS16480_REG(0x00, 0x40)
51#define ADIS16480_REG_Y_DELTAANG_OUT ADIS16480_REG(0x00, 0x44)
52#define ADIS16480_REG_Z_DELTAANG_OUT ADIS16480_REG(0x00, 0x48)
53#define ADIS16480_REG_X_DELTAVEL_OUT ADIS16480_REG(0x00, 0x4C)
54#define ADIS16480_REG_Y_DELTAVEL_OUT ADIS16480_REG(0x00, 0x50)
55#define ADIS16480_REG_Z_DELTAVEL_OUT ADIS16480_REG(0x00, 0x54)
56#define ADIS16480_REG_PROD_ID ADIS16480_REG(0x00, 0x7E)
57
58#define ADIS16480_REG_X_GYRO_SCALE ADIS16480_REG(0x02, 0x04)
59#define ADIS16480_REG_Y_GYRO_SCALE ADIS16480_REG(0x02, 0x06)
60#define ADIS16480_REG_Z_GYRO_SCALE ADIS16480_REG(0x02, 0x08)
61#define ADIS16480_REG_X_ACCEL_SCALE ADIS16480_REG(0x02, 0x0A)
62#define ADIS16480_REG_Y_ACCEL_SCALE ADIS16480_REG(0x02, 0x0C)
63#define ADIS16480_REG_Z_ACCEL_SCALE ADIS16480_REG(0x02, 0x0E)
64#define ADIS16480_REG_X_GYRO_BIAS ADIS16480_REG(0x02, 0x10)
65#define ADIS16480_REG_Y_GYRO_BIAS ADIS16480_REG(0x02, 0x14)
66#define ADIS16480_REG_Z_GYRO_BIAS ADIS16480_REG(0x02, 0x18)
67#define ADIS16480_REG_X_ACCEL_BIAS ADIS16480_REG(0x02, 0x1C)
68#define ADIS16480_REG_Y_ACCEL_BIAS ADIS16480_REG(0x02, 0x20)
69#define ADIS16480_REG_Z_ACCEL_BIAS ADIS16480_REG(0x02, 0x24)
70#define ADIS16480_REG_X_HARD_IRON ADIS16480_REG(0x02, 0x28)
71#define ADIS16480_REG_Y_HARD_IRON ADIS16480_REG(0x02, 0x2A)
72#define ADIS16480_REG_Z_HARD_IRON ADIS16480_REG(0x02, 0x2C)
73#define ADIS16480_REG_BAROM_BIAS ADIS16480_REG(0x02, 0x40)
74#define ADIS16480_REG_FLASH_CNT ADIS16480_REG(0x02, 0x7C)
75
76#define ADIS16480_REG_GLOB_CMD ADIS16480_REG(0x03, 0x02)
77#define ADIS16480_REG_FNCTIO_CTRL ADIS16480_REG(0x03, 0x06)
78#define ADIS16480_REG_GPIO_CTRL ADIS16480_REG(0x03, 0x08)
79#define ADIS16480_REG_CONFIG ADIS16480_REG(0x03, 0x0A)
80#define ADIS16480_REG_DEC_RATE ADIS16480_REG(0x03, 0x0C)
81#define ADIS16480_REG_SLP_CNT ADIS16480_REG(0x03, 0x10)
82#define ADIS16480_REG_FILTER_BNK0 ADIS16480_REG(0x03, 0x16)
83#define ADIS16480_REG_FILTER_BNK1 ADIS16480_REG(0x03, 0x18)
84#define ADIS16480_REG_ALM_CNFG0 ADIS16480_REG(0x03, 0x20)
85#define ADIS16480_REG_ALM_CNFG1 ADIS16480_REG(0x03, 0x22)
86#define ADIS16480_REG_ALM_CNFG2 ADIS16480_REG(0x03, 0x24)
87#define ADIS16480_REG_XG_ALM_MAGN ADIS16480_REG(0x03, 0x28)
88#define ADIS16480_REG_YG_ALM_MAGN ADIS16480_REG(0x03, 0x2A)
89#define ADIS16480_REG_ZG_ALM_MAGN ADIS16480_REG(0x03, 0x2C)
90#define ADIS16480_REG_XA_ALM_MAGN ADIS16480_REG(0x03, 0x2E)
91#define ADIS16480_REG_YA_ALM_MAGN ADIS16480_REG(0x03, 0x30)
92#define ADIS16480_REG_ZA_ALM_MAGN ADIS16480_REG(0x03, 0x32)
93#define ADIS16480_REG_XM_ALM_MAGN ADIS16480_REG(0x03, 0x34)
94#define ADIS16480_REG_YM_ALM_MAGN ADIS16480_REG(0x03, 0x36)
95#define ADIS16480_REG_ZM_ALM_MAGN ADIS16480_REG(0x03, 0x38)
96#define ADIS16480_REG_BR_ALM_MAGN ADIS16480_REG(0x03, 0x3A)
97#define ADIS16480_REG_FIRM_REV ADIS16480_REG(0x03, 0x78)
98#define ADIS16480_REG_FIRM_DM ADIS16480_REG(0x03, 0x7A)
99#define ADIS16480_REG_FIRM_Y ADIS16480_REG(0x03, 0x7C)
100
101#define ADIS16480_REG_SERIAL_NUM ADIS16480_REG(0x04, 0x20)
102
103/* Each filter coefficent bank spans two pages */
104#define ADIS16480_FIR_COEF(page) (x < 60 ? ADIS16480_REG(page, (x) + 8) : \
105 ADIS16480_REG((page) + 1, (x) - 60 + 8))
106#define ADIS16480_FIR_COEF_A(x) ADIS16480_FIR_COEF(0x05, (x))
107#define ADIS16480_FIR_COEF_B(x) ADIS16480_FIR_COEF(0x07, (x))
108#define ADIS16480_FIR_COEF_C(x) ADIS16480_FIR_COEF(0x09, (x))
109#define ADIS16480_FIR_COEF_D(x) ADIS16480_FIR_COEF(0x0B, (x))
110
111struct adis16480_chip_info {
112 unsigned int num_channels;
113 const struct iio_chan_spec *channels;
114};
115
116struct adis16480 {
117 const struct adis16480_chip_info *chip_info;
118
119 struct adis adis;
120};
121
122#ifdef CONFIG_DEBUG_FS
123
124static ssize_t adis16480_show_firmware_revision(struct file *file,
125 char __user *userbuf, size_t count, loff_t *ppos)
126{
127 struct adis16480 *adis16480 = file->private_data;
128 char buf[6];
129 size_t len;
130 u16 rev;
131 int ret;
132
133 ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_REV, &rev);
134 if (ret < 0)
135 return ret;
136
137 len = snprintf(buf, sizeof(buf), "%x.%x\n", rev >> 8, rev & 0xff);
138
139 return simple_read_from_buffer(userbuf, count, ppos, buf, len);
140}
141
142static const struct file_operations adis16480_firmware_revision_fops = {
143 .open = simple_open,
144 .read = adis16480_show_firmware_revision,
145 .llseek = default_llseek,
146 .owner = THIS_MODULE,
147};
148
149static ssize_t adis16480_show_firmware_date(struct file *file,
150 char __user *userbuf, size_t count, loff_t *ppos)
151{
152 struct adis16480 *adis16480 = file->private_data;
153 u16 md, year;
154 char buf[12];
155 size_t len;
156 int ret;
157
158 ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_Y, &year);
159 if (ret < 0)
160 return ret;
161
162 ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_FIRM_DM, &md);
163 if (ret < 0)
164 return ret;
165
166 len = snprintf(buf, sizeof(buf), "%.2x-%.2x-%.4x\n",
167 md >> 8, md & 0xff, year);
168
169 return simple_read_from_buffer(userbuf, count, ppos, buf, len);
170}
171
172static const struct file_operations adis16480_firmware_date_fops = {
173 .open = simple_open,
174 .read = adis16480_show_firmware_date,
175 .llseek = default_llseek,
176 .owner = THIS_MODULE,
177};
178
179static int adis16480_show_serial_number(void *arg, u64 *val)
180{
181 struct adis16480 *adis16480 = arg;
182 u16 serial;
183 int ret;
184
185 ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_SERIAL_NUM,
186 &serial);
187 if (ret < 0)
188 return ret;
189
190 *val = serial;
191
192 return 0;
193}
194DEFINE_SIMPLE_ATTRIBUTE(adis16480_serial_number_fops,
195 adis16480_show_serial_number, NULL, "0x%.4llx\n");
196
197static int adis16480_show_product_id(void *arg, u64 *val)
198{
199 struct adis16480 *adis16480 = arg;
200 u16 prod_id;
201 int ret;
202
203 ret = adis_read_reg_16(&adis16480->adis, ADIS16480_REG_PROD_ID,
204 &prod_id);
205 if (ret < 0)
206 return ret;
207
208 *val = prod_id;
209
210 return 0;
211}
212DEFINE_SIMPLE_ATTRIBUTE(adis16480_product_id_fops,
213 adis16480_show_product_id, NULL, "%llu\n");
214
215static int adis16480_show_flash_count(void *arg, u64 *val)
216{
217 struct adis16480 *adis16480 = arg;
218 u32 flash_count;
219 int ret;
220
221 ret = adis_read_reg_32(&adis16480->adis, ADIS16480_REG_FLASH_CNT,
222 &flash_count);
223 if (ret < 0)
224 return ret;
225
226 *val = flash_count;
227
228 return 0;
229}
230DEFINE_SIMPLE_ATTRIBUTE(adis16480_flash_count_fops,
231 adis16480_show_flash_count, NULL, "%lld\n");
232
233static int adis16480_debugfs_init(struct iio_dev *indio_dev)
234{
235 struct adis16480 *adis16480 = iio_priv(indio_dev);
236
237 debugfs_create_file("firmware_revision", 0400,
238 indio_dev->debugfs_dentry, adis16480,
239 &adis16480_firmware_revision_fops);
240 debugfs_create_file("firmware_date", 0400, indio_dev->debugfs_dentry,
241 adis16480, &adis16480_firmware_date_fops);
242 debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry,
243 adis16480, &adis16480_serial_number_fops);
244 debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry,
245 adis16480, &adis16480_product_id_fops);
246 debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry,
247 adis16480, &adis16480_flash_count_fops);
248
249 return 0;
250}
251
252#else
253
254static int adis16480_debugfs_init(struct iio_dev *indio_dev)
255{
256 return 0;
257}
258
259#endif
260
261static int adis16480_set_freq(struct adis16480 *st, unsigned int freq)
262{
263 unsigned int t;
264
265 t = 2460000 / freq;
266 if (t > 2048)
267 t = 2048;
268
269 if (t != 0)
270 t--;
271
272 return adis_write_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, t);
273}
274
275static int adis16480_get_freq(struct adis16480 *st, unsigned int *freq)
276{
277 uint16_t t;
278 int ret;
279
280 ret = adis_read_reg_16(&st->adis, ADIS16480_REG_DEC_RATE, &t);
281 if (ret < 0)
282 return ret;
283
284 *freq = 2460000 / (t + 1);
285
286 return 0;
287}
288
289static ssize_t adis16480_read_frequency(struct device *dev,
290 struct device_attribute *attr,
291 char *buf)
292{
293 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
294 struct adis16480 *st = iio_priv(indio_dev);
295 unsigned int freq;
296 int ret;
297
298 ret = adis16480_get_freq(st, &freq);
299 if (ret < 0)
300 return ret;
301
302 return sprintf(buf, "%d.%.3d\n", freq / 1000, freq % 1000);
303}
304
305static ssize_t adis16480_write_frequency(struct device *dev,
306 struct device_attribute *attr,
307 const char *buf,
308 size_t len)
309{
310 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
311 struct adis16480 *st = iio_priv(indio_dev);
312 int freq_int, freq_fract;
313 long val;
314 int ret;
315
316 ret = iio_str_to_fixpoint(buf, 100, &freq_int, &freq_fract);
317 if (ret)
318 return ret;
319
320 val = freq_int * 1000 + freq_fract;
321
322 if (val <= 0)
323 return -EINVAL;
324
325 ret = adis16480_set_freq(st, val);
326
327 return ret ? ret : len;
328}
329
330static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
331 adis16480_read_frequency,
332 adis16480_write_frequency);
333
334enum {
335 ADIS16480_SCAN_GYRO_X,
336 ADIS16480_SCAN_GYRO_Y,
337 ADIS16480_SCAN_GYRO_Z,
338 ADIS16480_SCAN_ACCEL_X,
339 ADIS16480_SCAN_ACCEL_Y,
340 ADIS16480_SCAN_ACCEL_Z,
341 ADIS16480_SCAN_MAGN_X,
342 ADIS16480_SCAN_MAGN_Y,
343 ADIS16480_SCAN_MAGN_Z,
344 ADIS16480_SCAN_BARO,
345 ADIS16480_SCAN_TEMP,
346};
347
348static const unsigned int adis16480_calibbias_regs[] = {
349 [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_BIAS,
350 [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_BIAS,
351 [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_BIAS,
352 [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_BIAS,
353 [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_BIAS,
354 [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_BIAS,
355 [ADIS16480_SCAN_MAGN_X] = ADIS16480_REG_X_HARD_IRON,
356 [ADIS16480_SCAN_MAGN_Y] = ADIS16480_REG_Y_HARD_IRON,
357 [ADIS16480_SCAN_MAGN_Z] = ADIS16480_REG_Z_HARD_IRON,
358 [ADIS16480_SCAN_BARO] = ADIS16480_REG_BAROM_BIAS,
359};
360
361static const unsigned int adis16480_calibscale_regs[] = {
362 [ADIS16480_SCAN_GYRO_X] = ADIS16480_REG_X_GYRO_SCALE,
363 [ADIS16480_SCAN_GYRO_Y] = ADIS16480_REG_Y_GYRO_SCALE,
364 [ADIS16480_SCAN_GYRO_Z] = ADIS16480_REG_Z_GYRO_SCALE,
365 [ADIS16480_SCAN_ACCEL_X] = ADIS16480_REG_X_ACCEL_SCALE,
366 [ADIS16480_SCAN_ACCEL_Y] = ADIS16480_REG_Y_ACCEL_SCALE,
367 [ADIS16480_SCAN_ACCEL_Z] = ADIS16480_REG_Z_ACCEL_SCALE,
368};
369
370static int adis16480_set_calibbias(struct iio_dev *indio_dev,
371 const struct iio_chan_spec *chan, int bias)
372{
373 unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
374 struct adis16480 *st = iio_priv(indio_dev);
375
376 switch (chan->type) {
377 case IIO_MAGN:
378 case IIO_PRESSURE:
379 if (bias < -0x8000 || bias >= 0x8000)
380 return -EINVAL;
381 return adis_write_reg_16(&st->adis, reg, bias);
382 case IIO_ANGL_VEL:
383 case IIO_ACCEL:
384 return adis_write_reg_32(&st->adis, reg, bias);
385 default:
386 break;
387 }
388
389 return -EINVAL;
390}
391
392static int adis16480_get_calibbias(struct iio_dev *indio_dev,
393 const struct iio_chan_spec *chan, int *bias)
394{
395 unsigned int reg = adis16480_calibbias_regs[chan->scan_index];
396 struct adis16480 *st = iio_priv(indio_dev);
397 uint16_t val16;
398 uint32_t val32;
399 int ret;
400
401 switch (chan->type) {
402 case IIO_MAGN:
403 case IIO_PRESSURE:
404 ret = adis_read_reg_16(&st->adis, reg, &val16);
405 *bias = sign_extend32(val16, 15);
406 break;
407 case IIO_ANGL_VEL:
408 case IIO_ACCEL:
409 ret = adis_read_reg_32(&st->adis, reg, &val32);
410 *bias = sign_extend32(val32, 31);
411 break;
412 default:
413 ret = -EINVAL;
414 }
415
416 if (ret < 0)
417 return ret;
418
419 return IIO_VAL_INT;
420}
421
422static int adis16480_set_calibscale(struct iio_dev *indio_dev,
423 const struct iio_chan_spec *chan, int scale)
424{
425 unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
426 struct adis16480 *st = iio_priv(indio_dev);
427
428 if (scale < -0x8000 || scale >= 0x8000)
429 return -EINVAL;
430
431 return adis_write_reg_16(&st->adis, reg, scale);
432}
433
434static int adis16480_get_calibscale(struct iio_dev *indio_dev,
435 const struct iio_chan_spec *chan, int *scale)
436{
437 unsigned int reg = adis16480_calibscale_regs[chan->scan_index];
438 struct adis16480 *st = iio_priv(indio_dev);
439 uint16_t val16;
440 int ret;
441
442 ret = adis_read_reg_16(&st->adis, reg, &val16);
443 if (ret < 0)
444 return ret;
445
446 *scale = sign_extend32(val16, 15);
447 return IIO_VAL_INT;
448}
449
450static const unsigned int adis16480_def_filter_freqs[] = {
451 310,
452 55,
453 275,
454 63,
455};
456
457static const unsigned int ad16480_filter_data[][2] = {
458 [ADIS16480_SCAN_GYRO_X] = { ADIS16480_REG_FILTER_BNK0, 0 },
459 [ADIS16480_SCAN_GYRO_Y] = { ADIS16480_REG_FILTER_BNK0, 3 },
460 [ADIS16480_SCAN_GYRO_Z] = { ADIS16480_REG_FILTER_BNK0, 6 },
461 [ADIS16480_SCAN_ACCEL_X] = { ADIS16480_REG_FILTER_BNK0, 9 },
462 [ADIS16480_SCAN_ACCEL_Y] = { ADIS16480_REG_FILTER_BNK0, 12 },
463 [ADIS16480_SCAN_ACCEL_Z] = { ADIS16480_REG_FILTER_BNK1, 0 },
464 [ADIS16480_SCAN_MAGN_X] = { ADIS16480_REG_FILTER_BNK1, 3 },
465 [ADIS16480_SCAN_MAGN_Y] = { ADIS16480_REG_FILTER_BNK1, 6 },
466 [ADIS16480_SCAN_MAGN_Z] = { ADIS16480_REG_FILTER_BNK1, 9 },
467};
468
469static int adis16480_get_filter_freq(struct iio_dev *indio_dev,
470 const struct iio_chan_spec *chan, int *freq)
471{
472 struct adis16480 *st = iio_priv(indio_dev);
473 unsigned int enable_mask, offset, reg;
474 uint16_t val;
475 int ret;
476
477 reg = ad16480_filter_data[chan->scan_index][0];
478 offset = ad16480_filter_data[chan->scan_index][1];
479 enable_mask = BIT(offset + 2);
480
481 ret = adis_read_reg_16(&st->adis, reg, &val);
482 if (ret < 0)
483 return ret;
484
485 if (!(val & enable_mask))
486 *freq = 0;
487 else
488 *freq = adis16480_def_filter_freqs[(val >> offset) & 0x3];
489
490 return IIO_VAL_INT;
491}
492
493static int adis16480_set_filter_freq(struct iio_dev *indio_dev,
494 const struct iio_chan_spec *chan, unsigned int freq)
495{
496 struct adis16480 *st = iio_priv(indio_dev);
497 unsigned int enable_mask, offset, reg;
498 unsigned int diff, best_diff;
499 unsigned int i, best_freq;
500 uint16_t val;
501 int ret;
502
503 reg = ad16480_filter_data[chan->scan_index][0];
504 offset = ad16480_filter_data[chan->scan_index][1];
505 enable_mask = BIT(offset + 2);
506
507 ret = adis_read_reg_16(&st->adis, reg, &val);
508 if (ret < 0)
509 return ret;
510
511 if (freq == 0) {
512 val &= ~enable_mask;
513 } else {
514 best_freq = 0;
515 best_diff = 310;
516 for (i = 0; i < ARRAY_SIZE(adis16480_def_filter_freqs); i++) {
517 if (adis16480_def_filter_freqs[i] >= freq) {
518 diff = adis16480_def_filter_freqs[i] - freq;
519 if (diff < best_diff) {
520 best_diff = diff;
521 best_freq = i;
522 }
523 }
524 }
525
526 val &= ~(0x3 << offset);
527 val |= best_freq << offset;
528 val |= enable_mask;
529 }
530
531 return adis_write_reg_16(&st->adis, reg, val);
532}
533
534static int adis16480_read_raw(struct iio_dev *indio_dev,
535 const struct iio_chan_spec *chan, int *val, int *val2, long info)
536{
537 switch (info) {
538 case IIO_CHAN_INFO_RAW:
539 return adis_single_conversion(indio_dev, chan, 0, val);
540 case IIO_CHAN_INFO_SCALE:
541 switch (chan->type) {
542 case IIO_ANGL_VEL:
543 *val = 0;
544 *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */
545 return IIO_VAL_INT_PLUS_MICRO;
546 case IIO_ACCEL:
547 *val = 0;
548 *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */
549 return IIO_VAL_INT_PLUS_MICRO;
550 case IIO_MAGN:
551 *val = 0;
552 *val2 = 100; /* 0.0001 gauss */
553 return IIO_VAL_INT_PLUS_MICRO;
554 case IIO_TEMP:
555 *val = 5;
556 *val2 = 650000; /* 5.65 milli degree Celsius */
557 return IIO_VAL_INT_PLUS_MICRO;
558 case IIO_PRESSURE:
559 *val = 0;
560 *val2 = 4000; /* 40ubar = 0.004 kPa */
561 return IIO_VAL_INT_PLUS_MICRO;
562 default:
563 return -EINVAL;
564 }
565 case IIO_CHAN_INFO_OFFSET:
566 /* Only the temperature channel has a offset */
567 *val = 4425; /* 25 degree Celsius = 0x0000 */
568 return IIO_VAL_INT;
569 case IIO_CHAN_INFO_CALIBBIAS:
570 return adis16480_get_calibbias(indio_dev, chan, val);
571 case IIO_CHAN_INFO_CALIBSCALE:
572 return adis16480_get_calibscale(indio_dev, chan, val);
573 case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
574 return adis16480_get_filter_freq(indio_dev, chan, val);
575 default:
576 return -EINVAL;
577 }
578}
579
580static int adis16480_write_raw(struct iio_dev *indio_dev,
581 const struct iio_chan_spec *chan, int val, int val2, long info)
582{
583 switch (info) {
584 case IIO_CHAN_INFO_CALIBBIAS:
585 return adis16480_set_calibbias(indio_dev, chan, val);
586 case IIO_CHAN_INFO_CALIBSCALE:
587 return adis16480_set_calibscale(indio_dev, chan, val);
588 case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
589 return adis16480_set_filter_freq(indio_dev, chan, val);
590 default:
591 return -EINVAL;
592 }
593}
594
595#define ADIS16480_MOD_CHANNEL(_type, _mod, _address, _si, _info, _bits) \
596 { \
597 .type = (_type), \
598 .modified = 1, \
599 .channel2 = (_mod), \
600 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
601 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
602 IIO_CHAN_INFO_SCALE_SHARED_BIT | \
603 _info, \
604 .address = (_address), \
605 .scan_index = (_si), \
606 .scan_type = { \
607 .sign = 's', \
608 .realbits = (_bits), \
609 .storagebits = (_bits), \
610 .endianness = IIO_BE, \
611 }, \
612 }
613
614#define ADIS16480_GYRO_CHANNEL(_mod) \
615 ADIS16480_MOD_CHANNEL(IIO_ANGL_VEL, IIO_MOD_ ## _mod, \
616 ADIS16480_REG_ ## _mod ## _GYRO_OUT, ADIS16480_SCAN_GYRO_ ## _mod, \
617 IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
618 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
619 32)
620
621#define ADIS16480_ACCEL_CHANNEL(_mod) \
622 ADIS16480_MOD_CHANNEL(IIO_ACCEL, IIO_MOD_ ## _mod, \
623 ADIS16480_REG_ ## _mod ## _ACCEL_OUT, ADIS16480_SCAN_ACCEL_ ## _mod, \
624 IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT | \
625 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, \
626 32)
627
628#define ADIS16480_MAGN_CHANNEL(_mod) \
629 ADIS16480_MOD_CHANNEL(IIO_MAGN, IIO_MOD_ ## _mod, \
630 ADIS16480_REG_ ## _mod ## _MAGN_OUT, ADIS16480_SCAN_MAGN_ ## _mod, \
631 IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, \
632 16)
633
634#define ADIS16480_PRESSURE_CHANNEL() \
635 { \
636 .type = IIO_PRESSURE, \
637 .indexed = 1, \
638 .channel = 0, \
639 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
640 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
641 IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
642 .address = ADIS16480_REG_BAROM_OUT, \
643 .scan_index = ADIS16480_SCAN_BARO, \
644 .scan_type = { \
645 .sign = 's', \
646 .realbits = 32, \
647 .storagebits = 32, \
648 .endianness = IIO_BE, \
649 }, \
650 }
651
652#define ADIS16480_TEMP_CHANNEL() { \
653 .type = IIO_TEMP, \
654 .indexed = 1, \
655 .channel = 0, \
656 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
657 IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
658 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \
659 .address = ADIS16480_REG_TEMP_OUT, \
660 .scan_index = ADIS16480_SCAN_TEMP, \
661 .scan_type = { \
662 .sign = 's', \
663 .realbits = 16, \
664 .storagebits = 16, \
665 .endianness = IIO_BE, \
666 }, \
667 }
668
669static const struct iio_chan_spec adis16480_channels[] = {
670 ADIS16480_GYRO_CHANNEL(X),
671 ADIS16480_GYRO_CHANNEL(Y),
672 ADIS16480_GYRO_CHANNEL(Z),
673 ADIS16480_ACCEL_CHANNEL(X),
674 ADIS16480_ACCEL_CHANNEL(Y),
675 ADIS16480_ACCEL_CHANNEL(Z),
676 ADIS16480_MAGN_CHANNEL(X),
677 ADIS16480_MAGN_CHANNEL(Y),
678 ADIS16480_MAGN_CHANNEL(Z),
679 ADIS16480_PRESSURE_CHANNEL(),
680 ADIS16480_TEMP_CHANNEL(),
681 IIO_CHAN_SOFT_TIMESTAMP(11)
682};
683
684static const struct iio_chan_spec adis16485_channels[] = {
685 ADIS16480_GYRO_CHANNEL(X),
686 ADIS16480_GYRO_CHANNEL(Y),
687 ADIS16480_GYRO_CHANNEL(Z),
688 ADIS16480_ACCEL_CHANNEL(X),
689 ADIS16480_ACCEL_CHANNEL(Y),
690 ADIS16480_ACCEL_CHANNEL(Z),
691 ADIS16480_TEMP_CHANNEL(),
692 IIO_CHAN_SOFT_TIMESTAMP(7)
693};
694
695enum adis16480_variant {
696 ADIS16375,
697 ADIS16480,
698 ADIS16485,
699 ADIS16488,
700};
701
702static const struct adis16480_chip_info adis16480_chip_info[] = {
703 [ADIS16375] = {
704 .channels = adis16485_channels,
705 .num_channels = ARRAY_SIZE(adis16485_channels),
706 },
707 [ADIS16480] = {
708 .channels = adis16480_channels,
709 .num_channels = ARRAY_SIZE(adis16480_channels),
710 },
711 [ADIS16485] = {
712 .channels = adis16485_channels,
713 .num_channels = ARRAY_SIZE(adis16485_channels),
714 },
715 [ADIS16488] = {
716 .channels = adis16480_channels,
717 .num_channels = ARRAY_SIZE(adis16480_channels),
718 },
719};
720
721static struct attribute *adis16480_attributes[] = {
722 &iio_dev_attr_sampling_frequency.dev_attr.attr,
723 NULL
724};
725
726static const struct attribute_group adis16480_attribute_group = {
727 .attrs = adis16480_attributes,
728};
729
730static const struct iio_info adis16480_info = {
731 .attrs = &adis16480_attribute_group,
732 .read_raw = &adis16480_read_raw,
733 .write_raw = &adis16480_write_raw,
734 .update_scan_mode = adis_update_scan_mode,
735 .driver_module = THIS_MODULE,
736};
737
738static int adis16480_stop_device(struct iio_dev *indio_dev)
739{
740 struct adis16480 *st = iio_priv(indio_dev);
741 int ret;
742
743 ret = adis_write_reg_16(&st->adis, ADIS16480_REG_SLP_CNT, BIT(9));
744 if (ret)
745 dev_err(&indio_dev->dev,
746 "Could not power down device: %d\n", ret);
747
748 return ret;
749}
750
751static int adis16480_enable_irq(struct adis *adis, bool enable)
752{
753 return adis_write_reg_16(adis, ADIS16480_REG_FNCTIO_CTRL,
754 enable ? BIT(3) : 0);
755}
756
757static int adis16480_initial_setup(struct iio_dev *indio_dev)
758{
759 struct adis16480 *st = iio_priv(indio_dev);
760 uint16_t prod_id;
761 unsigned int device_id;
762 int ret;
763
764 adis_reset(&st->adis);
765 msleep(70);
766
767 ret = adis_write_reg_16(&st->adis, ADIS16480_REG_GLOB_CMD, BIT(1));
768 if (ret)
769 return ret;
770 msleep(30);
771
772 ret = adis_check_status(&st->adis);
773 if (ret)
774 return ret;
775
776 ret = adis_read_reg_16(&st->adis, ADIS16480_REG_PROD_ID, &prod_id);
777 if (ret)
778 return ret;
779
780 sscanf(indio_dev->name, "adis%u\n", &device_id);
781
782 if (prod_id != device_id)
783 dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.",
784 device_id, prod_id);
785
786 return 0;
787}
788
789#define ADIS16480_DIAG_STAT_XGYRO_FAIL 0
790#define ADIS16480_DIAG_STAT_YGYRO_FAIL 1
791#define ADIS16480_DIAG_STAT_ZGYRO_FAIL 2
792#define ADIS16480_DIAG_STAT_XACCL_FAIL 3
793#define ADIS16480_DIAG_STAT_YACCL_FAIL 4
794#define ADIS16480_DIAG_STAT_ZACCL_FAIL 5
795#define ADIS16480_DIAG_STAT_XMAGN_FAIL 8
796#define ADIS16480_DIAG_STAT_YMAGN_FAIL 9
797#define ADIS16480_DIAG_STAT_ZMAGN_FAIL 10
798#define ADIS16480_DIAG_STAT_BARO_FAIL 11
799
800static const char * const adis16480_status_error_msgs[] = {
801 [ADIS16480_DIAG_STAT_XGYRO_FAIL] = "X-axis gyroscope self-test failure",
802 [ADIS16480_DIAG_STAT_YGYRO_FAIL] = "Y-axis gyroscope self-test failure",
803 [ADIS16480_DIAG_STAT_ZGYRO_FAIL] = "Z-axis gyroscope self-test failure",
804 [ADIS16480_DIAG_STAT_XACCL_FAIL] = "X-axis accelerometer self-test failure",
805 [ADIS16480_DIAG_STAT_YACCL_FAIL] = "Y-axis accelerometer self-test failure",
806 [ADIS16480_DIAG_STAT_ZACCL_FAIL] = "Z-axis accelerometer self-test failure",
807 [ADIS16480_DIAG_STAT_XMAGN_FAIL] = "X-axis magnetometer self-test failure",
808 [ADIS16480_DIAG_STAT_YMAGN_FAIL] = "Y-axis magnetometer self-test failure",
809 [ADIS16480_DIAG_STAT_ZMAGN_FAIL] = "Z-axis magnetometer self-test failure",
810 [ADIS16480_DIAG_STAT_BARO_FAIL] = "Barometer self-test failure",
811};
812
813static const struct adis_data adis16480_data = {
814 .diag_stat_reg = ADIS16480_REG_DIAG_STS,
815 .glob_cmd_reg = ADIS16480_REG_GLOB_CMD,
816 .has_paging = true,
817
818 .read_delay = 5,
819 .write_delay = 5,
820
821 .status_error_msgs = adis16480_status_error_msgs,
822 .status_error_mask = BIT(ADIS16480_DIAG_STAT_XGYRO_FAIL) |
823 BIT(ADIS16480_DIAG_STAT_YGYRO_FAIL) |
824 BIT(ADIS16480_DIAG_STAT_ZGYRO_FAIL) |
825 BIT(ADIS16480_DIAG_STAT_XACCL_FAIL) |
826 BIT(ADIS16480_DIAG_STAT_YACCL_FAIL) |
827 BIT(ADIS16480_DIAG_STAT_ZACCL_FAIL) |
828 BIT(ADIS16480_DIAG_STAT_XMAGN_FAIL) |
829 BIT(ADIS16480_DIAG_STAT_YMAGN_FAIL) |
830 BIT(ADIS16480_DIAG_STAT_ZMAGN_FAIL) |
831 BIT(ADIS16480_DIAG_STAT_BARO_FAIL),
832
833 .enable_irq = adis16480_enable_irq,
834};
835
836static int adis16480_probe(struct spi_device *spi)
837{
838 const struct spi_device_id *id = spi_get_device_id(spi);
839 struct iio_dev *indio_dev;
840 struct adis16480 *st;
841 int ret;
842
843 indio_dev = iio_device_alloc(sizeof(*st));
844 if (indio_dev == NULL)
845 return -ENOMEM;
846
847 spi_set_drvdata(spi, indio_dev);
848
849 st = iio_priv(indio_dev);
850
851 st->chip_info = &adis16480_chip_info[id->driver_data];
852 indio_dev->dev.parent = &spi->dev;
853 indio_dev->name = spi_get_device_id(spi)->name;
854 indio_dev->channels = st->chip_info->channels;
855 indio_dev->num_channels = st->chip_info->num_channels;
856 indio_dev->info = &adis16480_info;
857 indio_dev->modes = INDIO_DIRECT_MODE;
858
859 ret = adis_init(&st->adis, indio_dev, spi, &adis16480_data);
860 if (ret)
861 goto error_free_dev;
862
863 ret = adis_setup_buffer_and_trigger(&st->adis, indio_dev, NULL);
864 if (ret)
865 goto error_free_dev;
866
867 ret = adis16480_initial_setup(indio_dev);
868 if (ret)
869 goto error_cleanup_buffer;
870
871 ret = iio_device_register(indio_dev);
872 if (ret)
873 goto error_stop_device;
874
875 adis16480_debugfs_init(indio_dev);
876
877 return 0;
878
879error_stop_device:
880 adis16480_stop_device(indio_dev);
881error_cleanup_buffer:
882 adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
883error_free_dev:
884 iio_device_free(indio_dev);
885 return ret;
886}
887
888static int adis16480_remove(struct spi_device *spi)
889{
890 struct iio_dev *indio_dev = spi_get_drvdata(spi);
891 struct adis16480 *st = iio_priv(indio_dev);
892
893 iio_device_unregister(indio_dev);
894 adis16480_stop_device(indio_dev);
895
896 adis_cleanup_buffer_and_trigger(&st->adis, indio_dev);
897
898 iio_device_free(indio_dev);
899
900 return 0;
901}
902
903static const struct spi_device_id adis16480_ids[] = {
904 { "adis16375", ADIS16375 },
905 { "adis16480", ADIS16480 },
906 { "adis16485", ADIS16485 },
907 { "adis16488", ADIS16488 },
908 { }
909};
910MODULE_DEVICE_TABLE(spi, adis16480_ids);
911
912static struct spi_driver adis16480_driver = {
913 .driver = {
914 .name = "adis16480",
915 .owner = THIS_MODULE,
916 },
917 .id_table = adis16480_ids,
918 .probe = adis16480_probe,
919 .remove = adis16480_remove,
920};
921module_spi_driver(adis16480_driver);
922
923MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
924MODULE_DESCRIPTION("Analog Devices ADIS16480 IMU driver");
925MODULE_LICENSE("GPL v2");