blob: c755089c711715802ce6e90818a35bae41941acb [file] [log] [blame]
Barry Song06f19622010-05-16 21:11:37 +01001/*
2 * ADIS16220 Programmable Digital Vibration Sensor driver
3 *
4 * Copyright 2010 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
Barry Song06f19622010-05-16 21:11:37 +01009#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>
Mike Frysinger1cb6c1f2010-05-23 03:10:35 -040014#include <linux/slab.h>
Barry Song06f19622010-05-16 21:11:37 +010015#include <linux/sysfs.h>
Greg Kroah-Hartman6f4ebab2011-08-24 14:21:48 -070016#include <linux/module.h>
Barry Song06f19622010-05-16 21:11:37 +010017
Jonathan Cameron06458e22012-04-25 15:54:58 +010018#include <linux/iio/iio.h>
19#include <linux/iio/sysfs.h>
Barry Song06f19622010-05-16 21:11:37 +010020
21#include "adis16220.h"
22
23#define DRIVER_NAME "adis16220"
24
Barry Song06f19622010-05-16 21:11:37 +010025/**
26 * adis16220_spi_write_reg_8() - write single byte to a register
Jonathan Cameron79910292011-08-12 17:48:02 +010027 * @indio_dev: iio device associated with child of actual device
Barry Song06f19622010-05-16 21:11:37 +010028 * @reg_address: the address of the register to be written
29 * @val: the value to write
30 **/
Jonathan Cameron79910292011-08-12 17:48:02 +010031static int adis16220_spi_write_reg_8(struct iio_dev *indio_dev,
Barry Song06f19622010-05-16 21:11:37 +010032 u8 reg_address,
33 u8 val)
34{
35 int ret;
Jonathan Cameron01a67212011-06-27 13:07:15 +010036 struct adis16220_state *st = iio_priv(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +010037
38 mutex_lock(&st->buf_lock);
39 st->tx[0] = ADIS16220_WRITE_REG(reg_address);
40 st->tx[1] = val;
41
42 ret = spi_write(st->us, st->tx, 2);
43 mutex_unlock(&st->buf_lock);
44
45 return ret;
46}
47
48/**
49 * adis16220_spi_write_reg_16() - write 2 bytes to a pair of registers
Jonathan Cameron79910292011-08-12 17:48:02 +010050 * @indio_dev: iio device associated with child of actual device
Barry Song06f19622010-05-16 21:11:37 +010051 * @reg_address: the address of the lower of the two registers. Second register
52 * is assumed to have address one greater.
53 * @val: value to be written
54 **/
Jonathan Cameron79910292011-08-12 17:48:02 +010055static int adis16220_spi_write_reg_16(struct iio_dev *indio_dev,
Barry Song06f19622010-05-16 21:11:37 +010056 u8 lower_reg_address,
57 u16 value)
58{
59 int ret;
60 struct spi_message msg;
Jonathan Cameron01a67212011-06-27 13:07:15 +010061 struct adis16220_state *st = iio_priv(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +010062 struct spi_transfer xfers[] = {
63 {
64 .tx_buf = st->tx,
65 .bits_per_word = 8,
66 .len = 2,
67 .cs_change = 1,
Barry Song00ae7942010-06-04 17:19:54 +080068 .delay_usecs = 35,
Barry Song06f19622010-05-16 21:11:37 +010069 }, {
70 .tx_buf = st->tx + 2,
71 .bits_per_word = 8,
72 .len = 2,
Barry Song00ae7942010-06-04 17:19:54 +080073 .delay_usecs = 35,
Barry Song06f19622010-05-16 21:11:37 +010074 },
75 };
76
77 mutex_lock(&st->buf_lock);
78 st->tx[0] = ADIS16220_WRITE_REG(lower_reg_address);
79 st->tx[1] = value & 0xFF;
80 st->tx[2] = ADIS16220_WRITE_REG(lower_reg_address + 1);
81 st->tx[3] = (value >> 8) & 0xFF;
82
83 spi_message_init(&msg);
84 spi_message_add_tail(&xfers[0], &msg);
85 spi_message_add_tail(&xfers[1], &msg);
86 ret = spi_sync(st->us, &msg);
87 mutex_unlock(&st->buf_lock);
88
89 return ret;
90}
91
92/**
93 * adis16220_spi_read_reg_16() - read 2 bytes from a 16-bit register
Jonathan Cameron79910292011-08-12 17:48:02 +010094 * @indio_dev: iio device associated with child of actual device
Barry Song06f19622010-05-16 21:11:37 +010095 * @reg_address: the address of the lower of the two registers. Second register
96 * is assumed to have address one greater.
97 * @val: somewhere to pass back the value read
98 **/
Jonathan Cameron79910292011-08-12 17:48:02 +010099static int adis16220_spi_read_reg_16(struct iio_dev *indio_dev,
100 u8 lower_reg_address,
101 u16 *val)
Barry Song06f19622010-05-16 21:11:37 +0100102{
103 struct spi_message msg;
Jonathan Cameron01a67212011-06-27 13:07:15 +0100104 struct adis16220_state *st = iio_priv(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100105 int ret;
106 struct spi_transfer xfers[] = {
107 {
108 .tx_buf = st->tx,
109 .bits_per_word = 8,
110 .len = 2,
111 .cs_change = 1,
Barry Song00ae7942010-06-04 17:19:54 +0800112 .delay_usecs = 35,
Barry Song06f19622010-05-16 21:11:37 +0100113 }, {
114 .rx_buf = st->rx,
115 .bits_per_word = 8,
116 .len = 2,
117 .cs_change = 1,
Barry Song00ae7942010-06-04 17:19:54 +0800118 .delay_usecs = 35,
Barry Song06f19622010-05-16 21:11:37 +0100119 },
120 };
121
122 mutex_lock(&st->buf_lock);
123 st->tx[0] = ADIS16220_READ_REG(lower_reg_address);
124 st->tx[1] = 0;
Barry Song06f19622010-05-16 21:11:37 +0100125
126 spi_message_init(&msg);
127 spi_message_add_tail(&xfers[0], &msg);
128 spi_message_add_tail(&xfers[1], &msg);
129 ret = spi_sync(st->us, &msg);
130 if (ret) {
131 dev_err(&st->us->dev,
132 "problem when reading 16 bit register 0x%02X",
133 lower_reg_address);
134 goto error_ret;
135 }
136 *val = (st->rx[0] << 8) | st->rx[1];
137
138error_ret:
139 mutex_unlock(&st->buf_lock);
140 return ret;
141}
142
Barry Song06f19622010-05-16 21:11:37 +0100143static ssize_t adis16220_read_16bit(struct device *dev,
144 struct device_attribute *attr,
145 char *buf)
146{
Jonathan Cameron79910292011-08-12 17:48:02 +0100147 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
Lars-Peter Clausen4b522ce2012-05-12 15:39:43 +0200148 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Barry Song06f19622010-05-16 21:11:37 +0100149 ssize_t ret;
Jonathan Cameron79910292011-08-12 17:48:02 +0100150 s16 val = 0;
Barry Song06f19622010-05-16 21:11:37 +0100151
152 /* Take the iio_dev status lock */
153 mutex_lock(&indio_dev->mlock);
Jonathan Cameron79910292011-08-12 17:48:02 +0100154 ret = adis16220_spi_read_reg_16(indio_dev, this_attr->address,
155 (u16 *)&val);
Barry Song06f19622010-05-16 21:11:37 +0100156 mutex_unlock(&indio_dev->mlock);
Jonathan Cameron79910292011-08-12 17:48:02 +0100157 if (ret)
158 return ret;
159 return sprintf(buf, "%d\n", val);
Barry Song06f19622010-05-16 21:11:37 +0100160}
161
162static ssize_t adis16220_write_16bit(struct device *dev,
163 struct device_attribute *attr,
164 const char *buf,
165 size_t len)
166{
Lars-Peter Clausen4b522ce2012-05-12 15:39:43 +0200167 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Barry Song06f19622010-05-16 21:11:37 +0100168 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
169 int ret;
Andreas Ruprechtbae5b532011-11-27 23:17:40 +0100170 u16 val;
Barry Song06f19622010-05-16 21:11:37 +0100171
Andreas Ruprechtbae5b532011-11-27 23:17:40 +0100172 ret = kstrtou16(buf, 10, &val);
Barry Song06f19622010-05-16 21:11:37 +0100173 if (ret)
174 goto error_ret;
Jonathan Cameron79910292011-08-12 17:48:02 +0100175 ret = adis16220_spi_write_reg_16(indio_dev, this_attr->address, val);
Barry Song06f19622010-05-16 21:11:37 +0100176
177error_ret:
178 return ret ? ret : len;
179}
180
Jonathan Cameron79910292011-08-12 17:48:02 +0100181static int adis16220_capture(struct iio_dev *indio_dev)
Barry Song06f19622010-05-16 21:11:37 +0100182{
183 int ret;
Jonathan Cameron79910292011-08-12 17:48:02 +0100184 ret = adis16220_spi_write_reg_16(indio_dev,
Barry Song06f19622010-05-16 21:11:37 +0100185 ADIS16220_GLOB_CMD,
186 0xBF08); /* initiates a manual data capture */
187 if (ret)
Jonathan Cameron79910292011-08-12 17:48:02 +0100188 dev_err(&indio_dev->dev, "problem beginning capture");
Barry Song06f19622010-05-16 21:11:37 +0100189
190 msleep(10); /* delay for capture to finish */
191
192 return ret;
193}
194
Jonathan Cameron79910292011-08-12 17:48:02 +0100195static int adis16220_reset(struct iio_dev *indio_dev)
Barry Song06f19622010-05-16 21:11:37 +0100196{
197 int ret;
Jonathan Cameron79910292011-08-12 17:48:02 +0100198 ret = adis16220_spi_write_reg_8(indio_dev,
Barry Song06f19622010-05-16 21:11:37 +0100199 ADIS16220_GLOB_CMD,
200 ADIS16220_GLOB_CMD_SW_RESET);
201 if (ret)
Jonathan Cameron79910292011-08-12 17:48:02 +0100202 dev_err(&indio_dev->dev, "problem resetting device");
Barry Song06f19622010-05-16 21:11:37 +0100203
204 return ret;
205}
206
Barry Song06f19622010-05-16 21:11:37 +0100207static ssize_t adis16220_write_capture(struct device *dev,
208 struct device_attribute *attr,
209 const char *buf, size_t len)
210{
Lars-Peter Clausen4b522ce2012-05-12 15:39:43 +0200211 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
Jonathan Cameron79910292011-08-12 17:48:02 +0100212 bool val;
213 int ret;
214
215 ret = strtobool(buf, &val);
216 if (ret)
217 return ret;
218 if (!val)
219 return -EINVAL;
220 ret = adis16220_capture(indio_dev);
221 if (ret)
222 return ret;
223
224 return len;
Barry Song06f19622010-05-16 21:11:37 +0100225}
226
Jonathan Cameron79910292011-08-12 17:48:02 +0100227static int adis16220_check_status(struct iio_dev *indio_dev)
Barry Song06f19622010-05-16 21:11:37 +0100228{
229 u16 status;
230 int ret;
231
Jonathan Cameron79910292011-08-12 17:48:02 +0100232 ret = adis16220_spi_read_reg_16(indio_dev, ADIS16220_DIAG_STAT,
233 &status);
Barry Song06f19622010-05-16 21:11:37 +0100234
235 if (ret < 0) {
Jonathan Cameron79910292011-08-12 17:48:02 +0100236 dev_err(&indio_dev->dev, "Reading status failed\n");
Barry Song06f19622010-05-16 21:11:37 +0100237 goto error_ret;
238 }
239 ret = status & 0x7F;
240
241 if (status & ADIS16220_DIAG_STAT_VIOLATION)
Jonathan Cameron79910292011-08-12 17:48:02 +0100242 dev_err(&indio_dev->dev,
243 "Capture period violation/interruption\n");
Barry Song06f19622010-05-16 21:11:37 +0100244 if (status & ADIS16220_DIAG_STAT_SPI_FAIL)
Jonathan Cameron79910292011-08-12 17:48:02 +0100245 dev_err(&indio_dev->dev, "SPI failure\n");
Barry Song06f19622010-05-16 21:11:37 +0100246 if (status & ADIS16220_DIAG_STAT_FLASH_UPT)
Jonathan Cameron79910292011-08-12 17:48:02 +0100247 dev_err(&indio_dev->dev, "Flash update failed\n");
Barry Song06f19622010-05-16 21:11:37 +0100248 if (status & ADIS16220_DIAG_STAT_POWER_HIGH)
Jonathan Cameron79910292011-08-12 17:48:02 +0100249 dev_err(&indio_dev->dev, "Power supply above 3.625V\n");
Barry Song06f19622010-05-16 21:11:37 +0100250 if (status & ADIS16220_DIAG_STAT_POWER_LOW)
Jonathan Cameron79910292011-08-12 17:48:02 +0100251 dev_err(&indio_dev->dev, "Power supply below 3.15V\n");
Barry Song06f19622010-05-16 21:11:37 +0100252
253error_ret:
254 return ret;
255}
256
Jonathan Cameron79910292011-08-12 17:48:02 +0100257static int adis16220_self_test(struct iio_dev *indio_dev)
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100258{
259 int ret;
Jonathan Cameron79910292011-08-12 17:48:02 +0100260 ret = adis16220_spi_write_reg_16(indio_dev,
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100261 ADIS16220_MSC_CTRL,
262 ADIS16220_MSC_CTRL_SELF_TEST_EN);
263 if (ret) {
Jonathan Cameron79910292011-08-12 17:48:02 +0100264 dev_err(&indio_dev->dev, "problem starting self test");
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100265 goto err_ret;
266 }
267
Jonathan Cameron79910292011-08-12 17:48:02 +0100268 adis16220_check_status(indio_dev);
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100269
270err_ret:
271 return ret;
272}
273
Jonathan Cameron01a67212011-06-27 13:07:15 +0100274static int adis16220_initial_setup(struct iio_dev *indio_dev)
Barry Song06f19622010-05-16 21:11:37 +0100275{
276 int ret;
Barry Song06f19622010-05-16 21:11:37 +0100277
278 /* Do self test */
Jonathan Cameron79910292011-08-12 17:48:02 +0100279 ret = adis16220_self_test(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100280 if (ret) {
Jonathan Cameron79910292011-08-12 17:48:02 +0100281 dev_err(&indio_dev->dev, "self test failure");
Barry Song06f19622010-05-16 21:11:37 +0100282 goto err_ret;
283 }
284
285 /* Read status register to check the result */
Jonathan Cameron79910292011-08-12 17:48:02 +0100286 ret = adis16220_check_status(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100287 if (ret) {
Jonathan Cameron79910292011-08-12 17:48:02 +0100288 adis16220_reset(indio_dev);
289 dev_err(&indio_dev->dev, "device not playing ball -> reset");
Barry Song06f19622010-05-16 21:11:37 +0100290 msleep(ADIS16220_STARTUP_DELAY);
Jonathan Cameron79910292011-08-12 17:48:02 +0100291 ret = adis16220_check_status(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100292 if (ret) {
Jonathan Cameron79910292011-08-12 17:48:02 +0100293 dev_err(&indio_dev->dev, "giving up");
Barry Song06f19622010-05-16 21:11:37 +0100294 goto err_ret;
295 }
296 }
297
Barry Song06f19622010-05-16 21:11:37 +0100298err_ret:
299 return ret;
300}
301
Jonathan Cameron01a67212011-06-27 13:07:15 +0100302static ssize_t adis16220_capture_buffer_read(struct iio_dev *indio_dev,
Barry Song06f19622010-05-16 21:11:37 +0100303 char *buf,
304 loff_t off,
305 size_t count,
306 int addr)
307{
Jonathan Cameron01a67212011-06-27 13:07:15 +0100308 struct adis16220_state *st = iio_priv(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100309 struct spi_message msg;
310 struct spi_transfer xfers[] = {
311 {
312 .tx_buf = st->tx,
313 .bits_per_word = 8,
314 .len = 2,
315 .cs_change = 1,
316 .delay_usecs = 25,
317 }, {
318 .tx_buf = st->tx,
319 .rx_buf = st->rx,
320 .bits_per_word = 8,
321 .cs_change = 1,
322 .delay_usecs = 25,
323 },
324 };
325 int ret;
326 int i;
327
328 if (unlikely(!count))
329 return count;
330
331 if ((off >= ADIS16220_CAPTURE_SIZE) || (count & 1) || (off & 1))
332 return -EINVAL;
333
334 if (off + count > ADIS16220_CAPTURE_SIZE)
335 count = ADIS16220_CAPTURE_SIZE - off;
336
337 /* write the begin position of capture buffer */
Jonathan Cameron79910292011-08-12 17:48:02 +0100338 ret = adis16220_spi_write_reg_16(indio_dev,
Barry Song06f19622010-05-16 21:11:37 +0100339 ADIS16220_CAPT_PNTR,
340 off > 1);
341 if (ret)
342 return -EIO;
343
344 /* read count/2 values from capture buffer */
345 mutex_lock(&st->buf_lock);
346
347 for (i = 0; i < count; i += 2) {
348 st->tx[i] = ADIS16220_READ_REG(addr);
349 st->tx[i + 1] = 0;
350 }
351 xfers[1].len = count;
352
353 spi_message_init(&msg);
354 spi_message_add_tail(&xfers[0], &msg);
355 spi_message_add_tail(&xfers[1], &msg);
356 ret = spi_sync(st->us, &msg);
357 if (ret) {
358
359 mutex_unlock(&st->buf_lock);
360 return -EIO;
361 }
362
363 memcpy(buf, st->rx, count);
364
365 mutex_unlock(&st->buf_lock);
366 return count;
367}
368
Dan Carpenter794e7d92010-06-16 15:32:07 +0200369static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj,
Barry Song06f19622010-05-16 21:11:37 +0100370 struct bin_attribute *attr,
371 char *buf,
372 loff_t off,
373 size_t count)
374{
Lars-Peter Clausen8e3829c2012-08-07 08:55:00 +0100375 struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
Barry Song06f19622010-05-16 21:11:37 +0100376
Jonathan Cameron01a67212011-06-27 13:07:15 +0100377 return adis16220_capture_buffer_read(indio_dev, buf,
Barry Song06f19622010-05-16 21:11:37 +0100378 off, count,
379 ADIS16220_CAPT_BUFA);
380}
381
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100382static struct bin_attribute accel_bin = {
383 .attr = {
384 .name = "accel_bin",
385 .mode = S_IRUGO,
386 },
387 .read = adis16220_accel_bin_read,
388 .size = ADIS16220_CAPTURE_SIZE,
389};
390
Dan Carpenter794e7d92010-06-16 15:32:07 +0200391static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj,
Barry Song06f19622010-05-16 21:11:37 +0100392 struct bin_attribute *attr,
393 char *buf, loff_t off,
394 size_t count)
395{
Lars-Peter Clausen8e3829c2012-08-07 08:55:00 +0100396 struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
Barry Song06f19622010-05-16 21:11:37 +0100397
Jonathan Cameron01a67212011-06-27 13:07:15 +0100398 return adis16220_capture_buffer_read(indio_dev, buf,
Barry Song06f19622010-05-16 21:11:37 +0100399 off, count,
400 ADIS16220_CAPT_BUF1);
401}
402
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100403static struct bin_attribute adc1_bin = {
404 .attr = {
405 .name = "in0_bin",
406 .mode = S_IRUGO,
407 },
408 .read = adis16220_adc1_bin_read,
409 .size = ADIS16220_CAPTURE_SIZE,
410};
411
Dan Carpenter794e7d92010-06-16 15:32:07 +0200412static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj,
Barry Song06f19622010-05-16 21:11:37 +0100413 struct bin_attribute *attr,
414 char *buf, loff_t off,
415 size_t count)
416{
Lars-Peter Clausen8e3829c2012-08-07 08:55:00 +0100417 struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
Barry Song06f19622010-05-16 21:11:37 +0100418
Jonathan Cameron01a67212011-06-27 13:07:15 +0100419 return adis16220_capture_buffer_read(indio_dev, buf,
Barry Song06f19622010-05-16 21:11:37 +0100420 off, count,
421 ADIS16220_CAPT_BUF2);
422}
423
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100424
425static struct bin_attribute adc2_bin = {
426 .attr = {
427 .name = "in1_bin",
428 .mode = S_IRUGO,
429 },
430 .read = adis16220_adc2_bin_read,
431 .size = ADIS16220_CAPTURE_SIZE,
432};
433
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100434#define IIO_DEV_ATTR_CAPTURE(_store) \
Greg Kroah-Hartmanc9e51d92010-11-18 11:21:04 -0800435 IIO_DEVICE_ATTR(capture, S_IWUSR, NULL, _store, 0)
Barry Song06f19622010-05-16 21:11:37 +0100436
437static IIO_DEV_ATTR_CAPTURE(adis16220_write_capture);
438
Jonathan Cameron9a3af582010-05-16 21:11:38 +0100439#define IIO_DEV_ATTR_CAPTURE_COUNT(_mode, _show, _store, _addr) \
Barry Song06f19622010-05-16 21:11:37 +0100440 IIO_DEVICE_ATTR(capture_count, _mode, _show, _store, _addr)
441
442static IIO_DEV_ATTR_CAPTURE_COUNT(S_IWUSR | S_IRUGO,
443 adis16220_read_16bit,
444 adis16220_write_16bit,
445 ADIS16220_CAPT_PNTR);
446
Jonathan Cameron79910292011-08-12 17:48:02 +0100447enum adis16220_channel {
448 in_supply, in_1, in_2, accel, temp
449};
450
451struct adis16220_address_spec {
452 u8 addr;
453 u8 bits;
454 bool sign;
455};
456
457/* Address / bits / signed */
458static const struct adis16220_address_spec adis16220_addresses[][3] = {
459 [in_supply] = { { ADIS16220_CAPT_SUPPLY, 12, 0 }, },
460 [in_1] = { { ADIS16220_CAPT_BUF1, 16, 1 },
461 { ADIS16220_AIN1_NULL, 16, 1 },
462 { ADIS16220_CAPT_PEAK1, 16, 1 }, },
463 [in_2] = { { ADIS16220_CAPT_BUF2, 16, 1 },
464 { ADIS16220_AIN2_NULL, 16, 1 },
465 { ADIS16220_CAPT_PEAK2, 16, 1 }, },
466 [accel] = { { ADIS16220_CAPT_BUFA, 16, 1 },
467 { ADIS16220_ACCL_NULL, 16, 1 },
468 { ADIS16220_CAPT_PEAKA, 16, 1 }, },
469 [temp] = { { ADIS16220_CAPT_TEMP, 12, 0 }, }
470};
471
472static int adis16220_read_raw(struct iio_dev *indio_dev,
473 struct iio_chan_spec const *chan,
474 int *val, int *val2,
475 long mask)
476{
477 int ret = -EINVAL;
478 int addrind = 0;
479 u16 uval;
480 s16 sval;
481 u8 bits;
482
483 switch (mask) {
Jonathan Cameron31313fc2012-04-15 17:41:17 +0100484 case IIO_CHAN_INFO_RAW:
Jonathan Cameron79910292011-08-12 17:48:02 +0100485 addrind = 0;
486 break;
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100487 case IIO_CHAN_INFO_OFFSET:
Jonathan Cameron79910292011-08-12 17:48:02 +0100488 if (chan->type == IIO_TEMP) {
489 *val = 25;
490 return IIO_VAL_INT;
491 }
492 addrind = 1;
493 break;
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100494 case IIO_CHAN_INFO_PEAK:
Jonathan Cameron79910292011-08-12 17:48:02 +0100495 addrind = 2;
496 break;
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100497 case IIO_CHAN_INFO_SCALE:
Jonathan Cameron79910292011-08-12 17:48:02 +0100498 *val = 0;
499 switch (chan->type) {
500 case IIO_TEMP:
501 *val2 = -470000;
502 return IIO_VAL_INT_PLUS_MICRO;
503 case IIO_ACCEL:
504 *val2 = 1887042;
505 return IIO_VAL_INT_PLUS_MICRO;
Jonathan Cameron6835cb62011-09-27 09:56:41 +0100506 case IIO_VOLTAGE:
Jonathan Cameron79910292011-08-12 17:48:02 +0100507 if (chan->channel == 0)
508 *val2 = 0012221;
509 else /* Should really be dependent on VDD */
510 *val2 = 305;
511 return IIO_VAL_INT_PLUS_MICRO;
512 default:
513 return -EINVAL;
514 }
515 default:
516 return -EINVAL;
517 }
518 if (adis16220_addresses[chan->address][addrind].sign) {
519 ret = adis16220_spi_read_reg_16(indio_dev,
520 adis16220_addresses[chan
521 ->address]
522 [addrind].addr,
523 &sval);
524 if (ret)
525 return ret;
526 bits = adis16220_addresses[chan->address][addrind].bits;
527 sval &= (1 << bits) - 1;
528 sval = (s16)(sval << (16 - bits)) >> (16 - bits);
529 *val = sval;
530 return IIO_VAL_INT;
531 } else {
532 ret = adis16220_spi_read_reg_16(indio_dev,
533 adis16220_addresses[chan
534 ->address]
535 [addrind].addr,
536 &uval);
537 if (ret)
538 return ret;
539 bits = adis16220_addresses[chan->address][addrind].bits;
540 uval &= (1 << bits) - 1;
541 *val = uval;
542 return IIO_VAL_INT;
543 }
544}
545
546static const struct iio_chan_spec adis16220_channels[] = {
547 {
Jonathan Cameron6835cb62011-09-27 09:56:41 +0100548 .type = IIO_VOLTAGE,
Jonathan Cameron79910292011-08-12 17:48:02 +0100549 .indexed = 1,
550 .channel = 0,
551 .extend_name = "supply",
Jonathan Cameron31313fc2012-04-15 17:41:17 +0100552 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
553 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
Jonathan Cameron79910292011-08-12 17:48:02 +0100554 .address = in_supply,
555 }, {
556 .type = IIO_ACCEL,
Jonathan Cameron31313fc2012-04-15 17:41:17 +0100557 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
558 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100559 IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
560 IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
Jonathan Cameron79910292011-08-12 17:48:02 +0100561 .address = accel,
562 }, {
563 .type = IIO_TEMP,
564 .indexed = 1,
565 .channel = 0,
Jonathan Cameron31313fc2012-04-15 17:41:17 +0100566 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
567 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100568 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
Jonathan Cameron79910292011-08-12 17:48:02 +0100569 .address = temp,
570 }, {
Jonathan Cameron6835cb62011-09-27 09:56:41 +0100571 .type = IIO_VOLTAGE,
Jonathan Cameron79910292011-08-12 17:48:02 +0100572 .indexed = 1,
573 .channel = 1,
Jonathan Cameron31313fc2012-04-15 17:41:17 +0100574 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
575 IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
Jonathan Cameronc8a9f802011-10-26 17:41:36 +0100576 IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
Jonathan Cameron79910292011-08-12 17:48:02 +0100577 .address = in_1,
578 }, {
Jonathan Cameron6835cb62011-09-27 09:56:41 +0100579 .type = IIO_VOLTAGE,
Jonathan Cameron79910292011-08-12 17:48:02 +0100580 .indexed = 1,
581 .channel = 2,
Jonathan Cameron31313fc2012-04-15 17:41:17 +0100582 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
Jonathan Cameron79910292011-08-12 17:48:02 +0100583 .address = in_2,
584 }
585};
Barry Song06f19622010-05-16 21:11:37 +0100586
Barry Song06f19622010-05-16 21:11:37 +0100587static struct attribute *adis16220_attributes[] = {
Barry Song06f19622010-05-16 21:11:37 +0100588 &iio_dev_attr_capture.dev_attr.attr,
589 &iio_dev_attr_capture_count.dev_attr.attr,
Barry Song06f19622010-05-16 21:11:37 +0100590 NULL
591};
592
593static const struct attribute_group adis16220_attribute_group = {
594 .attrs = adis16220_attributes,
595};
596
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100597static const struct iio_info adis16220_info = {
598 .attrs = &adis16220_attribute_group,
599 .driver_module = THIS_MODULE,
Jonathan Cameron79910292011-08-12 17:48:02 +0100600 .read_raw = &adis16220_read_raw,
Jonathan Cameron6fe81352011-05-18 14:42:37 +0100601};
Jonathan Cameron79910292011-08-12 17:48:02 +0100602
Barry Song06f19622010-05-16 21:11:37 +0100603static int __devinit adis16220_probe(struct spi_device *spi)
604{
Jonathan Camerond2fffd62011-10-14 14:46:58 +0100605 int ret;
Jonathan Cameron01a67212011-06-27 13:07:15 +0100606 struct adis16220_state *st;
607 struct iio_dev *indio_dev;
608
609 /* setup the industrialio driver allocated elements */
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200610 indio_dev = iio_device_alloc(sizeof(*st));
Jonathan Cameron01a67212011-06-27 13:07:15 +0100611 if (indio_dev == NULL) {
612 ret = -ENOMEM;
Barry Song06f19622010-05-16 21:11:37 +0100613 goto error_ret;
614 }
Barry Song06f19622010-05-16 21:11:37 +0100615
Jonathan Cameron01a67212011-06-27 13:07:15 +0100616 st = iio_priv(indio_dev);
617 /* this is only used for removal purposes */
618 spi_set_drvdata(spi, indio_dev);
619
Barry Song06f19622010-05-16 21:11:37 +0100620 st->us = spi;
621 mutex_init(&st->buf_lock);
Barry Song06f19622010-05-16 21:11:37 +0100622
Jonathan Cameron01a67212011-06-27 13:07:15 +0100623 indio_dev->name = spi->dev.driver->name;
624 indio_dev->dev.parent = &spi->dev;
625 indio_dev->info = &adis16220_info;
626 indio_dev->modes = INDIO_DIRECT_MODE;
Jonathan Cameron79910292011-08-12 17:48:02 +0100627 indio_dev->channels = adis16220_channels;
628 indio_dev->num_channels = ARRAY_SIZE(adis16220_channels);
Barry Song06f19622010-05-16 21:11:37 +0100629
Jonathan Cameron01a67212011-06-27 13:07:15 +0100630 ret = iio_device_register(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100631 if (ret)
632 goto error_free_dev;
Barry Song06f19622010-05-16 21:11:37 +0100633
Jonathan Cameron01a67212011-06-27 13:07:15 +0100634 ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &accel_bin);
Barry Song06f19622010-05-16 21:11:37 +0100635 if (ret)
Jonathan Camerond2fffd62011-10-14 14:46:58 +0100636 goto error_unregister_dev;
Barry Song06f19622010-05-16 21:11:37 +0100637
Jonathan Cameron01a67212011-06-27 13:07:15 +0100638 ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &adc1_bin);
Barry Song06f19622010-05-16 21:11:37 +0100639 if (ret)
640 goto error_rm_accel_bin;
641
Jonathan Cameron01a67212011-06-27 13:07:15 +0100642 ret = sysfs_create_bin_file(&indio_dev->dev.kobj, &adc2_bin);
Barry Song06f19622010-05-16 21:11:37 +0100643 if (ret)
644 goto error_rm_adc1_bin;
645
646 /* Get the device into a sane initial state */
Jonathan Cameron01a67212011-06-27 13:07:15 +0100647 ret = adis16220_initial_setup(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100648 if (ret)
649 goto error_rm_adc2_bin;
650 return 0;
651
652error_rm_adc2_bin:
Jonathan Cameron01a67212011-06-27 13:07:15 +0100653 sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc2_bin);
Barry Song06f19622010-05-16 21:11:37 +0100654error_rm_adc1_bin:
Jonathan Cameron01a67212011-06-27 13:07:15 +0100655 sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
Barry Song06f19622010-05-16 21:11:37 +0100656error_rm_accel_bin:
Jonathan Cameron01a67212011-06-27 13:07:15 +0100657 sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
Jonathan Camerond2fffd62011-10-14 14:46:58 +0100658error_unregister_dev:
659 iio_device_unregister(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100660error_free_dev:
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200661 iio_device_free(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100662error_ret:
663 return ret;
664}
665
Lars-Peter Clausen8e828752012-08-17 18:29:00 +0100666static int __devexit adis16220_remove(struct spi_device *spi)
Barry Song06f19622010-05-16 21:11:37 +0100667{
Jonathan Cameron01a67212011-06-27 13:07:15 +0100668 struct iio_dev *indio_dev = spi_get_drvdata(spi);
Barry Song06f19622010-05-16 21:11:37 +0100669
Jonathan Cameron01a67212011-06-27 13:07:15 +0100670 sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc2_bin);
671 sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
672 sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
Barry Song06f19622010-05-16 21:11:37 +0100673 iio_device_unregister(indio_dev);
Lars-Peter Clausen7cbb7532012-04-26 13:35:01 +0200674 iio_device_free(indio_dev);
Barry Song06f19622010-05-16 21:11:37 +0100675
676 return 0;
677}
678
679static struct spi_driver adis16220_driver = {
680 .driver = {
681 .name = "adis16220",
682 .owner = THIS_MODULE,
683 },
684 .probe = adis16220_probe,
685 .remove = __devexit_p(adis16220_remove),
686};
Lars-Peter Clausenae6ae6f2011-11-16 10:13:39 +0100687module_spi_driver(adis16220_driver);
Barry Song06f19622010-05-16 21:11:37 +0100688
689MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
690MODULE_DESCRIPTION("Analog Devices ADIS16220 Digital Vibration Sensor");
691MODULE_LICENSE("GPL v2");
Lars-Peter Clausen55e43902011-11-16 08:53:31 +0100692MODULE_ALIAS("spi:adis16220");