diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2012-11-20 08:36:00 -0500 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2012-11-20 16:26:34 -0500 |
commit | 9caed0d9d6db12cb6d81ba68d5bc98432d6b4711 (patch) | |
tree | 207c7f7410cee40409476a04c95fd5d2191ba2b6 /drivers/iio | |
parent | 57a1228a06b7a5939a8b0078a92b44fa30855bcb (diff) |
iio:gyro: Add support for the ADIS16136 gyroscope
This patch adds support for the ADIS16133, ADIS16135, ADIS16136 single channel
gyroscopes. The main difference between them is the sensor precision.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/gyro/Kconfig | 9 | ||||
-rw-r--r-- | drivers/iio/gyro/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/gyro/adis16136.c | 581 |
3 files changed, 591 insertions, 0 deletions
diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 21e27e2fc68c..48ed1483ff27 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig | |||
@@ -3,6 +3,15 @@ | |||
3 | # | 3 | # |
4 | menu "Digital gyroscope sensors" | 4 | menu "Digital gyroscope sensors" |
5 | 5 | ||
6 | config ADIS16136 | ||
7 | tristate "Analog devices ADIS16136 and similar gyroscopes driver" | ||
8 | depends on SPI_MASTER | ||
9 | select IIO_ADIS_LIB | ||
10 | select IIO_ADIS_LIB_BUFFER if IIO_BUFFER | ||
11 | help | ||
12 | Say yes here to build support for the Analog Devices ADIS16133, ADIS16135, | ||
13 | ADIS16136 gyroscope devices. | ||
14 | |||
6 | config HID_SENSOR_GYRO_3D | 15 | config HID_SENSOR_GYRO_3D |
7 | depends on HID_SENSOR_HUB | 16 | depends on HID_SENSOR_HUB |
8 | select IIO_BUFFER | 17 | select IIO_BUFFER |
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile index 8a895d9fcbce..702a058907e3 100644 --- a/drivers/iio/gyro/Makefile +++ b/drivers/iio/gyro/Makefile | |||
@@ -2,4 +2,5 @@ | |||
2 | # Makefile for industrial I/O gyroscope sensor drivers | 2 | # Makefile for industrial I/O gyroscope sensor drivers |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_ADIS16136) += adis16136.o | ||
5 | obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o | 6 | obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o |
diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c new file mode 100644 index 000000000000..05486dfd721b --- /dev/null +++ b/drivers/iio/gyro/adis16136.c | |||
@@ -0,0 +1,581 @@ | |||
1 | /* | ||
2 | * ADIS16133/ADIS16135/ADIS16136 gyroscope driver | ||
3 | * | ||
4 | * Copyright 2012 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/mutex.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/sysfs.h> | ||
18 | #include <linux/module.h> | ||
19 | |||
20 | #include <linux/iio/iio.h> | ||
21 | #include <linux/iio/sysfs.h> | ||
22 | #include <linux/iio/buffer.h> | ||
23 | #include <linux/iio/imu/adis.h> | ||
24 | |||
25 | #include <linux/iio/iio.h> | ||
26 | #include <linux/debugfs.h> | ||
27 | |||
28 | #define ADIS16136_REG_FLASH_CNT 0x00 | ||
29 | #define ADIS16136_REG_TEMP_OUT 0x02 | ||
30 | #define ADIS16136_REG_GYRO_OUT2 0x04 | ||
31 | #define ADIS16136_REG_GYRO_OUT 0x06 | ||
32 | #define ADIS16136_REG_GYRO_OFF2 0x08 | ||
33 | #define ADIS16136_REG_GYRO_OFF 0x0A | ||
34 | #define ADIS16136_REG_ALM_MAG1 0x10 | ||
35 | #define ADIS16136_REG_ALM_MAG2 0x12 | ||
36 | #define ADIS16136_REG_ALM_SAMPL1 0x14 | ||
37 | #define ADIS16136_REG_ALM_SAMPL2 0x16 | ||
38 | #define ADIS16136_REG_ALM_CTRL 0x18 | ||
39 | #define ADIS16136_REG_GPIO_CTRL 0x1A | ||
40 | #define ADIS16136_REG_MSC_CTRL 0x1C | ||
41 | #define ADIS16136_REG_SMPL_PRD 0x1E | ||
42 | #define ADIS16136_REG_AVG_CNT 0x20 | ||
43 | #define ADIS16136_REG_DEC_RATE 0x22 | ||
44 | #define ADIS16136_REG_SLP_CTRL 0x24 | ||
45 | #define ADIS16136_REG_DIAG_STAT 0x26 | ||
46 | #define ADIS16136_REG_GLOB_CMD 0x28 | ||
47 | #define ADIS16136_REG_LOT1 0x32 | ||
48 | #define ADIS16136_REG_LOT2 0x34 | ||
49 | #define ADIS16136_REG_LOT3 0x36 | ||
50 | #define ADIS16136_REG_PROD_ID 0x38 | ||
51 | #define ADIS16136_REG_SERIAL_NUM 0x3A | ||
52 | |||
53 | #define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2 | ||
54 | #define ADIS16136_DIAG_STAT_SPI_FAIL 3 | ||
55 | #define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5 | ||
56 | #define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6 | ||
57 | |||
58 | #define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11) | ||
59 | #define ADIS16136_MSC_CTRL_SELF_TEST BIT(10) | ||
60 | |||
61 | struct adis16136_chip_info { | ||
62 | unsigned int precision; | ||
63 | unsigned int fullscale; | ||
64 | }; | ||
65 | |||
66 | struct adis16136 { | ||
67 | const struct adis16136_chip_info *chip_info; | ||
68 | |||
69 | struct adis adis; | ||
70 | }; | ||
71 | |||
72 | #ifdef CONFIG_DEBUG_FS | ||
73 | |||
74 | static ssize_t adis16136_show_serial(struct file *file, | ||
75 | char __user *userbuf, size_t count, loff_t *ppos) | ||
76 | { | ||
77 | struct adis16136 *adis16136 = file->private_data; | ||
78 | uint16_t lot1, lot2, lot3, serial; | ||
79 | char buf[20]; | ||
80 | size_t len; | ||
81 | int ret; | ||
82 | |||
83 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, | ||
84 | &serial); | ||
85 | if (ret < 0) | ||
86 | return ret; | ||
87 | |||
88 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); | ||
93 | if (ret < 0) | ||
94 | return ret; | ||
95 | |||
96 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, | ||
101 | lot3, serial); | ||
102 | |||
103 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | ||
104 | } | ||
105 | |||
106 | static const struct file_operations adis16136_serial_fops = { | ||
107 | .open = simple_open, | ||
108 | .read = adis16136_show_serial, | ||
109 | .llseek = default_llseek, | ||
110 | .owner = THIS_MODULE, | ||
111 | }; | ||
112 | |||
113 | static int adis16136_show_product_id(void *arg, u64 *val) | ||
114 | { | ||
115 | struct adis16136 *adis16136 = arg; | ||
116 | u16 prod_id; | ||
117 | int ret; | ||
118 | |||
119 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, | ||
120 | &prod_id); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | *val = prod_id; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops, | ||
129 | adis16136_show_product_id, NULL, "%llu\n"); | ||
130 | |||
131 | static int adis16136_show_flash_count(void *arg, u64 *val) | ||
132 | { | ||
133 | struct adis16136 *adis16136 = arg; | ||
134 | uint16_t flash_count; | ||
135 | int ret; | ||
136 | |||
137 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, | ||
138 | &flash_count); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | *val = flash_count; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops, | ||
147 | adis16136_show_flash_count, NULL, "%lld\n"); | ||
148 | |||
149 | static int adis16136_debugfs_init(struct iio_dev *indio_dev) | ||
150 | { | ||
151 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
152 | |||
153 | debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, | ||
154 | adis16136, &adis16136_serial_fops); | ||
155 | debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, | ||
156 | adis16136, &adis16136_product_id_fops); | ||
157 | debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, | ||
158 | adis16136, &adis16136_flash_count_fops); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | #else | ||
164 | |||
165 | static int adis16136_debugfs_init(struct iio_dev *indio_dev) | ||
166 | { | ||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | #endif | ||
171 | |||
172 | static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq) | ||
173 | { | ||
174 | unsigned int t; | ||
175 | |||
176 | t = 32768 / freq; | ||
177 | if (t < 0xf) | ||
178 | t = 0xf; | ||
179 | else if (t > 0xffff) | ||
180 | t = 0xffff; | ||
181 | else | ||
182 | t--; | ||
183 | |||
184 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); | ||
185 | } | ||
186 | |||
187 | static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) | ||
188 | { | ||
189 | uint16_t t; | ||
190 | int ret; | ||
191 | |||
192 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); | ||
193 | if (ret < 0) | ||
194 | return ret; | ||
195 | |||
196 | *freq = 32768 / (t + 1); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static ssize_t adis16136_write_frequency(struct device *dev, | ||
202 | struct device_attribute *attr, const char *buf, size_t len) | ||
203 | { | ||
204 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
205 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
206 | long val; | ||
207 | int ret; | ||
208 | |||
209 | ret = kstrtol(buf, 10, &val); | ||
210 | if (ret) | ||
211 | return ret; | ||
212 | |||
213 | if (val == 0) | ||
214 | return -EINVAL; | ||
215 | |||
216 | ret = adis16136_set_freq(adis16136, val); | ||
217 | |||
218 | return ret ? ret : len; | ||
219 | } | ||
220 | |||
221 | static ssize_t adis16136_read_frequency(struct device *dev, | ||
222 | struct device_attribute *attr, char *buf) | ||
223 | { | ||
224 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | ||
225 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
226 | unsigned int freq; | ||
227 | int ret; | ||
228 | |||
229 | ret = adis16136_get_freq(adis16136, &freq); | ||
230 | if (ret < 0) | ||
231 | return ret; | ||
232 | |||
233 | return sprintf(buf, "%d\n", freq); | ||
234 | } | ||
235 | |||
236 | static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, | ||
237 | adis16136_read_frequency, | ||
238 | adis16136_write_frequency); | ||
239 | |||
240 | static const unsigned adis16136_3db_divisors[] = { | ||
241 | [0] = 2, /* Special case */ | ||
242 | [1] = 6, | ||
243 | [2] = 12, | ||
244 | [3] = 25, | ||
245 | [4] = 50, | ||
246 | [5] = 100, | ||
247 | [6] = 200, | ||
248 | [7] = 200, /* Not a valid setting */ | ||
249 | }; | ||
250 | |||
251 | static int adis16136_set_filter(struct iio_dev *indio_dev, int val) | ||
252 | { | ||
253 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
254 | unsigned int freq; | ||
255 | int i, ret; | ||
256 | |||
257 | ret = adis16136_get_freq(adis16136, &freq); | ||
258 | if (ret < 0) | ||
259 | return ret; | ||
260 | |||
261 | for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { | ||
262 | if (freq / adis16136_3db_divisors[i] >= val) | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); | ||
267 | } | ||
268 | |||
269 | static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) | ||
270 | { | ||
271 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
272 | unsigned int freq; | ||
273 | uint16_t val16; | ||
274 | int ret; | ||
275 | |||
276 | mutex_lock(&indio_dev->mlock); | ||
277 | |||
278 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); | ||
279 | if (ret < 0) | ||
280 | goto err_unlock; | ||
281 | |||
282 | ret = adis16136_get_freq(adis16136, &freq); | ||
283 | if (ret < 0) | ||
284 | goto err_unlock; | ||
285 | |||
286 | *val = freq / adis16136_3db_divisors[val16 & 0x07]; | ||
287 | |||
288 | err_unlock: | ||
289 | mutex_unlock(&indio_dev->mlock); | ||
290 | |||
291 | return ret ? ret : IIO_VAL_INT; | ||
292 | } | ||
293 | |||
294 | static int adis16136_read_raw(struct iio_dev *indio_dev, | ||
295 | const struct iio_chan_spec *chan, int *val, int *val2, long info) | ||
296 | { | ||
297 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
298 | uint32_t val32; | ||
299 | int ret; | ||
300 | |||
301 | switch (info) { | ||
302 | case IIO_CHAN_INFO_RAW: | ||
303 | return adis_single_conversion(indio_dev, chan, 0, val); | ||
304 | case IIO_CHAN_INFO_SCALE: | ||
305 | switch (chan->type) { | ||
306 | case IIO_ANGL_VEL: | ||
307 | *val = adis16136->chip_info->precision; | ||
308 | *val2 = (adis16136->chip_info->fullscale << 16); | ||
309 | return IIO_VAL_FRACTIONAL; | ||
310 | case IIO_TEMP: | ||
311 | *val = 10; | ||
312 | *val2 = 697000; /* 0.010697 degree Celsius */ | ||
313 | return IIO_VAL_INT_PLUS_MICRO; | ||
314 | default: | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | case IIO_CHAN_INFO_CALIBBIAS: | ||
318 | ret = adis_read_reg_32(&adis16136->adis, | ||
319 | ADIS16136_REG_GYRO_OFF2, &val32); | ||
320 | if (ret < 0) | ||
321 | return ret; | ||
322 | |||
323 | *val = sign_extend32(val32, 31); | ||
324 | |||
325 | return IIO_VAL_INT; | ||
326 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | ||
327 | return adis16136_get_filter(indio_dev, val); | ||
328 | default: | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | static int adis16136_write_raw(struct iio_dev *indio_dev, | ||
334 | const struct iio_chan_spec *chan, int val, int val2, long info) | ||
335 | { | ||
336 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
337 | |||
338 | switch (info) { | ||
339 | case IIO_CHAN_INFO_CALIBBIAS: | ||
340 | return adis_write_reg_32(&adis16136->adis, | ||
341 | ADIS16136_REG_GYRO_OFF2, val); | ||
342 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | ||
343 | return adis16136_set_filter(indio_dev, val); | ||
344 | default: | ||
345 | break; | ||
346 | } | ||
347 | |||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | enum { | ||
352 | ADIS16136_SCAN_GYRO, | ||
353 | ADIS16136_SCAN_TEMP, | ||
354 | }; | ||
355 | |||
356 | static const struct iio_chan_spec adis16136_channels[] = { | ||
357 | { | ||
358 | .type = IIO_ANGL_VEL, | ||
359 | .modified = 1, | ||
360 | .channel2 = IIO_MOD_X, | ||
361 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | | ||
362 | IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | | ||
363 | IIO_CHAN_INFO_SCALE_SHARED_BIT | | ||
364 | IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT, | ||
365 | .address = ADIS16136_REG_GYRO_OUT2, | ||
366 | .scan_index = ADIS16136_SCAN_GYRO, | ||
367 | .scan_type = { | ||
368 | .sign = 's', | ||
369 | .realbits = 32, | ||
370 | .storagebits = 32, | ||
371 | .endianness = IIO_BE, | ||
372 | }, | ||
373 | }, { | ||
374 | .type = IIO_TEMP, | ||
375 | .indexed = 1, | ||
376 | .channel = 0, | ||
377 | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | | ||
378 | IIO_CHAN_INFO_SCALE_SEPARATE_BIT, | ||
379 | .address = ADIS16136_REG_TEMP_OUT, | ||
380 | .scan_index = ADIS16136_SCAN_TEMP, | ||
381 | .scan_type = { | ||
382 | .sign = 's', | ||
383 | .realbits = 16, | ||
384 | .storagebits = 16, | ||
385 | .endianness = IIO_BE, | ||
386 | }, | ||
387 | }, | ||
388 | IIO_CHAN_SOFT_TIMESTAMP(2), | ||
389 | }; | ||
390 | |||
391 | static struct attribute *adis16136_attributes[] = { | ||
392 | &iio_dev_attr_sampling_frequency.dev_attr.attr, | ||
393 | NULL | ||
394 | }; | ||
395 | |||
396 | static const struct attribute_group adis16136_attribute_group = { | ||
397 | .attrs = adis16136_attributes, | ||
398 | }; | ||
399 | |||
400 | static const struct iio_info adis16136_info = { | ||
401 | .driver_module = THIS_MODULE, | ||
402 | .attrs = &adis16136_attribute_group, | ||
403 | .read_raw = &adis16136_read_raw, | ||
404 | .write_raw = &adis16136_write_raw, | ||
405 | .update_scan_mode = adis_update_scan_mode, | ||
406 | .debugfs_reg_access = adis_debugfs_reg_access, | ||
407 | }; | ||
408 | |||
409 | static int adis16136_stop_device(struct iio_dev *indio_dev) | ||
410 | { | ||
411 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
412 | int ret; | ||
413 | |||
414 | ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff); | ||
415 | if (ret) | ||
416 | dev_err(&indio_dev->dev, | ||
417 | "Could not power down device: %d\n", ret); | ||
418 | |||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | static int adis16136_initial_setup(struct iio_dev *indio_dev) | ||
423 | { | ||
424 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
425 | unsigned int device_id; | ||
426 | uint16_t prod_id; | ||
427 | int ret; | ||
428 | |||
429 | ret = adis_initial_startup(&adis16136->adis); | ||
430 | if (ret) | ||
431 | return ret; | ||
432 | |||
433 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, | ||
434 | &prod_id); | ||
435 | if (ret) | ||
436 | return ret; | ||
437 | |||
438 | sscanf(indio_dev->name, "adis%u\n", &device_id); | ||
439 | |||
440 | if (prod_id != device_id) | ||
441 | dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", | ||
442 | device_id, prod_id); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static const char * const adis16136_status_error_msgs[] = { | ||
448 | [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed", | ||
449 | [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure", | ||
450 | [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error", | ||
451 | [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error", | ||
452 | }; | ||
453 | |||
454 | static const struct adis_data adis16136_data = { | ||
455 | .diag_stat_reg = ADIS16136_REG_DIAG_STAT, | ||
456 | .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, | ||
457 | .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, | ||
458 | |||
459 | .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, | ||
460 | .startup_delay = 80, | ||
461 | |||
462 | .read_delay = 10, | ||
463 | .write_delay = 10, | ||
464 | |||
465 | .status_error_msgs = adis16136_status_error_msgs, | ||
466 | .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | | ||
467 | BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | | ||
468 | BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | | ||
469 | BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), | ||
470 | }; | ||
471 | |||
472 | enum adis16136_id { | ||
473 | ID_ADIS16133, | ||
474 | ID_ADIS16135, | ||
475 | ID_ADIS16136, | ||
476 | }; | ||
477 | |||
478 | static const struct adis16136_chip_info adis16136_chip_info[] = { | ||
479 | [ID_ADIS16133] = { | ||
480 | .precision = IIO_DEGREE_TO_RAD(1200), | ||
481 | .fullscale = 24000, | ||
482 | }, | ||
483 | [ID_ADIS16135] = { | ||
484 | .precision = IIO_DEGREE_TO_RAD(300), | ||
485 | .fullscale = 24000, | ||
486 | }, | ||
487 | [ID_ADIS16136] = { | ||
488 | .precision = IIO_DEGREE_TO_RAD(450), | ||
489 | .fullscale = 24623, | ||
490 | }, | ||
491 | }; | ||
492 | |||
493 | static int adis16136_probe(struct spi_device *spi) | ||
494 | { | ||
495 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
496 | struct adis16136 *adis16136; | ||
497 | struct iio_dev *indio_dev; | ||
498 | int ret; | ||
499 | |||
500 | indio_dev = iio_device_alloc(sizeof(*adis16136)); | ||
501 | if (indio_dev == NULL) | ||
502 | return -ENOMEM; | ||
503 | |||
504 | spi_set_drvdata(spi, indio_dev); | ||
505 | |||
506 | adis16136 = iio_priv(indio_dev); | ||
507 | |||
508 | adis16136->chip_info = &adis16136_chip_info[id->driver_data]; | ||
509 | indio_dev->dev.parent = &spi->dev; | ||
510 | indio_dev->name = spi_get_device_id(spi)->name; | ||
511 | indio_dev->channels = adis16136_channels; | ||
512 | indio_dev->num_channels = ARRAY_SIZE(adis16136_channels); | ||
513 | indio_dev->info = &adis16136_info; | ||
514 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
515 | |||
516 | ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data); | ||
517 | if (ret) | ||
518 | goto error_free_dev; | ||
519 | |||
520 | ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); | ||
521 | if (ret) | ||
522 | goto error_free_dev; | ||
523 | |||
524 | ret = adis16136_initial_setup(indio_dev); | ||
525 | if (ret) | ||
526 | goto error_cleanup_buffer; | ||
527 | |||
528 | ret = iio_device_register(indio_dev); | ||
529 | if (ret) | ||
530 | goto error_stop_device; | ||
531 | |||
532 | adis16136_debugfs_init(indio_dev); | ||
533 | |||
534 | return 0; | ||
535 | |||
536 | error_stop_device: | ||
537 | adis16136_stop_device(indio_dev); | ||
538 | error_cleanup_buffer: | ||
539 | adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); | ||
540 | error_free_dev: | ||
541 | iio_device_free(indio_dev); | ||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | static int adis16136_remove(struct spi_device *spi) | ||
546 | { | ||
547 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
548 | struct adis16136 *adis16136 = iio_priv(indio_dev); | ||
549 | |||
550 | iio_device_unregister(indio_dev); | ||
551 | adis16136_stop_device(indio_dev); | ||
552 | |||
553 | adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); | ||
554 | |||
555 | iio_device_free(indio_dev); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static const struct spi_device_id adis16136_ids[] = { | ||
561 | { "adis16133", ID_ADIS16133 }, | ||
562 | { "adis16135", ID_ADIS16135 }, | ||
563 | { "adis16136", ID_ADIS16136 }, | ||
564 | { } | ||
565 | }; | ||
566 | MODULE_DEVICE_TABLE(spi, adis16136_ids); | ||
567 | |||
568 | static struct spi_driver adis16136_driver = { | ||
569 | .driver = { | ||
570 | .name = "adis16136", | ||
571 | .owner = THIS_MODULE, | ||
572 | }, | ||
573 | .id_table = adis16136_ids, | ||
574 | .probe = adis16136_probe, | ||
575 | .remove = adis16136_remove, | ||
576 | }; | ||
577 | module_spi_driver(adis16136_driver); | ||
578 | |||
579 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
580 | MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); | ||
581 | MODULE_LICENSE("GPL v2"); | ||