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