aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorBarry Song <Barry.Song@analog.com>2010-05-16 16:11:37 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-18 17:40:47 -0400
commit06f1962ab475bdee3ae17afbaecee5b23f3cd5f0 (patch)
tree590e67081629a2e8861140c74c79ea8be8ed5f5e /drivers/staging
parentba2450b89bd9dce7d8926d919a67ed515be3e05f (diff)
Staging: iio: adis16220 vibration sensor driver
Signed-off-by: Barry Song <Barry.Song@analog.com> Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/iio/accel/Kconfig7
-rw-r--r--drivers/staging/iio/accel/Makefile3
-rw-r--r--drivers/staging/iio/accel/accel.h6
-rw-r--r--drivers/staging/iio/accel/adis16220.h150
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c664
5 files changed, 830 insertions, 0 deletions
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index 8f3f70f10a38..b4e57d1bc87d 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -12,6 +12,13 @@ config ADIS16209
12 Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer 12 Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer
13 and accelerometer. 13 and accelerometer.
14 14
15config ADIS16220
16 tristate "Analog Devices ADIS16220 Programmable Digital Vibration Sensor driver"
17 depends on SPI
18 help
19 Say yes here to build support for Analog Devices adis16220 programmable
20 digital vibration sensor.
21
15config ADIS16240 22config ADIS16240
16 tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder" 23 tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder"
17 depends on SPI 24 depends on SPI
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index 0e6762c34878..c34b13634c2d 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -5,6 +5,9 @@ adis16209-y := adis16209_core.o
5adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o 5adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o
6obj-$(CONFIG_ADIS16209) += adis16209.o 6obj-$(CONFIG_ADIS16209) += adis16209.o
7 7
8adis16220-y := adis16220_core.o
9obj-$(CONFIG_ADIS16220) += adis16220.o
10
8adis16240-y := adis16240_core.o 11adis16240-y := adis16240_core.o
9adis16240-$(CONFIG_IIO_RING_BUFFER) += adis16240_ring.o adis16240_trigger.o 12adis16240-$(CONFIG_IIO_RING_BUFFER) += adis16240_ring.o adis16240_trigger.o
10obj-$(CONFIG_ADIS16240) += adis16240.o 13obj-$(CONFIG_ADIS16240) += adis16240.o
diff --git a/drivers/staging/iio/accel/accel.h b/drivers/staging/iio/accel/accel.h
index 059209c9e339..1b6e37f76200 100644
--- a/drivers/staging/iio/accel/accel.h
+++ b/drivers/staging/iio/accel/accel.h
@@ -2,6 +2,9 @@
2#include "../sysfs.h" 2#include "../sysfs.h"
3 3
4/* Accelerometer types of attribute */ 4/* Accelerometer types of attribute */
5#define IIO_DEV_ATTR_ACCEL_OFFSET(_mode, _show, _store, _addr) \
6 IIO_DEVICE_ATTR(accel_offset, _mode, _show, _store, _addr)
7
5#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr) \ 8#define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr) \
6 IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr) 9 IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr)
7 10
@@ -20,6 +23,9 @@
20#define IIO_DEV_ATTR_ACCEL_Z_GAIN(_mode, _show, _store, _addr) \ 23#define IIO_DEV_ATTR_ACCEL_Z_GAIN(_mode, _show, _store, _addr) \
21 IIO_DEVICE_ATTR(accel_z_gain, _mode, _show, _store, _addr) 24 IIO_DEVICE_ATTR(accel_z_gain, _mode, _show, _store, _addr)
22 25
26#define IIO_DEV_ATTR_ACCEL(_show, _addr) \
27 IIO_DEVICE_ATTR(accel_raw, S_IRUGO, _show, NULL, _addr)
28
23#define IIO_DEV_ATTR_ACCEL_X(_show, _addr) \ 29#define IIO_DEV_ATTR_ACCEL_X(_show, _addr) \
24 IIO_DEVICE_ATTR(accel_x_raw, S_IRUGO, _show, NULL, _addr) 30 IIO_DEVICE_ATTR(accel_x_raw, S_IRUGO, _show, NULL, _addr)
25 31
diff --git a/drivers/staging/iio/accel/adis16220.h b/drivers/staging/iio/accel/adis16220.h
new file mode 100644
index 000000000000..6b49f70eff47
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16220.h
@@ -0,0 +1,150 @@
1#ifndef SPI_ADIS16220_H_
2#define SPI_ADIS16220_H_
3
4#define ADIS16220_STARTUP_DELAY 220 /* ms */
5
6#define ADIS16220_READ_REG(a) a
7#define ADIS16220_WRITE_REG(a) ((a) | 0x80)
8
9/* Flash memory write count */
10#define ADIS16220_FLASH_CNT 0x00
11/* Control, acceleration offset adjustment control */
12#define ADIS16220_ACCL_NULL 0x02
13/* Control, AIN1 offset adjustment control */
14#define ADIS16220_AIN1_NULL 0x04
15/* Control, AIN2 offset adjustment control */
16#define ADIS16220_AIN2_NULL 0x06
17/* Output, power supply during capture */
18#define ADIS16220_CAPT_SUPPLY 0x0A
19/* Output, temperature during capture */
20#define ADIS16220_CAPT_TEMP 0x0C
21/* Output, peak acceleration during capture */
22#define ADIS16220_CAPT_PEAKA 0x0E
23/* Output, peak AIN1 level during capture */
24#define ADIS16220_CAPT_PEAK1 0x10
25/* Output, peak AIN2 level during capture */
26#define ADIS16220_CAPT_PEAK2 0x12
27/* Output, capture buffer for acceleration */
28#define ADIS16220_CAPT_BUFA 0x14
29/* Output, capture buffer for AIN1 */
30#define ADIS16220_CAPT_BUF1 0x16
31/* Output, capture buffer for AIN2 */
32#define ADIS16220_CAPT_BUF2 0x18
33/* Control, capture buffer address pointer */
34#define ADIS16220_CAPT_PNTR 0x1A
35/* Control, capture control register */
36#define ADIS16220_CAPT_CTRL 0x1C
37/* Control, capture period (automatic mode) */
38#define ADIS16220_CAPT_PRD 0x1E
39/* Control, Alarm A, acceleration peak threshold */
40#define ADIS16220_ALM_MAGA 0x20
41/* Control, Alarm 1, AIN1 peak threshold */
42#define ADIS16220_ALM_MAG1 0x22
43/* Control, Alarm 2, AIN2 peak threshold */
44#define ADIS16220_ALM_MAG2 0x24
45/* Control, Alarm S, peak threshold */
46#define ADIS16220_ALM_MAGS 0x26
47/* Control, alarm configuration register */
48#define ADIS16220_ALM_CTRL 0x28
49/* Control, general I/O configuration */
50#define ADIS16220_GPIO_CTRL 0x32
51/* Control, self-test control, AIN configuration */
52#define ADIS16220_MSC_CTRL 0x34
53/* Control, digital I/O configuration */
54#define ADIS16220_DIO_CTRL 0x36
55/* Control, filter configuration */
56#define ADIS16220_AVG_CNT 0x38
57/* Status, system status */
58#define ADIS16220_DIAG_STAT 0x3C
59/* Control, system commands */
60#define ADIS16220_GLOB_CMD 0x3E
61/* Status, self-test response */
62#define ADIS16220_ST_DELTA 0x40
63/* Lot Identification Code 1 */
64#define ADIS16220_LOT_ID1 0x52
65/* Lot Identification Code 2 */
66#define ADIS16220_LOT_ID2 0x54
67/* Product identifier; convert to decimal = 16220 */
68#define ADIS16220_PROD_ID 0x56
69/* Serial number */
70#define ADIS16220_SERIAL_NUM 0x58
71
72#define ADIS16220_CAPTURE_SIZE 2048
73
74/* MSC_CTRL */
75#define ADIS16220_MSC_CTRL_SELF_TEST_EN (1 << 8)
76#define ADIS16220_MSC_CTRL_POWER_SUP_COM_AIN1 (1 << 1)
77#define ADIS16220_MSC_CTRL_POWER_SUP_COM_AIN2 (1 << 0)
78
79/* DIO_CTRL */
80#define ADIS16220_MSC_CTRL_DIO2_BUSY_IND (3<<4)
81#define ADIS16220_MSC_CTRL_DIO1_BUSY_IND (3<<2)
82#define ADIS16220_MSC_CTRL_DIO2_ACT_HIGH (1<<1)
83#define ADIS16220_MSC_CTRL_DIO1_ACT_HIGH (1<<0)
84
85/* DIAG_STAT */
86/* AIN2 sample > ALM_MAG2 */
87#define ADIS16220_DIAG_STAT_ALM_MAG2 (1<<14)
88/* AIN1 sample > ALM_MAG1 */
89#define ADIS16220_DIAG_STAT_ALM_MAG1 (1<<13)
90/* Acceleration sample > ALM_MAGA */
91#define ADIS16220_DIAG_STAT_ALM_MAGA (1<<12)
92/* Error condition programmed into ALM_MAGS[11:0] and ALM_CTRL[5:4] is true */
93#define ADIS16220_DIAG_STAT_ALM_MAGS (1<<11)
94/* |Peak value in AIN2 data capture| > ALM_MAG2 */
95#define ADIS16220_DIAG_STAT_PEAK_AIN2 (1<<10)
96/* |Peak value in AIN1 data capture| > ALM_MAG1 */
97#define ADIS16220_DIAG_STAT_PEAK_AIN1 (1<<9)
98/* |Peak value in acceleration data capture| > ALM_MAGA */
99#define ADIS16220_DIAG_STAT_PEAK_ACCEL (1<<8)
100/* Data ready, capture complete */
101#define ADIS16220_DIAG_STAT_DATA_RDY (1<<7)
102#define ADIS16220_DIAG_STAT_FLASH_CHK (1<<6)
103#define ADIS16220_DIAG_STAT_SELF_TEST (1<<5)
104/* Capture period violation/interruption */
105#define ADIS16220_DIAG_STAT_VIOLATION (1<<4)
106/* SPI communications failure */
107#define ADIS16220_DIAG_STAT_SPI_FAIL (1<<3)
108/* Flash update failure */
109#define ADIS16220_DIAG_STAT_FLASH_UPT (1<<2)
110/* Power supply above 3.625 V */
111#define ADIS16220_DIAG_STAT_POWER_HIGH (1<<1)
112/* Power supply below 3.15 V */
113#define ADIS16220_DIAG_STAT_POWER_LOW (1<<0)
114
115/* GLOB_CMD */
116#define ADIS16220_GLOB_CMD_SW_RESET (1<<7)
117#define ADIS16220_GLOB_CMD_SELF_TEST (1<<2)
118#define ADIS16220_GLOB_CMD_PWR_DOWN (1<<1)
119
120#define ADIS16220_MAX_TX 2048
121#define ADIS16220_MAX_RX 2048
122
123#define ADIS16220_SPI_BURST (u32)(1000 * 1000)
124#define ADIS16220_SPI_FAST (u32)(2000 * 1000)
125
126/**
127 * struct adis16220_state - device instance specific data
128 * @us: actual spi_device
129 * @work_trigger_to_ring: bh for triggered event handling
130 * @work_cont_thresh: CLEAN
131 * @inter: used to check if new interrupt has been triggered
132 * @last_timestamp: passing timestamp from th to bh of interrupt handler
133 * @indio_dev: industrial I/O device structure
134 * @trig: data ready trigger registered with iio
135 * @tx: transmit buffer
136 * @rx: recieve buffer
137 * @buf_lock: mutex to protect tx and rx
138 **/
139struct adis16220_state {
140 struct spi_device *us;
141 struct iio_dev *indio_dev;
142 u8 *tx;
143 u8 *rx;
144 struct bin_attribute accel_bin;
145 struct bin_attribute adc1_bin;
146 struct bin_attribute adc2_bin;
147 struct mutex buf_lock;
148};
149
150#endif /* SPI_ADIS16220_H_ */
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
new file mode 100644
index 000000000000..8b845d9b7b9e
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -0,0 +1,664 @@
1/*
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
9#include <linux/interrupt.h>
10#include <linux/irq.h>
11#include <linux/gpio.h>
12#include <linux/delay.h>
13#include <linux/mutex.h>
14#include <linux/device.h>
15#include <linux/kernel.h>
16#include <linux/spi/spi.h>
17
18#include <linux/sysfs.h>
19#include <linux/list.h>
20
21#include "../iio.h"
22#include "../sysfs.h"
23#include "accel.h"
24#include "../adc/adc.h"
25
26#include "adis16220.h"
27
28#define DRIVER_NAME "adis16220"
29
30static int adis16220_check_status(struct device *dev);
31
32/**
33 * adis16220_spi_write_reg_8() - write single byte to a register
34 * @dev: device associated with child of actual device (iio_dev or iio_trig)
35 * @reg_address: the address of the register to be written
36 * @val: the value to write
37 **/
38static int adis16220_spi_write_reg_8(struct device *dev,
39 u8 reg_address,
40 u8 val)
41{
42 int ret;
43 struct iio_dev *indio_dev = dev_get_drvdata(dev);
44 struct adis16220_state *st = iio_dev_get_devdata(indio_dev);
45
46 mutex_lock(&st->buf_lock);
47 st->tx[0] = ADIS16220_WRITE_REG(reg_address);
48 st->tx[1] = val;
49
50 ret = spi_write(st->us, st->tx, 2);
51 mutex_unlock(&st->buf_lock);
52
53 return ret;
54}
55
56/**
57 * adis16220_spi_write_reg_16() - write 2 bytes to a pair of registers
58 * @dev: device associated with child of actual device (iio_dev or iio_trig)
59 * @reg_address: the address of the lower of the two registers. Second register
60 * is assumed to have address one greater.
61 * @val: value to be written
62 **/
63static int adis16220_spi_write_reg_16(struct device *dev,
64 u8 lower_reg_address,
65 u16 value)
66{
67 int ret;
68 struct spi_message msg;
69 struct iio_dev *indio_dev = dev_get_drvdata(dev);
70 struct adis16220_state *st = iio_dev_get_devdata(indio_dev);
71 struct spi_transfer xfers[] = {
72 {
73 .tx_buf = st->tx,
74 .bits_per_word = 8,
75 .len = 2,
76 .cs_change = 1,
77 .delay_usecs = 25,
78 }, {
79 .tx_buf = st->tx + 2,
80 .bits_per_word = 8,
81 .len = 2,
82 .cs_change = 1,
83 .delay_usecs = 25,
84 },
85 };
86
87 mutex_lock(&st->buf_lock);
88 st->tx[0] = ADIS16220_WRITE_REG(lower_reg_address);
89 st->tx[1] = value & 0xFF;
90 st->tx[2] = ADIS16220_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 * adis16220_spi_read_reg_16() - read 2 bytes from a 16-bit register
104 * @dev: device associated with child of actual device (iio_dev or iio_trig)
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 **/
109static int adis16220_spi_read_reg_16(struct device *dev,
110 u8 lower_reg_address,
111 u16 *val)
112{
113 struct spi_message msg;
114 struct iio_dev *indio_dev = dev_get_drvdata(dev);
115 struct adis16220_state *st = iio_dev_get_devdata(indio_dev);
116 int ret;
117 struct spi_transfer xfers[] = {
118 {
119 .tx_buf = st->tx,
120 .bits_per_word = 8,
121 .len = 2,
122 .cs_change = 1,
123 .delay_usecs = 25,
124 }, {
125 .rx_buf = st->rx,
126 .bits_per_word = 8,
127 .len = 2,
128 .cs_change = 1,
129 .delay_usecs = 25,
130 },
131 };
132
133 mutex_lock(&st->buf_lock);
134 st->tx[0] = ADIS16220_READ_REG(lower_reg_address);
135 st->tx[1] = 0;
136 st->tx[2] = 0;
137 st->tx[3] = 0;
138
139 spi_message_init(&msg);
140 spi_message_add_tail(&xfers[0], &msg);
141 spi_message_add_tail(&xfers[1], &msg);
142 ret = spi_sync(st->us, &msg);
143 if (ret) {
144 dev_err(&st->us->dev,
145 "problem when reading 16 bit register 0x%02X",
146 lower_reg_address);
147 goto error_ret;
148 }
149 *val = (st->rx[0] << 8) | st->rx[1];
150
151error_ret:
152 mutex_unlock(&st->buf_lock);
153 return ret;
154}
155
156static ssize_t adis16220_spi_read_signed(struct device *dev,
157 struct device_attribute *attr,
158 char *buf,
159 unsigned bits)
160{
161 int ret;
162 s16 val = 0;
163 unsigned shift = 16 - bits;
164 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
165
166 ret = adis16220_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
167 if (ret)
168 return ret;
169
170 val = ((s16)(val << shift) >> shift);
171 return sprintf(buf, "%d\n", val);
172}
173
174static ssize_t adis16220_read_12bit_unsigned(struct device *dev,
175 struct device_attribute *attr,
176 char *buf)
177{
178 int ret;
179 u16 val = 0;
180 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
181
182 ret = adis16220_spi_read_reg_16(dev, this_attr->address, &val);
183 if (ret)
184 return ret;
185
186 return sprintf(buf, "%u\n", val & 0x0FFF);
187}
188
189static ssize_t adis16220_read_16bit(struct device *dev,
190 struct device_attribute *attr,
191 char *buf)
192{
193 struct iio_dev *indio_dev = dev_get_drvdata(dev);
194 ssize_t ret;
195
196 /* Take the iio_dev status lock */
197 mutex_lock(&indio_dev->mlock);
198 ret = adis16220_spi_read_signed(dev, attr, buf, 16);
199 mutex_unlock(&indio_dev->mlock);
200
201 return ret;
202}
203
204static ssize_t adis16220_write_16bit(struct device *dev,
205 struct device_attribute *attr,
206 const char *buf,
207 size_t len)
208{
209 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
210 int ret;
211 long val;
212
213 ret = strict_strtol(buf, 10, &val);
214 if (ret)
215 goto error_ret;
216 ret = adis16220_spi_write_reg_16(dev, this_attr->address, val);
217
218error_ret:
219 return ret ? ret : len;
220}
221
222static int adis16220_capture(struct device *dev)
223{
224 int ret;
225 ret = adis16220_spi_write_reg_16(dev,
226 ADIS16220_GLOB_CMD,
227 0xBF08); /* initiates a manual data capture */
228 if (ret)
229 dev_err(dev, "problem beginning capture");
230
231 msleep(10); /* delay for capture to finish */
232
233 return ret;
234}
235
236static int adis16220_reset(struct device *dev)
237{
238 int ret;
239 ret = adis16220_spi_write_reg_8(dev,
240 ADIS16220_GLOB_CMD,
241 ADIS16220_GLOB_CMD_SW_RESET);
242 if (ret)
243 dev_err(dev, "problem resetting device");
244
245 return ret;
246}
247
248static ssize_t adis16220_write_reset(struct device *dev,
249 struct device_attribute *attr,
250 const char *buf, size_t len)
251{
252 if (len < 1)
253 return -1;
254 switch (buf[0]) {
255 case '1':
256 case 'y':
257 case 'Y':
258 return adis16220_reset(dev) == 0 ? len : -EIO;
259 }
260 return -1;
261}
262
263static ssize_t adis16220_write_capture(struct device *dev,
264 struct device_attribute *attr,
265 const char *buf, size_t len)
266{
267 if (len < 1)
268 return -1;
269 switch (buf[0]) {
270 case '1':
271 case 'y':
272 case 'Y':
273 return adis16220_capture(dev) == 0 ? len : -EIO;
274 }
275 return -1;
276}
277
278static int adis16220_self_test(struct device *dev)
279{
280 int ret;
281 ret = adis16220_spi_write_reg_16(dev,
282 ADIS16220_MSC_CTRL,
283 ADIS16220_MSC_CTRL_SELF_TEST_EN);
284 if (ret) {
285 dev_err(dev, "problem starting self test");
286 goto err_ret;
287 }
288
289 adis16220_check_status(dev);
290
291err_ret:
292 return ret;
293}
294
295static int adis16220_check_status(struct device *dev)
296{
297 u16 status;
298 int ret;
299
300 ret = adis16220_spi_read_reg_16(dev, ADIS16220_DIAG_STAT, &status);
301
302 if (ret < 0) {
303 dev_err(dev, "Reading status failed\n");
304 goto error_ret;
305 }
306 ret = status & 0x7F;
307
308 if (status & ADIS16220_DIAG_STAT_VIOLATION)
309 dev_err(dev, "Capture period violation/interruption\n");
310 if (status & ADIS16220_DIAG_STAT_SPI_FAIL)
311 dev_err(dev, "SPI failure\n");
312 if (status & ADIS16220_DIAG_STAT_FLASH_UPT)
313 dev_err(dev, "Flash update failed\n");
314 if (status & ADIS16220_DIAG_STAT_POWER_HIGH)
315 dev_err(dev, "Power supply above 5.25V\n");
316 if (status & ADIS16220_DIAG_STAT_POWER_LOW)
317 dev_err(dev, "Power supply below 4.75V\n");
318
319error_ret:
320 return ret;
321}
322
323static int adis16220_initial_setup(struct adis16220_state *st)
324{
325 int ret;
326 struct device *dev = &st->indio_dev->dev;
327
328 /* Do self test */
329 ret = adis16220_self_test(dev);
330 if (ret) {
331 dev_err(dev, "self test failure");
332 goto err_ret;
333 }
334
335 /* Read status register to check the result */
336 ret = adis16220_check_status(dev);
337 if (ret) {
338 adis16220_reset(dev);
339 dev_err(dev, "device not playing ball -> reset");
340 msleep(ADIS16220_STARTUP_DELAY);
341 ret = adis16220_check_status(dev);
342 if (ret) {
343 dev_err(dev, "giving up");
344 goto err_ret;
345 }
346 }
347
348 printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
349 st->us->chip_select, st->us->irq);
350
351err_ret:
352 return ret;
353}
354
355static ssize_t adis16220_capture_buffer_read(struct adis16220_state *st,
356 char *buf,
357 loff_t off,
358 size_t count,
359 int addr)
360{
361 struct spi_message msg;
362 struct spi_transfer xfers[] = {
363 {
364 .tx_buf = st->tx,
365 .bits_per_word = 8,
366 .len = 2,
367 .cs_change = 1,
368 .delay_usecs = 25,
369 }, {
370 .tx_buf = st->tx,
371 .rx_buf = st->rx,
372 .bits_per_word = 8,
373 .cs_change = 1,
374 .delay_usecs = 25,
375 },
376 };
377 int ret;
378 int i;
379
380 if (unlikely(!count))
381 return count;
382
383 if ((off >= ADIS16220_CAPTURE_SIZE) || (count & 1) || (off & 1))
384 return -EINVAL;
385
386 if (off + count > ADIS16220_CAPTURE_SIZE)
387 count = ADIS16220_CAPTURE_SIZE - off;
388
389 /* write the begin position of capture buffer */
390 ret = adis16220_spi_write_reg_16(&st->indio_dev->dev,
391 ADIS16220_CAPT_PNTR,
392 off > 1);
393 if (ret)
394 return -EIO;
395
396 /* read count/2 values from capture buffer */
397 mutex_lock(&st->buf_lock);
398
399 for (i = 0; i < count; i += 2) {
400 st->tx[i] = ADIS16220_READ_REG(addr);
401 st->tx[i + 1] = 0;
402 }
403 xfers[1].len = count;
404
405 spi_message_init(&msg);
406 spi_message_add_tail(&xfers[0], &msg);
407 spi_message_add_tail(&xfers[1], &msg);
408 ret = spi_sync(st->us, &msg);
409 if (ret) {
410
411 mutex_unlock(&st->buf_lock);
412 return -EIO;
413 }
414
415 memcpy(buf, st->rx, count);
416
417 mutex_unlock(&st->buf_lock);
418 return count;
419}
420
421static ssize_t adis16220_accel_bin_read(struct kobject *kobj,
422 struct bin_attribute *attr,
423 char *buf,
424 loff_t off,
425 size_t count)
426{
427 struct device *dev = container_of(kobj, struct device, kobj);
428 struct iio_dev *indio_dev = dev_get_drvdata(dev);
429 struct adis16220_state *st = iio_dev_get_devdata(indio_dev);
430
431 return adis16220_capture_buffer_read(st, buf,
432 off, count,
433 ADIS16220_CAPT_BUFA);
434}
435
436static ssize_t adis16220_adc1_bin_read(struct kobject *kobj,
437 struct bin_attribute *attr,
438 char *buf, loff_t off,
439 size_t count)
440{
441 struct device *dev = container_of(kobj, struct device, kobj);
442 struct iio_dev *indio_dev = dev_get_drvdata(dev);
443 struct adis16220_state *st = iio_dev_get_devdata(indio_dev);
444
445 return adis16220_capture_buffer_read(st, buf,
446 off, count,
447 ADIS16220_CAPT_BUF1);
448}
449
450static ssize_t adis16220_adc2_bin_read(struct kobject *kobj,
451 struct bin_attribute *attr,
452 char *buf, loff_t off,
453 size_t count)
454{
455 struct device *dev = container_of(kobj, struct device, kobj);
456 struct iio_dev *indio_dev = dev_get_drvdata(dev);
457 struct adis16220_state *st = iio_dev_get_devdata(indio_dev);
458
459 return adis16220_capture_buffer_read(st, buf,
460 off, count,
461 ADIS16220_CAPT_BUF2);
462}
463
464static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16220_read_12bit_unsigned,
465 ADIS16220_CAPT_SUPPLY);
466static IIO_CONST_ATTR(in_supply_scale, "0.0012207");
467static IIO_DEV_ATTR_ACCEL(adis16220_read_16bit, ADIS16220_CAPT_BUFA);
468static IIO_DEVICE_ATTR(accel_peak_raw, S_IRUGO, adis16220_read_16bit,
469 NULL, ADIS16220_CAPT_PEAKA);
470static IIO_DEV_ATTR_ACCEL_OFFSET(S_IWUSR | S_IRUGO,
471 adis16220_read_16bit,
472 adis16220_write_16bit,
473 ADIS16220_ACCL_NULL);
474static IIO_DEV_ATTR_TEMP_RAW(adis16220_read_12bit_unsigned);
475static IIO_CONST_ATTR(temp_offset, "25");
476static IIO_CONST_ATTR(temp_scale, "-0.47");
477
478static IIO_DEV_ATTR_IN_RAW(0, adis16220_read_16bit, ADIS16220_CAPT_BUF1);
479static IIO_DEV_ATTR_IN_RAW(1, adis16220_read_16bit, ADIS16220_CAPT_BUF2);
480
481static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL,
482 adis16220_write_reset, 0);
483
484#define IIO_DEV_ATTR_CAPTURE(_store) \
485 IIO_DEVICE_ATTR(capture, S_IWUGO, NULL, _store, 0)
486
487static IIO_DEV_ATTR_CAPTURE(adis16220_write_capture);
488
489#define IIO_DEV_ATTR_CAPTURE_COUNT(_mode, _show, _store, _addr) \
490 IIO_DEVICE_ATTR(capture_count, _mode, _show, _store, _addr)
491
492static IIO_DEV_ATTR_CAPTURE_COUNT(S_IWUSR | S_IRUGO,
493 adis16220_read_16bit,
494 adis16220_write_16bit,
495 ADIS16220_CAPT_PNTR);
496
497static IIO_CONST_ATTR_AVAIL_SAMP_FREQ("100200");
498
499static IIO_CONST_ATTR(name, "adis16220");
500
501static struct attribute *adis16220_attributes[] = {
502 &iio_dev_attr_in_supply_raw.dev_attr.attr,
503 &iio_const_attr_in_supply_scale.dev_attr.attr,
504 &iio_dev_attr_accel_raw.dev_attr.attr,
505 &iio_dev_attr_accel_offset.dev_attr.attr,
506 &iio_dev_attr_accel_peak_raw.dev_attr.attr,
507 &iio_dev_attr_temp_raw.dev_attr.attr,
508 &iio_dev_attr_in0_raw.dev_attr.attr,
509 &iio_dev_attr_in1_raw.dev_attr.attr,
510 &iio_const_attr_temp_offset.dev_attr.attr,
511 &iio_const_attr_temp_scale.dev_attr.attr,
512 &iio_const_attr_available_sampling_frequency.dev_attr.attr,
513 &iio_dev_attr_reset.dev_attr.attr,
514 &iio_dev_attr_capture.dev_attr.attr,
515 &iio_dev_attr_capture_count.dev_attr.attr,
516 &iio_const_attr_name.dev_attr.attr,
517 NULL
518};
519
520static const struct attribute_group adis16220_attribute_group = {
521 .attrs = adis16220_attributes,
522};
523
524static int __devinit adis16220_probe(struct spi_device *spi)
525{
526 int ret, regdone = 0;
527 struct adis16220_state *st = kzalloc(sizeof *st, GFP_KERNEL);
528 if (!st) {
529 ret = -ENOMEM;
530 goto error_ret;
531 }
532 /* this is only used for removal purposes */
533 spi_set_drvdata(spi, st);
534
535 /* Allocate the comms buffers */
536 st->rx = kzalloc(sizeof(*st->rx)*ADIS16220_MAX_RX, GFP_KERNEL);
537 if (st->rx == NULL) {
538 ret = -ENOMEM;
539 goto error_free_st;
540 }
541 st->tx = kzalloc(sizeof(*st->tx)*ADIS16220_MAX_TX, GFP_KERNEL);
542 if (st->tx == NULL) {
543 ret = -ENOMEM;
544 goto error_free_rx;
545 }
546 st->us = spi;
547 mutex_init(&st->buf_lock);
548 /* setup the industrialio driver allocated elements */
549 st->indio_dev = iio_allocate_device();
550 if (st->indio_dev == NULL) {
551 ret = -ENOMEM;
552 goto error_free_tx;
553 }
554
555 st->indio_dev->dev.parent = &spi->dev;
556 st->indio_dev->attrs = &adis16220_attribute_group;
557 st->indio_dev->dev_data = (void *)(st);
558 st->indio_dev->driver_module = THIS_MODULE;
559 st->indio_dev->modes = INDIO_DIRECT_MODE;
560
561 ret = iio_device_register(st->indio_dev);
562 if (ret)
563 goto error_free_dev;
564 regdone = 1;
565
566 st->accel_bin.attr.name = "accel_bin";
567 st->accel_bin.attr.mode = S_IRUGO;
568 st->accel_bin.attr.owner = THIS_MODULE;
569 st->accel_bin.read = adis16220_accel_bin_read;
570 st->accel_bin.size = ADIS16220_CAPTURE_SIZE;
571
572 ret = sysfs_create_bin_file(&st->indio_dev->dev.kobj, &st->accel_bin);
573 if (ret)
574 goto error_free_dev;
575
576 st->adc1_bin.attr.name = "adc1_bin";
577 st->adc1_bin.attr.mode = S_IRUGO;
578 st->adc1_bin.attr.owner = THIS_MODULE;
579 st->adc1_bin.read = adis16220_adc1_bin_read;
580 st->adc1_bin.size = ADIS16220_CAPTURE_SIZE;
581
582 ret = sysfs_create_bin_file(&st->indio_dev->dev.kobj, &st->adc1_bin);
583 if (ret)
584 goto error_rm_accel_bin;
585
586 st->adc2_bin.attr.name = "adc2_bin";
587 st->adc2_bin.attr.mode = S_IRUGO;
588 st->adc2_bin.attr.owner = THIS_MODULE;
589 st->adc2_bin.read = adis16220_adc2_bin_read;
590 st->adc2_bin.size = ADIS16220_CAPTURE_SIZE;
591
592 ret = sysfs_create_bin_file(&st->indio_dev->dev.kobj, &st->adc2_bin);
593 if (ret)
594 goto error_rm_adc1_bin;
595
596 /* Get the device into a sane initial state */
597 ret = adis16220_initial_setup(st);
598 if (ret)
599 goto error_rm_adc2_bin;
600 return 0;
601
602error_rm_adc2_bin:
603 sysfs_remove_bin_file(&st->indio_dev->dev.kobj, &st->adc2_bin);
604error_rm_adc1_bin:
605 sysfs_remove_bin_file(&st->indio_dev->dev.kobj, &st->adc1_bin);
606error_rm_accel_bin:
607 sysfs_remove_bin_file(&st->indio_dev->dev.kobj, &st->accel_bin);
608error_free_dev:
609 if (regdone)
610 iio_device_unregister(st->indio_dev);
611 else
612 iio_free_device(st->indio_dev);
613error_free_tx:
614 kfree(st->tx);
615error_free_rx:
616 kfree(st->rx);
617error_free_st:
618 kfree(st);
619error_ret:
620 return ret;
621}
622
623static int adis16220_remove(struct spi_device *spi)
624{
625 struct adis16220_state *st = spi_get_drvdata(spi);
626 struct iio_dev *indio_dev = st->indio_dev;
627
628 flush_scheduled_work();
629
630 sysfs_remove_bin_file(&st->indio_dev->dev.kobj, &st->adc2_bin);
631 sysfs_remove_bin_file(&st->indio_dev->dev.kobj, &st->adc1_bin);
632 sysfs_remove_bin_file(&st->indio_dev->dev.kobj, &st->accel_bin);
633 iio_device_unregister(indio_dev);
634 kfree(st->tx);
635 kfree(st->rx);
636 kfree(st);
637
638 return 0;
639}
640
641static struct spi_driver adis16220_driver = {
642 .driver = {
643 .name = "adis16220",
644 .owner = THIS_MODULE,
645 },
646 .probe = adis16220_probe,
647 .remove = __devexit_p(adis16220_remove),
648};
649
650static __init int adis16220_init(void)
651{
652 return spi_register_driver(&adis16220_driver);
653}
654module_init(adis16220_init);
655
656static __exit void adis16220_exit(void)
657{
658 spi_unregister_driver(&adis16220_driver);
659}
660module_exit(adis16220_exit);
661
662MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
663MODULE_DESCRIPTION("Analog Devices ADIS16220 Digital Vibration Sensor");
664MODULE_LICENSE("GPL v2");