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