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