]>
Commit | Line | Data |
---|---|---|
9caed0d9 LPC |
1 | /* |
2 | * ADIS16133/ADIS16135/ADIS16136 gyroscope driver | |
3 | * | |
4 | * Copyright 2012 Analog Devices Inc. | |
5 | * Author: Lars-Peter Clausen <[email protected]> | |
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 | } | |
9aaea09b | 127 | DEFINE_DEBUGFS_ATTRIBUTE(adis16136_product_id_fops, |
9caed0d9 LPC |
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 | } | |
9aaea09b | 145 | DEFINE_DEBUGFS_ATTRIBUTE(adis16136_flash_count_fops, |
9caed0d9 LPC |
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 | ||
9aaea09b VP |
152 | debugfs_create_file_unsafe("serial_number", 0400, |
153 | indio_dev->debugfs_dentry, adis16136, | |
154 | &adis16136_serial_fops); | |
155 | debugfs_create_file_unsafe("product_id", 0400, | |
156 | indio_dev->debugfs_dentry, | |
9caed0d9 | 157 | adis16136, &adis16136_product_id_fops); |
9aaea09b VP |
158 | debugfs_create_file_unsafe("flash_count", 0400, |
159 | indio_dev->debugfs_dentry, | |
9caed0d9 LPC |
160 | adis16136, &adis16136_flash_count_fops); |
161 | ||
162 | return 0; | |
163 | } | |
164 | ||
165 | #else | |
166 | ||
167 | static int adis16136_debugfs_init(struct iio_dev *indio_dev) | |
168 | { | |
169 | return 0; | |
170 | } | |
171 | ||
172 | #endif | |
173 | ||
174 | static int adis16136_set_freq(struct adis16136 *adis16136, unsigned int freq) | |
175 | { | |
176 | unsigned int t; | |
177 | ||
178 | t = 32768 / freq; | |
179 | if (t < 0xf) | |
180 | t = 0xf; | |
181 | else if (t > 0xffff) | |
182 | t = 0xffff; | |
183 | else | |
184 | t--; | |
185 | ||
186 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, t); | |
187 | } | |
188 | ||
189 | static int adis16136_get_freq(struct adis16136 *adis16136, unsigned int *freq) | |
190 | { | |
191 | uint16_t t; | |
192 | int ret; | |
193 | ||
194 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_SMPL_PRD, &t); | |
195 | if (ret < 0) | |
196 | return ret; | |
197 | ||
198 | *freq = 32768 / (t + 1); | |
199 | ||
200 | return 0; | |
201 | } | |
202 | ||
203 | static ssize_t adis16136_write_frequency(struct device *dev, | |
204 | struct device_attribute *attr, const char *buf, size_t len) | |
205 | { | |
206 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
207 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
12660138 | 208 | unsigned int val; |
9caed0d9 LPC |
209 | int ret; |
210 | ||
12660138 | 211 | ret = kstrtouint(buf, 10, &val); |
9caed0d9 LPC |
212 | if (ret) |
213 | return ret; | |
214 | ||
215 | if (val == 0) | |
216 | return -EINVAL; | |
217 | ||
218 | ret = adis16136_set_freq(adis16136, val); | |
219 | ||
220 | return ret ? ret : len; | |
221 | } | |
222 | ||
223 | static ssize_t adis16136_read_frequency(struct device *dev, | |
224 | struct device_attribute *attr, char *buf) | |
225 | { | |
226 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
227 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
228 | unsigned int freq; | |
229 | int ret; | |
230 | ||
231 | ret = adis16136_get_freq(adis16136, &freq); | |
232 | if (ret < 0) | |
233 | return ret; | |
234 | ||
235 | return sprintf(buf, "%d\n", freq); | |
236 | } | |
237 | ||
238 | static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, | |
239 | adis16136_read_frequency, | |
240 | adis16136_write_frequency); | |
241 | ||
242 | static const unsigned adis16136_3db_divisors[] = { | |
243 | [0] = 2, /* Special case */ | |
244 | [1] = 6, | |
245 | [2] = 12, | |
246 | [3] = 25, | |
247 | [4] = 50, | |
248 | [5] = 100, | |
249 | [6] = 200, | |
250 | [7] = 200, /* Not a valid setting */ | |
251 | }; | |
252 | ||
253 | static int adis16136_set_filter(struct iio_dev *indio_dev, int val) | |
254 | { | |
255 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
256 | unsigned int freq; | |
257 | int i, ret; | |
258 | ||
259 | ret = adis16136_get_freq(adis16136, &freq); | |
260 | if (ret < 0) | |
261 | return ret; | |
262 | ||
263 | for (i = ARRAY_SIZE(adis16136_3db_divisors) - 1; i >= 1; i--) { | |
264 | if (freq / adis16136_3db_divisors[i] >= val) | |
265 | break; | |
266 | } | |
267 | ||
268 | return adis_write_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, i); | |
269 | } | |
270 | ||
271 | static int adis16136_get_filter(struct iio_dev *indio_dev, int *val) | |
272 | { | |
273 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
274 | unsigned int freq; | |
275 | uint16_t val16; | |
276 | int ret; | |
277 | ||
278 | mutex_lock(&indio_dev->mlock); | |
279 | ||
280 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_AVG_CNT, &val16); | |
281 | if (ret < 0) | |
282 | goto err_unlock; | |
283 | ||
284 | ret = adis16136_get_freq(adis16136, &freq); | |
285 | if (ret < 0) | |
286 | goto err_unlock; | |
287 | ||
288 | *val = freq / adis16136_3db_divisors[val16 & 0x07]; | |
289 | ||
290 | err_unlock: | |
291 | mutex_unlock(&indio_dev->mlock); | |
292 | ||
293 | return ret ? ret : IIO_VAL_INT; | |
294 | } | |
295 | ||
296 | static int adis16136_read_raw(struct iio_dev *indio_dev, | |
297 | const struct iio_chan_spec *chan, int *val, int *val2, long info) | |
298 | { | |
299 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
300 | uint32_t val32; | |
301 | int ret; | |
302 | ||
303 | switch (info) { | |
304 | case IIO_CHAN_INFO_RAW: | |
305 | return adis_single_conversion(indio_dev, chan, 0, val); | |
306 | case IIO_CHAN_INFO_SCALE: | |
307 | switch (chan->type) { | |
308 | case IIO_ANGL_VEL: | |
309 | *val = adis16136->chip_info->precision; | |
310 | *val2 = (adis16136->chip_info->fullscale << 16); | |
311 | return IIO_VAL_FRACTIONAL; | |
312 | case IIO_TEMP: | |
313 | *val = 10; | |
314 | *val2 = 697000; /* 0.010697 degree Celsius */ | |
315 | return IIO_VAL_INT_PLUS_MICRO; | |
316 | default: | |
317 | return -EINVAL; | |
318 | } | |
319 | case IIO_CHAN_INFO_CALIBBIAS: | |
320 | ret = adis_read_reg_32(&adis16136->adis, | |
321 | ADIS16136_REG_GYRO_OFF2, &val32); | |
322 | if (ret < 0) | |
323 | return ret; | |
324 | ||
325 | *val = sign_extend32(val32, 31); | |
326 | ||
327 | return IIO_VAL_INT; | |
328 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
329 | return adis16136_get_filter(indio_dev, val); | |
330 | default: | |
331 | return -EINVAL; | |
332 | } | |
333 | } | |
334 | ||
335 | static int adis16136_write_raw(struct iio_dev *indio_dev, | |
336 | const struct iio_chan_spec *chan, int val, int val2, long info) | |
337 | { | |
338 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
339 | ||
340 | switch (info) { | |
341 | case IIO_CHAN_INFO_CALIBBIAS: | |
342 | return adis_write_reg_32(&adis16136->adis, | |
343 | ADIS16136_REG_GYRO_OFF2, val); | |
344 | case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: | |
345 | return adis16136_set_filter(indio_dev, val); | |
346 | default: | |
347 | break; | |
348 | } | |
349 | ||
350 | return -EINVAL; | |
351 | } | |
352 | ||
353 | enum { | |
354 | ADIS16136_SCAN_GYRO, | |
355 | ADIS16136_SCAN_TEMP, | |
356 | }; | |
357 | ||
358 | static const struct iio_chan_spec adis16136_channels[] = { | |
359 | { | |
360 | .type = IIO_ANGL_VEL, | |
361 | .modified = 1, | |
362 | .channel2 = IIO_MOD_X, | |
606f9067 JC |
363 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
364 | BIT(IIO_CHAN_INFO_CALIBBIAS) | | |
365 | BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), | |
366 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), | |
367 | ||
9caed0d9 LPC |
368 | .address = ADIS16136_REG_GYRO_OUT2, |
369 | .scan_index = ADIS16136_SCAN_GYRO, | |
370 | .scan_type = { | |
371 | .sign = 's', | |
372 | .realbits = 32, | |
373 | .storagebits = 32, | |
374 | .endianness = IIO_BE, | |
375 | }, | |
376 | }, { | |
377 | .type = IIO_TEMP, | |
378 | .indexed = 1, | |
379 | .channel = 0, | |
606f9067 JC |
380 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | |
381 | BIT(IIO_CHAN_INFO_SCALE), | |
9caed0d9 LPC |
382 | .address = ADIS16136_REG_TEMP_OUT, |
383 | .scan_index = ADIS16136_SCAN_TEMP, | |
384 | .scan_type = { | |
385 | .sign = 's', | |
386 | .realbits = 16, | |
387 | .storagebits = 16, | |
388 | .endianness = IIO_BE, | |
389 | }, | |
390 | }, | |
391 | IIO_CHAN_SOFT_TIMESTAMP(2), | |
392 | }; | |
393 | ||
394 | static struct attribute *adis16136_attributes[] = { | |
395 | &iio_dev_attr_sampling_frequency.dev_attr.attr, | |
396 | NULL | |
397 | }; | |
398 | ||
399 | static const struct attribute_group adis16136_attribute_group = { | |
400 | .attrs = adis16136_attributes, | |
401 | }; | |
402 | ||
403 | static const struct iio_info adis16136_info = { | |
9caed0d9 LPC |
404 | .attrs = &adis16136_attribute_group, |
405 | .read_raw = &adis16136_read_raw, | |
406 | .write_raw = &adis16136_write_raw, | |
407 | .update_scan_mode = adis_update_scan_mode, | |
408 | .debugfs_reg_access = adis_debugfs_reg_access, | |
409 | }; | |
410 | ||
411 | static int adis16136_stop_device(struct iio_dev *indio_dev) | |
412 | { | |
413 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
414 | int ret; | |
415 | ||
416 | ret = adis_write_reg_16(&adis16136->adis, ADIS16136_REG_SLP_CTRL, 0xff); | |
417 | if (ret) | |
418 | dev_err(&indio_dev->dev, | |
419 | "Could not power down device: %d\n", ret); | |
420 | ||
421 | return ret; | |
422 | } | |
423 | ||
424 | static int adis16136_initial_setup(struct iio_dev *indio_dev) | |
425 | { | |
426 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
427 | unsigned int device_id; | |
428 | uint16_t prod_id; | |
429 | int ret; | |
430 | ||
431 | ret = adis_initial_startup(&adis16136->adis); | |
432 | if (ret) | |
433 | return ret; | |
434 | ||
435 | ret = adis_read_reg_16(&adis16136->adis, ADIS16136_REG_PROD_ID, | |
436 | &prod_id); | |
437 | if (ret) | |
438 | return ret; | |
439 | ||
a106b474 IC |
440 | ret = sscanf(indio_dev->name, "adis%u\n", &device_id); |
441 | if (ret != 1) | |
442 | return -EINVAL; | |
9caed0d9 LPC |
443 | |
444 | if (prod_id != device_id) | |
445 | dev_warn(&indio_dev->dev, "Device ID(%u) and product ID(%u) do not match.", | |
446 | device_id, prod_id); | |
447 | ||
448 | return 0; | |
449 | } | |
450 | ||
451 | static const char * const adis16136_status_error_msgs[] = { | |
452 | [ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL] = "Flash update failed", | |
453 | [ADIS16136_DIAG_STAT_SPI_FAIL] = "SPI failure", | |
454 | [ADIS16136_DIAG_STAT_SELF_TEST_FAIL] = "Self test error", | |
455 | [ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL] = "Flash checksum error", | |
456 | }; | |
457 | ||
458 | static const struct adis_data adis16136_data = { | |
459 | .diag_stat_reg = ADIS16136_REG_DIAG_STAT, | |
460 | .glob_cmd_reg = ADIS16136_REG_GLOB_CMD, | |
461 | .msc_ctrl_reg = ADIS16136_REG_MSC_CTRL, | |
462 | ||
463 | .self_test_mask = ADIS16136_MSC_CTRL_SELF_TEST, | |
464 | .startup_delay = 80, | |
465 | ||
466 | .read_delay = 10, | |
467 | .write_delay = 10, | |
468 | ||
469 | .status_error_msgs = adis16136_status_error_msgs, | |
470 | .status_error_mask = BIT(ADIS16136_DIAG_STAT_FLASH_UPDATE_FAIL) | | |
471 | BIT(ADIS16136_DIAG_STAT_SPI_FAIL) | | |
472 | BIT(ADIS16136_DIAG_STAT_SELF_TEST_FAIL) | | |
473 | BIT(ADIS16136_DIAG_STAT_FLASH_CHKSUM_FAIL), | |
474 | }; | |
475 | ||
476 | enum adis16136_id { | |
477 | ID_ADIS16133, | |
478 | ID_ADIS16135, | |
479 | ID_ADIS16136, | |
5450c360 | 480 | ID_ADIS16137, |
9caed0d9 LPC |
481 | }; |
482 | ||
483 | static const struct adis16136_chip_info adis16136_chip_info[] = { | |
484 | [ID_ADIS16133] = { | |
485 | .precision = IIO_DEGREE_TO_RAD(1200), | |
486 | .fullscale = 24000, | |
487 | }, | |
488 | [ID_ADIS16135] = { | |
489 | .precision = IIO_DEGREE_TO_RAD(300), | |
490 | .fullscale = 24000, | |
491 | }, | |
492 | [ID_ADIS16136] = { | |
493 | .precision = IIO_DEGREE_TO_RAD(450), | |
494 | .fullscale = 24623, | |
495 | }, | |
5450c360 LPC |
496 | [ID_ADIS16137] = { |
497 | .precision = IIO_DEGREE_TO_RAD(1000), | |
498 | .fullscale = 24609, | |
499 | }, | |
9caed0d9 LPC |
500 | }; |
501 | ||
502 | static int adis16136_probe(struct spi_device *spi) | |
503 | { | |
504 | const struct spi_device_id *id = spi_get_device_id(spi); | |
505 | struct adis16136 *adis16136; | |
506 | struct iio_dev *indio_dev; | |
507 | int ret; | |
508 | ||
c0ca6d31 | 509 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16136)); |
9caed0d9 LPC |
510 | if (indio_dev == NULL) |
511 | return -ENOMEM; | |
512 | ||
513 | spi_set_drvdata(spi, indio_dev); | |
514 | ||
515 | adis16136 = iio_priv(indio_dev); | |
516 | ||
517 | adis16136->chip_info = &adis16136_chip_info[id->driver_data]; | |
518 | indio_dev->dev.parent = &spi->dev; | |
519 | indio_dev->name = spi_get_device_id(spi)->name; | |
520 | indio_dev->channels = adis16136_channels; | |
521 | indio_dev->num_channels = ARRAY_SIZE(adis16136_channels); | |
522 | indio_dev->info = &adis16136_info; | |
523 | indio_dev->modes = INDIO_DIRECT_MODE; | |
524 | ||
525 | ret = adis_init(&adis16136->adis, indio_dev, spi, &adis16136_data); | |
526 | if (ret) | |
c0ca6d31 | 527 | return ret; |
9caed0d9 LPC |
528 | |
529 | ret = adis_setup_buffer_and_trigger(&adis16136->adis, indio_dev, NULL); | |
530 | if (ret) | |
c0ca6d31 | 531 | return ret; |
9caed0d9 LPC |
532 | |
533 | ret = adis16136_initial_setup(indio_dev); | |
534 | if (ret) | |
535 | goto error_cleanup_buffer; | |
536 | ||
537 | ret = iio_device_register(indio_dev); | |
538 | if (ret) | |
539 | goto error_stop_device; | |
540 | ||
541 | adis16136_debugfs_init(indio_dev); | |
542 | ||
543 | return 0; | |
544 | ||
545 | error_stop_device: | |
546 | adis16136_stop_device(indio_dev); | |
547 | error_cleanup_buffer: | |
548 | adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); | |
9caed0d9 LPC |
549 | return ret; |
550 | } | |
551 | ||
552 | static int adis16136_remove(struct spi_device *spi) | |
553 | { | |
554 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
555 | struct adis16136 *adis16136 = iio_priv(indio_dev); | |
556 | ||
557 | iio_device_unregister(indio_dev); | |
558 | adis16136_stop_device(indio_dev); | |
559 | ||
560 | adis_cleanup_buffer_and_trigger(&adis16136->adis, indio_dev); | |
561 | ||
9caed0d9 LPC |
562 | return 0; |
563 | } | |
564 | ||
565 | static const struct spi_device_id adis16136_ids[] = { | |
566 | { "adis16133", ID_ADIS16133 }, | |
567 | { "adis16135", ID_ADIS16135 }, | |
568 | { "adis16136", ID_ADIS16136 }, | |
5450c360 | 569 | { "adis16137", ID_ADIS16137 }, |
9caed0d9 LPC |
570 | { } |
571 | }; | |
572 | MODULE_DEVICE_TABLE(spi, adis16136_ids); | |
573 | ||
574 | static struct spi_driver adis16136_driver = { | |
575 | .driver = { | |
576 | .name = "adis16136", | |
9caed0d9 LPC |
577 | }, |
578 | .id_table = adis16136_ids, | |
579 | .probe = adis16136_probe, | |
580 | .remove = adis16136_remove, | |
581 | }; | |
582 | module_spi_driver(adis16136_driver); | |
583 | ||
584 | MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>"); | |
585 | MODULE_DESCRIPTION("Analog Devices ADIS16133/ADIS16135/ADIS16136 gyroscope driver"); | |
586 | MODULE_LICENSE("GPL v2"); |