Commit | Line | Data |
---|---|---|
671ece14 BS |
1 | /* |
2 | * ADIS16209 Programmable Digital Vibration Sensor driver | |
3 | * | |
4 | * Copyright 2010 Analog Devices Inc. | |
5 | * | |
6 | * Licensed under the GPL-2 or later. | |
7 | */ | |
8 | ||
671ece14 BS |
9 | #include <linux/delay.h> |
10 | #include <linux/mutex.h> | |
11 | #include <linux/device.h> | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/spi/spi.h> | |
1cb6c1f5 | 14 | #include <linux/slab.h> |
671ece14 BS |
15 | #include <linux/sysfs.h> |
16 | #include <linux/list.h> | |
99c97852 | 17 | #include <linux/module.h> |
671ece14 BS |
18 | |
19 | #include "../iio.h" | |
20 | #include "../sysfs.h" | |
2662051e | 21 | #include "../ring_generic.h" |
671ece14 BS |
22 | |
23 | #include "adis16209.h" | |
24 | ||
25 | #define DRIVER_NAME "adis16209" | |
26 | ||
671ece14 BS |
27 | /** |
28 | * adis16209_spi_write_reg_8() - write single byte to a register | |
a34c26dc | 29 | * @indio_dev: iio device associated with actual device |
671ece14 BS |
30 | * @reg_address: the address of the register to be written |
31 | * @val: the value to write | |
32 | **/ | |
a34c26dc JC |
33 | static int adis16209_spi_write_reg_8(struct iio_dev *indio_dev, |
34 | u8 reg_address, | |
35 | u8 val) | |
671ece14 BS |
36 | { |
37 | int ret; | |
35212dfa | 38 | struct adis16209_state *st = iio_priv(indio_dev); |
671ece14 BS |
39 | |
40 | mutex_lock(&st->buf_lock); | |
41 | st->tx[0] = ADIS16209_WRITE_REG(reg_address); | |
42 | st->tx[1] = val; | |
43 | ||
44 | ret = spi_write(st->us, st->tx, 2); | |
45 | mutex_unlock(&st->buf_lock); | |
46 | ||
47 | return ret; | |
48 | } | |
49 | ||
50 | /** | |
51 | * adis16209_spi_write_reg_16() - write 2 bytes to a pair of registers | |
a34c26dc | 52 | * @indio_dev: iio device associated actual device |
671ece14 BS |
53 | * @reg_address: the address of the lower of the two registers. Second register |
54 | * is assumed to have address one greater. | |
55 | * @val: value to be written | |
56 | **/ | |
a34c26dc JC |
57 | static int adis16209_spi_write_reg_16(struct iio_dev *indio_dev, |
58 | u8 lower_reg_address, | |
59 | u16 value) | |
671ece14 BS |
60 | { |
61 | int ret; | |
62 | struct spi_message msg; | |
35212dfa | 63 | struct adis16209_state *st = iio_priv(indio_dev); |
671ece14 BS |
64 | struct spi_transfer xfers[] = { |
65 | { | |
66 | .tx_buf = st->tx, | |
67 | .bits_per_word = 8, | |
68 | .len = 2, | |
69 | .cs_change = 1, | |
00ae7946 | 70 | .delay_usecs = 30, |
671ece14 BS |
71 | }, { |
72 | .tx_buf = st->tx + 2, | |
73 | .bits_per_word = 8, | |
74 | .len = 2, | |
00ae7946 | 75 | .delay_usecs = 30, |
671ece14 BS |
76 | }, |
77 | }; | |
78 | ||
79 | mutex_lock(&st->buf_lock); | |
80 | st->tx[0] = ADIS16209_WRITE_REG(lower_reg_address); | |
81 | st->tx[1] = value & 0xFF; | |
82 | st->tx[2] = ADIS16209_WRITE_REG(lower_reg_address + 1); | |
83 | st->tx[3] = (value >> 8) & 0xFF; | |
84 | ||
85 | spi_message_init(&msg); | |
86 | spi_message_add_tail(&xfers[0], &msg); | |
87 | spi_message_add_tail(&xfers[1], &msg); | |
88 | ret = spi_sync(st->us, &msg); | |
89 | mutex_unlock(&st->buf_lock); | |
90 | ||
91 | return ret; | |
92 | } | |
93 | ||
94 | /** | |
95 | * adis16209_spi_read_reg_16() - read 2 bytes from a 16-bit register | |
a34c26dc | 96 | * @indio_dev: iio device associated with device |
671ece14 BS |
97 | * @reg_address: the address of the lower of the two registers. Second register |
98 | * is assumed to have address one greater. | |
99 | * @val: somewhere to pass back the value read | |
100 | **/ | |
a34c26dc JC |
101 | static int adis16209_spi_read_reg_16(struct iio_dev *indio_dev, |
102 | u8 lower_reg_address, | |
103 | u16 *val) | |
671ece14 BS |
104 | { |
105 | struct spi_message msg; | |
35212dfa | 106 | struct adis16209_state *st = iio_priv(indio_dev); |
671ece14 BS |
107 | int ret; |
108 | struct spi_transfer xfers[] = { | |
109 | { | |
110 | .tx_buf = st->tx, | |
111 | .bits_per_word = 8, | |
112 | .len = 2, | |
113 | .cs_change = 1, | |
00ae7946 | 114 | .delay_usecs = 30, |
671ece14 BS |
115 | }, { |
116 | .rx_buf = st->rx, | |
117 | .bits_per_word = 8, | |
118 | .len = 2, | |
00ae7946 | 119 | .delay_usecs = 30, |
671ece14 BS |
120 | }, |
121 | }; | |
122 | ||
123 | mutex_lock(&st->buf_lock); | |
124 | st->tx[0] = ADIS16209_READ_REG(lower_reg_address); | |
125 | st->tx[1] = 0; | |
126 | ||
127 | spi_message_init(&msg); | |
128 | spi_message_add_tail(&xfers[0], &msg); | |
129 | spi_message_add_tail(&xfers[1], &msg); | |
130 | ret = spi_sync(st->us, &msg); | |
131 | if (ret) { | |
132 | dev_err(&st->us->dev, | |
133 | "problem when reading 16 bit register 0x%02X", | |
134 | lower_reg_address); | |
135 | goto error_ret; | |
136 | } | |
137 | *val = (st->rx[0] << 8) | st->rx[1]; | |
138 | ||
139 | error_ret: | |
140 | mutex_unlock(&st->buf_lock); | |
141 | return ret; | |
142 | } | |
143 | ||
a34c26dc | 144 | static int adis16209_reset(struct iio_dev *indio_dev) |
671ece14 BS |
145 | { |
146 | int ret; | |
a34c26dc | 147 | ret = adis16209_spi_write_reg_8(indio_dev, |
671ece14 BS |
148 | ADIS16209_GLOB_CMD, |
149 | ADIS16209_GLOB_CMD_SW_RESET); | |
150 | if (ret) | |
a34c26dc | 151 | dev_err(&indio_dev->dev, "problem resetting device"); |
671ece14 BS |
152 | |
153 | return ret; | |
154 | } | |
155 | ||
156 | static ssize_t adis16209_write_reset(struct device *dev, | |
157 | struct device_attribute *attr, | |
158 | const char *buf, size_t len) | |
159 | { | |
a34c26dc JC |
160 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
161 | ||
671ece14 BS |
162 | if (len < 1) |
163 | return -EINVAL; | |
164 | switch (buf[0]) { | |
165 | case '1': | |
166 | case 'y': | |
167 | case 'Y': | |
a34c26dc | 168 | return adis16209_reset(indio_dev); |
671ece14 BS |
169 | } |
170 | return -EINVAL; | |
171 | } | |
172 | ||
a34c26dc | 173 | int adis16209_set_irq(struct iio_dev *indio_dev, bool enable) |
671ece14 BS |
174 | { |
175 | int ret = 0; | |
176 | u16 msc; | |
177 | ||
a34c26dc | 178 | ret = adis16209_spi_read_reg_16(indio_dev, ADIS16209_MSC_CTRL, &msc); |
671ece14 BS |
179 | if (ret) |
180 | goto error_ret; | |
181 | ||
182 | msc |= ADIS16209_MSC_CTRL_ACTIVE_HIGH; | |
183 | msc &= ~ADIS16209_MSC_CTRL_DATA_RDY_DIO2; | |
184 | if (enable) | |
185 | msc |= ADIS16209_MSC_CTRL_DATA_RDY_EN; | |
186 | else | |
187 | msc &= ~ADIS16209_MSC_CTRL_DATA_RDY_EN; | |
188 | ||
a34c26dc | 189 | ret = adis16209_spi_write_reg_16(indio_dev, ADIS16209_MSC_CTRL, msc); |
671ece14 BS |
190 | |
191 | error_ret: | |
192 | return ret; | |
193 | } | |
194 | ||
a34c26dc | 195 | static int adis16209_check_status(struct iio_dev *indio_dev) |
671ece14 BS |
196 | { |
197 | u16 status; | |
198 | int ret; | |
199 | ||
a34c26dc JC |
200 | ret = adis16209_spi_read_reg_16(indio_dev, |
201 | ADIS16209_DIAG_STAT, &status); | |
671ece14 | 202 | if (ret < 0) { |
a34c26dc | 203 | dev_err(&indio_dev->dev, "Reading status failed\n"); |
671ece14 BS |
204 | goto error_ret; |
205 | } | |
206 | ret = status & 0x1F; | |
207 | ||
208 | if (status & ADIS16209_DIAG_STAT_SELFTEST_FAIL) | |
a34c26dc | 209 | dev_err(&indio_dev->dev, "Self test failure\n"); |
671ece14 | 210 | if (status & ADIS16209_DIAG_STAT_SPI_FAIL) |
a34c26dc | 211 | dev_err(&indio_dev->dev, "SPI failure\n"); |
671ece14 | 212 | if (status & ADIS16209_DIAG_STAT_FLASH_UPT) |
a34c26dc | 213 | dev_err(&indio_dev->dev, "Flash update failed\n"); |
671ece14 | 214 | if (status & ADIS16209_DIAG_STAT_POWER_HIGH) |
a34c26dc | 215 | dev_err(&indio_dev->dev, "Power supply above 3.625V\n"); |
671ece14 | 216 | if (status & ADIS16209_DIAG_STAT_POWER_LOW) |
a34c26dc | 217 | dev_err(&indio_dev->dev, "Power supply below 3.15V\n"); |
671ece14 BS |
218 | |
219 | error_ret: | |
220 | return ret; | |
221 | } | |
222 | ||
a34c26dc | 223 | static int adis16209_self_test(struct iio_dev *indio_dev) |
671ece14 BS |
224 | { |
225 | int ret; | |
a34c26dc | 226 | ret = adis16209_spi_write_reg_16(indio_dev, |
671ece14 BS |
227 | ADIS16209_MSC_CTRL, |
228 | ADIS16209_MSC_CTRL_SELF_TEST_EN); | |
229 | if (ret) { | |
a34c26dc | 230 | dev_err(&indio_dev->dev, "problem starting self test"); |
671ece14 BS |
231 | goto err_ret; |
232 | } | |
233 | ||
a34c26dc | 234 | adis16209_check_status(indio_dev); |
671ece14 BS |
235 | |
236 | err_ret: | |
237 | return ret; | |
238 | } | |
239 | ||
a34c26dc | 240 | static int adis16209_initial_setup(struct iio_dev *indio_dev) |
671ece14 BS |
241 | { |
242 | int ret; | |
671ece14 BS |
243 | |
244 | /* Disable IRQ */ | |
a34c26dc | 245 | ret = adis16209_set_irq(indio_dev, false); |
671ece14 | 246 | if (ret) { |
a34c26dc | 247 | dev_err(&indio_dev->dev, "disable irq failed"); |
671ece14 BS |
248 | goto err_ret; |
249 | } | |
250 | ||
251 | /* Do self test */ | |
a34c26dc | 252 | ret = adis16209_self_test(indio_dev); |
671ece14 | 253 | if (ret) { |
a34c26dc | 254 | dev_err(&indio_dev->dev, "self test failure"); |
671ece14 BS |
255 | goto err_ret; |
256 | } | |
257 | ||
258 | /* Read status register to check the result */ | |
a34c26dc | 259 | ret = adis16209_check_status(indio_dev); |
671ece14 | 260 | if (ret) { |
a34c26dc JC |
261 | adis16209_reset(indio_dev); |
262 | dev_err(&indio_dev->dev, "device not playing ball -> reset"); | |
671ece14 | 263 | msleep(ADIS16209_STARTUP_DELAY); |
a34c26dc | 264 | ret = adis16209_check_status(indio_dev); |
671ece14 | 265 | if (ret) { |
a34c26dc | 266 | dev_err(&indio_dev->dev, "giving up"); |
671ece14 BS |
267 | goto err_ret; |
268 | } | |
269 | } | |
270 | ||
671ece14 BS |
271 | err_ret: |
272 | return ret; | |
273 | } | |
274 | ||
a34c26dc JC |
275 | enum adis16209_chan { |
276 | in_supply, | |
277 | temp, | |
278 | accel_x, | |
279 | accel_y, | |
280 | incli_x, | |
281 | incli_y, | |
282 | in_aux, | |
283 | rot, | |
284 | }; | |
285 | ||
286 | static const u8 adis16209_addresses[8][2] = { | |
287 | [in_supply] = { ADIS16209_SUPPLY_OUT }, | |
288 | [in_aux] = { ADIS16209_AUX_ADC }, | |
289 | [accel_x] = { ADIS16209_XACCL_OUT, ADIS16209_XACCL_NULL }, | |
290 | [accel_y] = { ADIS16209_YACCL_OUT, ADIS16209_YACCL_NULL }, | |
291 | [incli_x] = { ADIS16209_XINCL_OUT, ADIS16209_XINCL_NULL }, | |
292 | [incli_y] = { ADIS16209_YINCL_OUT, ADIS16209_YINCL_NULL }, | |
293 | [rot] = { ADIS16209_ROT_OUT }, | |
294 | [temp] = { ADIS16209_TEMP_OUT }, | |
295 | }; | |
296 | ||
297 | static int adis16209_write_raw(struct iio_dev *indio_dev, | |
298 | struct iio_chan_spec const *chan, | |
299 | int val, | |
300 | int val2, | |
301 | long mask) | |
302 | { | |
303 | int bits; | |
304 | s16 val16; | |
305 | u8 addr; | |
306 | switch (mask) { | |
307 | case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): | |
308 | switch (chan->type) { | |
309 | case IIO_ACCEL: | |
310 | case IIO_INCLI: | |
311 | bits = 14; | |
312 | break; | |
313 | default: | |
314 | return -EINVAL; | |
315 | }; | |
316 | val16 = val & ((1 << bits) - 1); | |
317 | addr = adis16209_addresses[chan->address][1]; | |
318 | return adis16209_spi_write_reg_16(indio_dev, addr, val16); | |
319 | } | |
320 | return -EINVAL; | |
321 | } | |
322 | ||
323 | static int adis16209_read_raw(struct iio_dev *indio_dev, | |
324 | struct iio_chan_spec const *chan, | |
325 | int *val, int *val2, | |
326 | long mask) | |
327 | { | |
328 | int ret; | |
329 | int bits; | |
330 | u8 addr; | |
331 | s16 val16; | |
332 | ||
333 | switch (mask) { | |
334 | case 0: | |
335 | mutex_lock(&indio_dev->mlock); | |
336 | addr = adis16209_addresses[chan->address][0]; | |
337 | ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16); | |
8f896155 DC |
338 | if (ret) { |
339 | mutex_unlock(&indio_dev->mlock); | |
a34c26dc | 340 | return ret; |
8f896155 | 341 | } |
a34c26dc JC |
342 | |
343 | if (val16 & ADIS16209_ERROR_ACTIVE) { | |
344 | ret = adis16209_check_status(indio_dev); | |
8f896155 DC |
345 | if (ret) { |
346 | mutex_unlock(&indio_dev->mlock); | |
a34c26dc | 347 | return ret; |
8f896155 | 348 | } |
a34c26dc JC |
349 | } |
350 | val16 = val16 & ((1 << chan->scan_type.realbits) - 1); | |
351 | if (chan->scan_type.sign == 's') | |
352 | val16 = (s16)(val16 << | |
353 | (16 - chan->scan_type.realbits)) >> | |
354 | (16 - chan->scan_type.realbits); | |
355 | *val = val16; | |
356 | mutex_unlock(&indio_dev->mlock); | |
357 | return IIO_VAL_INT; | |
358 | case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): | |
359 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | |
360 | switch (chan->type) { | |
361 | case IIO_IN: | |
362 | *val = 0; | |
363 | if (chan->channel == 0) | |
364 | *val2 = 305180; | |
365 | else | |
366 | *val2 = 610500; | |
367 | return IIO_VAL_INT_PLUS_MICRO; | |
368 | case IIO_TEMP: | |
369 | *val = 0; | |
370 | *val2 = -470000; | |
371 | return IIO_VAL_INT_PLUS_MICRO; | |
372 | case IIO_ACCEL: | |
373 | *val = 0; | |
374 | *val2 = 2394; | |
375 | return IIO_VAL_INT_PLUS_MICRO; | |
376 | case IIO_INCLI: | |
377 | *val = 0; | |
378 | *val2 = 436; | |
379 | return IIO_VAL_INT_PLUS_MICRO; | |
380 | default: | |
381 | return -EINVAL; | |
382 | } | |
383 | break; | |
384 | case (1 << IIO_CHAN_INFO_OFFSET_SEPARATE): | |
385 | *val = 25; | |
386 | return IIO_VAL_INT; | |
387 | case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE): | |
388 | switch (chan->type) { | |
389 | case IIO_ACCEL: | |
390 | bits = 14; | |
391 | break; | |
392 | default: | |
393 | return -EINVAL; | |
394 | }; | |
395 | mutex_lock(&indio_dev->mlock); | |
396 | addr = adis16209_addresses[chan->address][1]; | |
397 | ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16); | |
398 | if (ret) { | |
399 | mutex_unlock(&indio_dev->mlock); | |
400 | return ret; | |
401 | } | |
402 | val16 &= (1 << bits) - 1; | |
403 | val16 = (s16)(val16 << (16 - bits)) >> (16 - bits); | |
404 | *val = val16; | |
405 | mutex_unlock(&indio_dev->mlock); | |
406 | return IIO_VAL_INT; | |
407 | } | |
408 | return -EINVAL; | |
409 | } | |
410 | ||
411 | static struct iio_chan_spec adis16209_channels[] = { | |
412 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | |
413 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | |
414 | in_supply, ADIS16209_SCAN_SUPPLY, | |
415 | IIO_ST('u', 14, 16, 0), 0), | |
416 | IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, | |
417 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE) | | |
418 | (1 << IIO_CHAN_INFO_OFFSET_SEPARATE), | |
419 | temp, ADIS16209_SCAN_TEMP, | |
420 | IIO_ST('u', 12, 16, 0), 0), | |
421 | IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, | |
422 | (1 << IIO_CHAN_INFO_SCALE_SHARED) | | |
423 | (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), | |
424 | accel_x, ADIS16209_SCAN_ACC_X, | |
425 | IIO_ST('s', 14, 16, 0), 0), | |
426 | IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, | |
427 | (1 << IIO_CHAN_INFO_SCALE_SHARED) | | |
428 | (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE), | |
429 | accel_y, ADIS16209_SCAN_ACC_Y, | |
430 | IIO_ST('s', 14, 16, 0), 0), | |
431 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, | |
432 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | |
433 | in_aux, ADIS16209_SCAN_AUX_ADC, | |
434 | IIO_ST('u', 12, 16, 0), 0), | |
435 | IIO_CHAN(IIO_INCLI, 0, 1, 0, NULL, 0, IIO_MOD_X, | |
436 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
437 | incli_x, ADIS16209_SCAN_INCLI_X, | |
438 | IIO_ST('s', 14, 16, 0), 0), | |
439 | IIO_CHAN(IIO_INCLI, 0, 1, 0, NULL, 0, IIO_MOD_Y, | |
440 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | |
441 | incli_y, ADIS16209_SCAN_INCLI_Y, | |
442 | IIO_ST('s', 14, 16, 0), 0), | |
443 | IIO_CHAN(IIO_ROT, 0, 1, 0, NULL, 0, IIO_MOD_X, | |
444 | 0, | |
445 | rot, ADIS16209_SCAN_ROT, | |
446 | IIO_ST('s', 14, 16, 0), 0), | |
447 | IIO_CHAN_SOFT_TIMESTAMP(8) | |
448 | }; | |
671ece14 BS |
449 | |
450 | static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16209_write_reset, 0); | |
451 | ||
671ece14 | 452 | static struct attribute *adis16209_attributes[] = { |
671ece14 | 453 | &iio_dev_attr_reset.dev_attr.attr, |
671ece14 BS |
454 | NULL |
455 | }; | |
456 | ||
457 | static const struct attribute_group adis16209_attribute_group = { | |
458 | .attrs = adis16209_attributes, | |
459 | }; | |
460 | ||
6fe8135f JC |
461 | static const struct iio_info adis16209_info = { |
462 | .attrs = &adis16209_attribute_group, | |
463 | .read_raw = &adis16209_read_raw, | |
464 | .write_raw = &adis16209_write_raw, | |
465 | .driver_module = THIS_MODULE, | |
466 | }; | |
467 | ||
671ece14 BS |
468 | static int __devinit adis16209_probe(struct spi_device *spi) |
469 | { | |
470 | int ret, regdone = 0; | |
35212dfa JC |
471 | struct adis16209_state *st; |
472 | struct iio_dev *indio_dev; | |
671ece14 | 473 | |
35212dfa JC |
474 | /* setup the industrialio driver allocated elements */ |
475 | indio_dev = iio_allocate_device(sizeof(*st)); | |
476 | if (indio_dev == NULL) { | |
671ece14 | 477 | ret = -ENOMEM; |
35212dfa | 478 | goto error_ret; |
671ece14 | 479 | } |
35212dfa JC |
480 | st = iio_priv(indio_dev); |
481 | /* this is only used for removal purposes */ | |
482 | spi_set_drvdata(spi, indio_dev); | |
671ece14 BS |
483 | st->us = spi; |
484 | mutex_init(&st->buf_lock); | |
671ece14 | 485 | |
35212dfa JC |
486 | indio_dev->name = spi->dev.driver->name; |
487 | indio_dev->dev.parent = &spi->dev; | |
488 | indio_dev->info = &adis16209_info; | |
489 | indio_dev->channels = adis16209_channels; | |
490 | indio_dev->num_channels = ARRAY_SIZE(adis16209_channels); | |
491 | indio_dev->modes = INDIO_DIRECT_MODE; | |
671ece14 | 492 | |
35212dfa | 493 | ret = adis16209_configure_ring(indio_dev); |
671ece14 BS |
494 | if (ret) |
495 | goto error_free_dev; | |
496 | ||
35212dfa | 497 | ret = iio_device_register(indio_dev); |
671ece14 BS |
498 | if (ret) |
499 | goto error_unreg_ring_funcs; | |
500 | regdone = 1; | |
501 | ||
1aa04278 | 502 | ret = iio_ring_buffer_register_ex(indio_dev, 0, |
a34c26dc JC |
503 | adis16209_channels, |
504 | ARRAY_SIZE(adis16209_channels)); | |
671ece14 BS |
505 | if (ret) { |
506 | printk(KERN_ERR "failed to initialize the ring\n"); | |
507 | goto error_unreg_ring_funcs; | |
508 | } | |
509 | ||
510 | if (spi->irq) { | |
35212dfa | 511 | ret = adis16209_probe_trigger(indio_dev); |
671ece14 | 512 | if (ret) |
48f27194 | 513 | goto error_uninitialize_ring; |
671ece14 BS |
514 | } |
515 | ||
516 | /* Get the device into a sane initial state */ | |
35212dfa | 517 | ret = adis16209_initial_setup(indio_dev); |
671ece14 BS |
518 | if (ret) |
519 | goto error_remove_trigger; | |
520 | return 0; | |
521 | ||
522 | error_remove_trigger: | |
35212dfa | 523 | adis16209_remove_trigger(indio_dev); |
671ece14 | 524 | error_uninitialize_ring: |
1aa04278 | 525 | iio_ring_buffer_unregister(indio_dev); |
671ece14 | 526 | error_unreg_ring_funcs: |
35212dfa | 527 | adis16209_unconfigure_ring(indio_dev); |
671ece14 BS |
528 | error_free_dev: |
529 | if (regdone) | |
35212dfa | 530 | iio_device_unregister(indio_dev); |
671ece14 | 531 | else |
35212dfa | 532 | iio_free_device(indio_dev); |
671ece14 BS |
533 | error_ret: |
534 | return ret; | |
535 | } | |
536 | ||
537 | static int adis16209_remove(struct spi_device *spi) | |
538 | { | |
35212dfa | 539 | struct iio_dev *indio_dev = spi_get_drvdata(spi); |
671ece14 BS |
540 | |
541 | flush_scheduled_work(); | |
542 | ||
543 | adis16209_remove_trigger(indio_dev); | |
1aa04278 | 544 | iio_ring_buffer_unregister(indio_dev); |
671ece14 BS |
545 | iio_device_unregister(indio_dev); |
546 | adis16209_unconfigure_ring(indio_dev); | |
671ece14 BS |
547 | |
548 | return 0; | |
549 | } | |
550 | ||
551 | static struct spi_driver adis16209_driver = { | |
552 | .driver = { | |
553 | .name = "adis16209", | |
554 | .owner = THIS_MODULE, | |
555 | }, | |
556 | .probe = adis16209_probe, | |
557 | .remove = __devexit_p(adis16209_remove), | |
558 | }; | |
559 | ||
560 | static __init int adis16209_init(void) | |
561 | { | |
562 | return spi_register_driver(&adis16209_driver); | |
563 | } | |
564 | module_init(adis16209_init); | |
565 | ||
566 | static __exit void adis16209_exit(void) | |
567 | { | |
568 | spi_unregister_driver(&adis16209_driver); | |
569 | } | |
570 | module_exit(adis16209_exit); | |
571 | ||
572 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | |
573 | MODULE_DESCRIPTION("Analog Devices ADIS16209 Digital Vibration Sensor driver"); | |
574 | MODULE_LICENSE("GPL v2"); |