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