]>
Commit | Line | Data |
---|---|---|
9caed0d9 LPC |
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 | ||
9caed0d9 LPC |
25 | #include <linux/debugfs.h> |
26 | ||
27 | #define ADIS16136_REG_FLASH_CNT 0x00 | |
28 | #define ADIS16136_REG_TEMP_OUT 0x02 | |
29 | #define ADIS16136_REG_GYRO_OUT2 0x04 | |
30 | #define ADIS16136_REG_GYRO_OUT 0x06 | |
31 | #define ADIS16136_REG_GYRO_OFF2 0x08 | |
32 | #define ADIS16136_REG_GYRO_OFF 0x0A | |
33 | #define ADIS16136_REG_ALM_MAG1 0x10 | |
34 | #define ADIS16136_REG_ALM_MAG2 0x12 | |
35 | #define ADIS16136_REG_ALM_SAMPL1 0x14 | |
36 | #define ADIS16136_REG_ALM_SAMPL2 0x16 | |
37 | #define ADIS16136_REG_ALM_CTRL 0x18 | |
38 | #define ADIS16136_REG_GPIO_CTRL 0x1A | |
39 | #define ADIS16136_REG_MSC_CTRL 0x1C | |
40 | #define ADIS16136_REG_SMPL_PRD 0x1E | |
41 | #define ADIS16136_REG_AVG_CNT 0x20 | |
42 | #define ADIS16136_REG_DEC_RATE 0x22 | |
43 | #define ADIS16136_REG_SLP_CTRL 0x24 | |
44 | #define ADIS16136_REG_DIAG_STAT 0x26 | |
45 | #define ADIS16136_REG_GLOB_CMD 0x28 | |
46 | #define ADIS16136_REG_LOT1 0x32 | |
47 | #define ADIS16136_REG_LOT2 0x34 | |
48 | #define ADIS16136_REG_LOT3 0x36 | |
49 | #define ADIS16136_REG_PROD_ID 0x38 | |
50 | #define ADIS16136_REG_SERIAL_NUM 0x3A | |
51 | ||
52 | #define ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL 2 | |
53 | #define ADIS16136_DIAG_STAT_SPI_FAIL 3 | |
54 | #define ADIS16136_DIAG_STAT_SELF_TEST_FAIL 5 | |
55 | #define ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL 6 | |
56 | ||
57 | #define ADIS16136_MSC_CTRL_MEMORY_TEST BIT(11) | |
58 | #define ADIS16136_MSC_CTRL_SELF_TEST BIT(10) | |
59 | ||
60 | struct adis16136_chip_info { | |
61 | unsigned int precision; | |
62 | unsigned int fullscale; | |
63 | }; | |
64 | ||
65 | struct adis16136 { | |
66 | const struct adis16136_chip_info *chip_info; | |
67 | ||
68 | struct adis adis; | |
69 | }; | |
70 | ||
71 | #ifdef CONFIG_DEBUG_FS | |
72 | ||
73 | static ssize_t adis16136_show_serial(struct file *file, | |
74 | char __user *userbuf, size_t count, loff_t *ppos) | |
75 | { | |
76 | struct adis16136 *adis16136 = file->private_data; | |
77 | uint16_t lot1, lot2, lot3, serial; | |
78 | char buf[20]; | |
79 | size_t len; | |
80 | int ret; | |
81 | ||
82 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SERIAL_NUM, | |
83 | &serial); | |
84 | if (ret < 0) | |
85 | return ret; | |
86 | ||
87 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT1, &lot1); | |
88 | if (ret < 0) | |
89 | return ret; | |
90 | ||
91 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT2, &lot2); | |
92 | if (ret < 0) | |
93 | return ret; | |
94 | ||
95 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_LOT3, &lot3); | |
96 | if (ret < 0) | |
97 | return ret; | |
98 | ||
99 | len = snprintf(buf, sizeof(buf), "%.4x%.4x%.4x-%.4x\n", lot1, lot2, | |
100 | lot3, serial); | |
101 | ||
102 | return simple_read_from_buffer(userbuf, count, ppos, buf, len); | |
103 | } | |
104 | ||
105 | static const struct file_operations adis16136_serial_fops = { | |
106 | .open = simple_open, | |
107 | .read = adis16136_show_serial, | |
108 | .llseek = default_llseek, | |
109 | .owner = THIS_MODULE, | |
110 | }; | |
111 | ||
112 | static int adis16136_show_product_id(void *arg, u64 *val) | |
113 | { | |
114 | struct adis16136 *adis16136 = arg; | |
115 | u16 prod_id; | |
116 | int ret; | |
117 | ||
118 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, | |
119 | &prod_id); | |
120 | if (ret < 0) | |
121 | return ret; | |
122 | ||
123 | *val = prod_id; | |
124 | ||
125 | return 0; | |
126 | } | |
127 | DEFINE_SIMPLE_ATTRIBUTE(adis16136_product_id_fops, | |
128 | adis16136_show_product_id, NULL, "%llu\n"); | |
129 | ||
130 | static int adis16136_show_flash_count(void *arg, u64 *val) | |
131 | { | |
132 | struct adis16136 *adis16136 = arg; | |
133 | uint16_t flash_count; | |
134 | int ret; | |
135 | ||
136 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_FLASH_CNT, | |
137 | &flash_count); | |
138 | if (ret < 0) | |
139 | return ret; | |
140 | ||
141 | *val = flash_count; | |
142 | ||
143 | return 0; | |
144 | } | |
145 | DEFINE_SIMPLE_ATTRIBUTE(adis16136_flash_count_fops, | |
146 | adis16136_show_flash_count, NULL, "%lld\n"); | |
147 | ||
148 | static int adis16136_debugfs_init(struct iio_dev *indio_dev) | |
149 | { | |
150 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
151 | ||
152 | debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, | |
153 | adis16136, &adis16136_serial_fops); | |
154 | debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, | |
155 | adis16136, &adis16136_product_id_fops); | |
156 | debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, | |
157 | adis16136, &adis16136_flash_count_fops); | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
162 | #else | |
163 | ||
164 | static int adis16136_debugfs_init(struct iio_dev *indio_dev) | |
165 | { | |
166 | return 0; | |
167 | } | |
168 | ||
169 | #endif | |
170 | ||
171 | static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq) | |
172 | { | |
173 | unsigned int t; | |
174 | ||
175 | t = 32768 / freq; | |
176 | if (t < 0xf) | |
177 | t = 0xf; | |
178 | else if (t > 0xffff) | |
179 | t = 0xffff; | |
180 | else | |
181 | t--; | |
182 | ||
183 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); | |
184 | } | |
185 | ||
186 | static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) | |
187 | { | |
188 | uint16_t t; | |
189 | int ret; | |
190 | ||
191 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); | |
192 | if (ret < 0) | |
193 | return ret; | |
194 | ||
195 | *freq = 32768 / (t + 1); | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | static ssize_t adis16136_write_frequency(struct device *dev, | |
201 | struct device_attribute *attr, const char *buf, size_t len) | |
202 | { | |
203 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
204 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
12660138 | 205 | unsigned int val; |
9caed0d9 LPC |
206 | int ret; |
207 | ||
12660138 | 208 | ret = kstrtouint(buf, 10, &val); |
9caed0d9 LPC |
209 | if (ret) |
210 | return ret; | |
211 | ||
212 | if (val == 0) | |
213 | return -EINVAL; | |
214 | ||
215 | ret = adis16136_set_freq(adis16136, val); | |
216 | ||
217 | return ret ? ret : len; | |
218 | } | |
219 | ||
220 | static ssize_t adis16136_read_frequency(struct device *dev, | |
221 | struct device_attribute *attr, char *buf) | |
222 | { | |
223 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
224 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
225 | unsigned int freq; | |
226 | int ret; | |
227 | ||
228 | ret = adis16136_get_freq(adis16136, &freq); | |
229 | if (ret < 0) | |
230 | return ret; | |
231 | ||
232 | return sprintf(buf, "%d\n", freq); | |
233 | } | |
234 | ||
235 | static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, | |
236 | adis16136_read_frequency, | |
237 | adis16136_write_frequency); | |
238 | ||
239 | static const unsigned adis16136_3db_divisors[] = { | |
240 | [0] = 2, /* Special case */ | |
241 | [1] = 6, | |
242 | [2] = 12, | |
243 | [3] = 25, | |
244 | [4] = 50, | |
245 | [5] = 100, | |
246 | [6] = 200, | |
247 | [7] = 200, /* Not a valid setting */ | |
248 | }; | |
249 | ||
250 | static int adis16136_set_filter(struct iio_dev *indio_dev, int val) | |
251 | { | |
252 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
253 | unsigned int freq; | |
254 | int i, ret; | |
255 | ||
256 | ret = adis16136_get_freq(adis16136, &freq); | |
257 | if (ret < 0) | |
258 | return ret; | |
259 | ||
260 | for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { | |
261 | if (freq / adis16136_3db_divisors[i] >= val) | |
262 | break; | |
263 | } | |
264 | ||
265 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); | |
266 | } | |
267 | ||
268 | static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) | |
269 | { | |
270 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
271 | unsigned int freq; | |
272 | uint16_t val16; | |
273 | int ret; | |
274 | ||
275 | mutex_lock(&indio_dev->mlock); | |
276 | ||
277 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); | |
278 | if (ret < 0) | |
279 | goto err_unlock; | |
280 | ||
281 | ret = adis16136_get_freq(adis16136, &freq); | |
282 | if (ret < 0) | |
283 | goto err_unlock; | |
284 | ||
285 | *val = freq / adis16136_3db_divisors[val16 & 0x07]; | |
286 | ||
287 | err_unlock: | |
288 | mutex_unlock(&indio_dev->mlock); | |
289 | ||
290 | return ret ? ret : IIO_VAL_INT; | |
291 | } | |
292 | ||
293 | static int adis16136_read_raw(struct iio_dev *indio_dev, | |
294 | const struct iio_chan_spec *chan, int *val, int *val2, long info) | |
295 | { | |
296 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
297 | uint32_t val32; | |
298 | int ret; | |
299 | ||
300 | switch (info) { | |
301 | case IIO_CHAN_INFO_RAW: | |
302 | return adis_single_conversion(indio_dev, chan, 0, val); | |
303 | case IIO_CHAN_INFO_SCALE: | |
304 | switch (chan->type) { | |
305 | case IIO_ANGL_VEL: | |
306 | *val = adis16136->chip_info->precision; | |
307 | *val2 = (adis16136->chip_info->fullscale << 16); | |
308 | return IIO_VAL_FRACTIONAL; | |
309 | case IIO_TEMP: | |
310 | *val = 10; | |
311 | *val2 = 697000; /* 0.010697 degree Celsius */ | |
312 | return IIO_VAL_INT_PLUS_MICRO; | |
313 | default: | |
314 | return -EINVAL; | |
315 | } | |
316 | case IIO_CHAN_INFO_CALIBBIAS: | |
317 | ret = adis_read_reg_32(&adis16136->adis, | |
318 | ADIS16136_REG_GYRO_OFF2, &val32); | |
319 | if (ret < 0) | |
320 | return ret; | |
321 | ||
322 | *val = sign_extend32(val32, 31); | |
323 | ||
324 | return IIO_VAL_INT; | |
325 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
326 | return adis16136_get_filter(indio_dev, val); | |
327 | default: | |
328 | return -EINVAL; | |
329 | } | |
330 | } | |
331 | ||
332 | static int adis16136_write_raw(struct iio_dev *indio_dev, | |
333 | const struct iio_chan_spec *chan, int val, int val2, long info) | |
334 | { | |
335 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
336 | ||
337 | switch (info) { | |
338 | case IIO_CHAN_INFO_CALIBBIAS: | |
339 | return adis_write_reg_32(&adis16136->adis, | |
340 | ADIS16136_REG_GYRO_OFF2, val); | |
341 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
342 | return adis16136_set_filter(indio_dev, val); | |
343 | default: | |
344 | break; | |
345 | } | |
346 | ||
347 | return -EINVAL; | |
348 | } | |
349 | ||
350 | enum { | |
351 | ADIS16136_SCAN_GYRO, | |
352 | ADIS16136_SCAN_TEMP, | |
353 | }; | |
354 | ||
355 | static const struct iio_chan_spec adis16136_channels[] = { | |
356 | { | |
357 | .type = IIO_ANGL_VEL, | |
358 | .modified = 1, | |
359 | .channel2 = IIO_MOD_X, | |
606f9067 JC |
360 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
361 | BIT(IIO_CHAN_INFO_CALIBBIAS) | | |
362 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), | |
363 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), | |
364 | ||
9caed0d9 LPC |
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, | |
606f9067 JC |
377 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
378 | BIT(IIO_CHAN_INFO_SCALE), | |
9caed0d9 LPC |
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 | ||
a106b474 IC |
438 | ret = sscanf(indio_dev->name, "adis%u\n", &device_id); |
439 | if (ret != 1) | |
440 | return -EINVAL; | |
9caed0d9 LPC |
441 | |
442 | if (prod_id != device_id) | |
443 | dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", | |
444 | device_id, prod_id); | |
445 | ||
446 | return 0; | |
447 | } | |
448 | ||
449 | static const char * const adis16136_status_error_msgs[] = { | |
450 | [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed", | |
451 | [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure", | |
452 | [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error", | |
453 | [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error", | |
454 | }; | |
455 | ||
456 | static const struct adis_data adis16136_data = { | |
457 | .diag_stat_reg = ADIS16136_REG_DIAG_STAT, | |
458 | .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, | |
459 | .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, | |
460 | ||
461 | .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, | |
462 | .startup_delay = 80, | |
463 | ||
464 | .read_delay = 10, | |
465 | .write_delay = 10, | |
466 | ||
467 | .status_error_msgs = adis16136_status_error_msgs, | |
468 | .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | | |
469 | BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | | |
470 | BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | | |
471 | BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), | |
472 | }; | |
473 | ||
474 | enum adis16136_id { | |
475 | ID_ADIS16133, | |
476 | ID_ADIS16135, | |
477 | ID_ADIS16136, | |
5450c360 | 478 | ID_ADIS16137, |
9caed0d9 LPC |
479 | }; |
480 | ||
481 | static const struct adis16136_chip_info adis16136_chip_info[] = { | |
482 | [ID_ADIS16133] = { | |
483 | .precision = IIO_DEGREE_TO_RAD(1200), | |
484 | .fullscale = 24000, | |
485 | }, | |
486 | [ID_ADIS16135] = { | |
487 | .precision = IIO_DEGREE_TO_RAD(300), | |
488 | .fullscale = 24000, | |
489 | }, | |
490 | [ID_ADIS16136] = { | |
491 | .precision = IIO_DEGREE_TO_RAD(450), | |
492 | .fullscale = 24623, | |
493 | }, | |
5450c360 LPC |
494 | [ID_ADIS16137] = { |
495 | .precision = IIO_DEGREE_TO_RAD(1000), | |
496 | .fullscale = 24609, | |
497 | }, | |
9caed0d9 LPC |
498 | }; |
499 | ||
500 | static int adis16136_probe(struct spi_device *spi) | |
501 | { | |
502 | const struct spi_device_id *id = spi_get_device_id(spi); | |
503 | struct adis16136 *adis16136; | |
504 | struct iio_dev *indio_dev; | |
505 | int ret; | |
506 | ||
c0ca6d31 | 507 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136)); |
9caed0d9 LPC |
508 | if (indio_dev == NULL) |
509 | return -ENOMEM; | |
510 | ||
511 | spi_set_drvdata(spi, indio_dev); | |
512 | ||
513 | adis16136 = iio_priv(indio_dev); | |
514 | ||
515 | adis16136->chip_info = &adis16136_chip_info[id->driver_data]; | |
516 | indio_dev->dev.parent = &spi->dev; | |
517 | indio_dev->name = spi_get_device_id(spi)->name; | |
518 | indio_dev->channels = adis16136_channels; | |
519 | indio_dev->num_channels = ARRAY_SIZE(adis16136_channels); | |
520 | indio_dev->info = &adis16136_info; | |
521 | indio_dev->modes = INDIO_DIRECT_MODE; | |
522 | ||
523 | ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data); | |
524 | if (ret) | |
c0ca6d31 | 525 | return ret; |
9caed0d9 LPC |
526 | |
527 | ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); | |
528 | if (ret) | |
c0ca6d31 | 529 | return ret; |
9caed0d9 LPC |
530 | |
531 | ret = adis16136_initial_setup(indio_dev); | |
532 | if (ret) | |
533 | goto error_cleanup_buffer; | |
534 | ||
535 | ret = iio_device_register(indio_dev); | |
536 | if (ret) | |
537 | goto error_stop_device; | |
538 | ||
539 | adis16136_debugfs_init(indio_dev); | |
540 | ||
541 | return 0; | |
542 | ||
543 | error_stop_device: | |
544 | adis16136_stop_device(indio_dev); | |
545 | error_cleanup_buffer: | |
546 | adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); | |
9caed0d9 LPC |
547 | return ret; |
548 | } | |
549 | ||
550 | static int adis16136_remove(struct spi_device *spi) | |
551 | { | |
552 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
553 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
554 | ||
555 | iio_device_unregister(indio_dev); | |
556 | adis16136_stop_device(indio_dev); | |
557 | ||
558 | adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); | |
559 | ||
9caed0d9 LPC |
560 | return 0; |
561 | } | |
562 | ||
563 | static const struct spi_device_id adis16136_ids[] = { | |
564 | { "adis16133", ID_ADIS16133 }, | |
565 | { "adis16135", ID_ADIS16135 }, | |
566 | { "adis16136", ID_ADIS16136 }, | |
5450c360 | 567 | { "adis16137", ID_ADIS16137 }, |
9caed0d9 LPC |
568 | { } |
569 | }; | |
570 | MODULE_DEVICE_TABLE(spi, adis16136_ids); | |
571 | ||
572 | static struct spi_driver adis16136_driver = { | |
573 | .driver = { | |
574 | .name = "adis16136", | |
9caed0d9 LPC |
575 | }, |
576 | .id_table = adis16136_ids, | |
577 | .probe = adis16136_probe, | |
578 | .remove = adis16136_remove, | |
579 | }; | |
580 | module_spi_driver(adis16136_driver); | |
581 | ||
582 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | |
583 | MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); | |
584 | MODULE_LICENSE("GPL v2"); |