aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio
diff options
context:
space:
mode:
authorBarry Song <Barry.Song@analog.com>2010-05-07 10:38:59 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-11 17:33:24 -0400
commit671ece14bc58a88dea76b11c5745a09c33934663 (patch)
treee99dd5e5dd433c2404e367ba3f6d5edbcdcdf66b /drivers/staging/iio
parentb155498b1842090f2cf5164908deaa0762a9a8b1 (diff)
staging: iio: adis16209 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/iio')
-rw-r--r--drivers/staging/iio/accel/Kconfig9
-rw-r--r--drivers/staging/iio/accel/Makefile4
-rw-r--r--drivers/staging/iio/accel/adis16209.h193
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c615
-rw-r--r--drivers/staging/iio/accel/adis16209_ring.c266
-rw-r--r--drivers/staging/iio/accel/adis16209_trigger.c124
6 files changed, 1211 insertions, 0 deletions
diff --git a/drivers/staging/iio/accel/Kconfig b/drivers/staging/iio/accel/Kconfig
index 3d3c3339dbc..1d89e2153dd 100644
--- a/drivers/staging/iio/accel/Kconfig
+++ b/drivers/staging/iio/accel/Kconfig
@@ -3,6 +3,15 @@
3# 3#
4comment "Accelerometers" 4comment "Accelerometers"
5 5
6config ADIS16209
7 tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
8 depends on SPI
9 select IIO_TRIGGER if IIO_RING_BUFFER
10 select IIO_SW_RING if IIO_RING_BUFFER
11 help
12 Say yes here to build support for Analog Devices adis16209 dual-axis digital inclinometer
13 and accelerometer.
14
6config KXSD9 15config KXSD9
7 tristate "Kionix KXSD9 Accelerometer Driver" 16 tristate "Kionix KXSD9 Accelerometer Driver"
8 depends on SPI 17 depends on SPI
diff --git a/drivers/staging/iio/accel/Makefile b/drivers/staging/iio/accel/Makefile
index d5335f9094a..f8f2124720e 100644
--- a/drivers/staging/iio/accel/Makefile
+++ b/drivers/staging/iio/accel/Makefile
@@ -1,6 +1,10 @@
1# 1#
2# Makefile for industrial I/O accelerometer drivers 2# Makefile for industrial I/O accelerometer drivers
3# 3#
4adis16209-y := adis16209_core.o
5adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o
6obj-$(CONFIG_ADIS16209) += adis16209.o
7
4obj-$(CONFIG_KXSD9) += kxsd9.o 8obj-$(CONFIG_KXSD9) += kxsd9.o
5 9
6lis3l02dq-y := lis3l02dq_core.o 10lis3l02dq-y := lis3l02dq_core.o
diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h
new file mode 100644
index 00000000000..877fd2a4838
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16209.h
@@ -0,0 +1,193 @@
1#ifndef SPI_ADIS16209_H_
2#define SPI_ADIS16209_H_
3
4#define ADIS16209_STARTUP_DELAY 220 /* ms */
5
6#define ADIS16209_READ_REG(a) a
7#define ADIS16209_WRITE_REG(a) ((a) | 0x80)
8
9/* Flash memory write count */
10#define ADIS16209_FLASH_CNT 0x00
11/* Output, power supply */
12#define ADIS16209_SUPPLY_OUT 0x02
13/* Output, x-axis accelerometer */
14#define ADIS16209_XACCL_OUT 0x04
15/* Output, y-axis accelerometer */
16#define ADIS16209_YACCL_OUT 0x06
17/* Output, auxiliary ADC input */
18#define ADIS16209_AUX_ADC 0x08
19/* Output, temperature */
20#define ADIS16209_TEMP_OUT 0x0A
21/* Output, x-axis inclination */
22#define ADIS16209_XINCL_OUT 0x0C
23/* Output, y-axis inclination */
24#define ADIS16209_YINCL_OUT 0x0E
25/* Output, +/-180 vertical rotational position */
26#define ADIS16209_ROT_OUT 0x10
27/* Calibration, x-axis acceleration offset null */
28#define ADIS16209_XACCL_NULL 0x12
29/* Calibration, y-axis acceleration offset null */
30#define ADIS16209_YACCL_NULL 0x14
31/* Calibration, x-axis inclination offset null */
32#define ADIS16209_XINCL_NULL 0x16
33/* Calibration, y-axis inclination offset null */
34#define ADIS16209_YINCL_NULL 0x18
35/* Calibration, vertical rotation offset null */
36#define ADIS16209_ROT_NULL 0x1A
37/* Alarm 1 amplitude threshold */
38#define ADIS16209_ALM_MAG1 0x20
39/* Alarm 2 amplitude threshold */
40#define ADIS16209_ALM_MAG2 0x22
41/* Alarm 1, sample period */
42#define ADIS16209_ALM_SMPL1 0x24
43/* Alarm 2, sample period */
44#define ADIS16209_ALM_SMPL2 0x26
45/* Alarm control */
46#define ADIS16209_ALM_CTRL 0x28
47/* Auxiliary DAC data */
48#define ADIS16209_AUX_DAC 0x30
49/* General-purpose digital input/output control */
50#define ADIS16209_GPIO_CTRL 0x32
51/* Miscellaneous control */
52#define ADIS16209_MSC_CTRL 0x34
53/* Internal sample period (rate) control */
54#define ADIS16209_SMPL_PRD 0x36
55/* Operation, filter configuration */
56#define ADIS16209_AVG_CNT 0x38
57/* Operation, sleep mode control */
58#define ADIS16209_SLP_CNT 0x3A
59/* Diagnostics, system status register */
60#define ADIS16209_DIAG_STAT 0x3C
61/* Operation, system command register */
62#define ADIS16209_GLOB_CMD 0x3E
63
64#define ADIS16209_OUTPUTS 8
65
66/* MSC_CTRL */
67/* Self-test at power-on: 1 = disabled, 0 = enabled */
68#define ADIS16209_MSC_CTRL_PWRUP_SELF_TEST (1 << 10)
69/* Self-test enable */
70#define ADIS16209_MSC_CTRL_SELF_TEST_EN (1 << 8)
71/* Data-ready enable: 1 = enabled, 0 = disabled */
72#define ADIS16209_MSC_CTRL_DATA_RDY_EN (1 << 2)
73/* Data-ready polarity: 1 = active high, 0 = active low */
74#define ADIS16209_MSC_CTRL_ACTIVE_HIGH (1 << 1)
75/* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
76#define ADIS16209_MSC_CTRL_DATA_RDY_DIO2 (1 << 0)
77
78/* DIAG_STAT */
79/* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
80#define ADIS16209_DIAG_STAT_ALARM2 (1<<9)
81/* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
82#define ADIS16209_DIAG_STAT_ALARM1 (1<<8)
83/* Self-test diagnostic error flag: 1 = error condition, 0 = normal operation */
84#define ADIS16209_DIAG_STAT_SELFTEST_FAIL (1<<5)
85/* SPI communications failure */
86#define ADIS16209_DIAG_STAT_SPI_FAIL (1<<3)
87/* Flash update failure */
88#define ADIS16209_DIAG_STAT_FLASH_UPT (1<<2)
89/* Power supply above 3.625 V */
90#define ADIS16209_DIAG_STAT_POWER_HIGH (1<<1)
91/* Power supply below 3.15 V */
92#define ADIS16209_DIAG_STAT_POWER_LOW (1<<0)
93
94/* GLOB_CMD */
95#define ADIS16209_GLOB_CMD_SW_RESET (1<<7)
96#define ADIS16209_GLOB_CMD_CLEAR_STAT (1<<4)
97#define ADIS16209_GLOB_CMD_FACTORY_CAL (1<<1)
98
99#define ADIS16209_MAX_TX 24
100#define ADIS16209_MAX_RX 24
101
102#define ADIS16209_ERROR_ACTIVE (1<<14)
103
104/**
105 * struct adis16209_state - device instance specific data
106 * @us: actual spi_device
107 * @work_trigger_to_ring: bh for triggered event handling
108 * @work_cont_thresh: CLEAN
109 * @inter: used to check if new interrupt has been triggered
110 * @last_timestamp: passing timestamp from th to bh of interrupt handler
111 * @indio_dev: industrial I/O device structure
112 * @trig: data ready trigger registered with iio
113 * @tx: transmit buffer
114 * @rx: recieve buffer
115 * @buf_lock: mutex to protect tx and rx
116 **/
117struct adis16209_state {
118 struct spi_device *us;
119 struct work_struct work_trigger_to_ring;
120 struct iio_work_cont work_cont_thresh;
121 s64 last_timestamp;
122 struct iio_dev *indio_dev;
123 struct iio_trigger *trig;
124 u8 *tx;
125 u8 *rx;
126 struct mutex buf_lock;
127};
128
129int adis16209_set_irq(struct device *dev, bool enable);
130
131#ifdef CONFIG_IIO_RING_BUFFER
132enum adis16209_scan {
133 ADIS16209_SCAN_SUPPLY,
134 ADIS16209_SCAN_ACC_X,
135 ADIS16209_SCAN_ACC_Y,
136 ADIS16209_SCAN_AUX_ADC,
137 ADIS16209_SCAN_TEMP,
138 ADIS16209_SCAN_INCLI_X,
139 ADIS16209_SCAN_INCLI_Y,
140 ADIS16209_SCAN_ROT,
141};
142
143void adis16209_remove_trigger(struct iio_dev *indio_dev);
144int adis16209_probe_trigger(struct iio_dev *indio_dev);
145
146ssize_t adis16209_read_data_from_ring(struct device *dev,
147 struct device_attribute *attr,
148 char *buf);
149
150int adis16209_configure_ring(struct iio_dev *indio_dev);
151void adis16209_unconfigure_ring(struct iio_dev *indio_dev);
152
153int adis16209_initialize_ring(struct iio_ring_buffer *ring);
154void adis16209_uninitialize_ring(struct iio_ring_buffer *ring);
155#else /* CONFIG_IIO_RING_BUFFER */
156
157static inline void adis16209_remove_trigger(struct iio_dev *indio_dev)
158{
159}
160
161static inline int adis16209_probe_trigger(struct iio_dev *indio_dev)
162{
163 return 0;
164}
165
166static inline ssize_t
167adis16209_read_data_from_ring(struct device *dev,
168 struct device_attribute *attr,
169 char *buf)
170{
171 return 0;
172}
173
174static int adis16209_configure_ring(struct iio_dev *indio_dev)
175{
176 return 0;
177}
178
179static inline void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
180{
181}
182
183static inline int adis16209_initialize_ring(struct iio_ring_buffer *ring)
184{
185 return 0;
186}
187
188static inline void adis16209_uninitialize_ring(struct iio_ring_buffer *ring)
189{
190}
191
192#endif /* CONFIG_IIO_RING_BUFFER */
193#endif /* SPI_ADIS16209_H_ */
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
new file mode 100644
index 00000000000..ac375c50f56
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -0,0 +1,615 @@
1/*
2 * ADIS16209 Programmable Digital Vibration Sensor driver
3 *
4 * Copyright 2010 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
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 "inclinometer.h"
25#include "../gyro/gyro.h"
26#include "../adc/adc.h"
27
28#include "adis16209.h"
29
30#define DRIVER_NAME "adis16209"
31
32static int adis16209_check_status(struct device *dev);
33
34/**
35 * adis16209_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 **/
40static int adis16209_spi_write_reg_8(struct device *dev,
41 u8 reg_address,
42 u8 val)
43{
44 int ret;
45 struct iio_dev *indio_dev = dev_get_drvdata(dev);
46 struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
47
48 mutex_lock(&st->buf_lock);
49 st->tx[0] = ADIS16209_WRITE_REG(reg_address);
50 st->tx[1] = val;
51
52 ret = spi_write(st->us, st->tx, 2);
53 mutex_unlock(&st->buf_lock);
54
55 return ret;
56}
57
58/**
59 * adis16209_spi_write_reg_16() - write 2 bytes to a pair of registers
60 * @dev: device associated with child of actual device (iio_dev or iio_trig)
61 * @reg_address: the address of the lower of the two registers. Second register
62 * is assumed to have address one greater.
63 * @val: value to be written
64 **/
65static int adis16209_spi_write_reg_16(struct device *dev,
66 u8 lower_reg_address,
67 u16 value)
68{
69 int ret;
70 struct spi_message msg;
71 struct iio_dev *indio_dev = dev_get_drvdata(dev);
72 struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
73 struct spi_transfer xfers[] = {
74 {
75 .tx_buf = st->tx,
76 .bits_per_word = 8,
77 .len = 2,
78 .cs_change = 1,
79 }, {
80 .tx_buf = st->tx + 2,
81 .bits_per_word = 8,
82 .len = 2,
83 .cs_change = 1,
84 },
85 };
86
87 mutex_lock(&st->buf_lock);
88 st->tx[0] = ADIS16209_WRITE_REG(lower_reg_address);
89 st->tx[1] = value & 0xFF;
90 st->tx[2] = ADIS16209_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 * adis16209_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 adis16209_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 adis16209_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 = 20,
124 }, {
125 .rx_buf = st->rx,
126 .bits_per_word = 8,
127 .len = 2,
128 .cs_change = 1,
129 .delay_usecs = 20,
130 },
131 };
132
133 mutex_lock(&st->buf_lock);
134 st->tx[0] = ADIS16209_READ_REG(lower_reg_address);
135 st->tx[1] = 0;
136
137 spi_message_init(&msg);
138 spi_message_add_tail(&xfers[0], &msg);
139 spi_message_add_tail(&xfers[1], &msg);
140 ret = spi_sync(st->us, &msg);
141 if (ret) {
142 dev_err(&st->us->dev,
143 "problem when reading 16 bit register 0x%02X",
144 lower_reg_address);
145 goto error_ret;
146 }
147 *val = (st->rx[0] << 8) | st->rx[1];
148
149error_ret:
150 mutex_unlock(&st->buf_lock);
151 return ret;
152}
153
154static ssize_t adis16209_read_12bit_unsigned(struct device *dev,
155 struct device_attribute *attr,
156 char *buf)
157{
158 int ret;
159 u16 val = 0;
160 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
161
162 ret = adis16209_spi_read_reg_16(dev, this_attr->address, &val);
163 if (ret)
164 return ret;
165
166 if (val & ADIS16209_ERROR_ACTIVE)
167 adis16209_check_status(dev);
168
169 return sprintf(buf, "%u\n", val & 0x0FFF);
170}
171
172static ssize_t adis16209_read_14bit_unsigned(struct device *dev,
173 struct device_attribute *attr,
174 char *buf)
175{
176 int ret;
177 u16 val = 0;
178 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
179
180 ret = adis16209_spi_read_reg_16(dev, this_attr->address, &val);
181 if (ret)
182 return ret;
183
184 if (val & ADIS16209_ERROR_ACTIVE)
185 adis16209_check_status(dev);
186
187 return sprintf(buf, "%u\n", val & 0x3FFF);
188}
189
190static ssize_t adis16209_read_temp(struct device *dev,
191 struct device_attribute *attr,
192 char *buf)
193{
194 struct iio_dev *indio_dev = dev_get_drvdata(dev);
195 ssize_t ret;
196 u16 val;
197
198 /* Take the iio_dev status lock */
199 mutex_lock(&indio_dev->mlock);
200
201 ret = adis16209_spi_read_reg_16(dev, ADIS16209_TEMP_OUT, (u16 *)&val);
202 if (ret)
203 goto error_ret;
204
205 if (val & ADIS16209_ERROR_ACTIVE)
206 adis16209_check_status(dev);
207
208 val &= 0xFFF;
209 ret = sprintf(buf, "%d\n", val);
210
211error_ret:
212 mutex_unlock(&indio_dev->mlock);
213 return ret;
214}
215
216static ssize_t adis16209_read_14bit_signed(struct device *dev,
217 struct device_attribute *attr,
218 char *buf)
219{
220 struct iio_dev *indio_dev = dev_get_drvdata(dev);
221 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
222 s16 val = 0;
223 ssize_t ret;
224
225 mutex_lock(&indio_dev->mlock);
226
227 ret = adis16209_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
228 if (!ret) {
229 if (val & ADIS16209_ERROR_ACTIVE)
230 adis16209_check_status(dev);
231
232 val = ((s16)(val << 2) >> 2);
233 ret = sprintf(buf, "%d\n", val);
234 }
235
236 mutex_unlock(&indio_dev->mlock);
237
238 return ret;
239}
240
241static ssize_t adis16209_write_16bit(struct device *dev,
242 struct device_attribute *attr,
243 const char *buf,
244 size_t len)
245{
246 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
247 int ret;
248 long val;
249
250 ret = strict_strtol(buf, 10, &val);
251 if (ret)
252 goto error_ret;
253 ret = adis16209_spi_write_reg_16(dev, this_attr->address, val);
254
255error_ret:
256 return ret ? ret : len;
257}
258
259static int adis16209_reset(struct device *dev)
260{
261 int ret;
262 ret = adis16209_spi_write_reg_8(dev,
263 ADIS16209_GLOB_CMD,
264 ADIS16209_GLOB_CMD_SW_RESET);
265 if (ret)
266 dev_err(dev, "problem resetting device");
267
268 return ret;
269}
270
271static ssize_t adis16209_write_reset(struct device *dev,
272 struct device_attribute *attr,
273 const char *buf, size_t len)
274{
275 if (len < 1)
276 return -EINVAL;
277 switch (buf[0]) {
278 case '1':
279 case 'y':
280 case 'Y':
281 return adis16209_reset(dev);
282 }
283 return -EINVAL;
284}
285
286int adis16209_set_irq(struct device *dev, bool enable)
287{
288 int ret = 0;
289 u16 msc;
290
291 ret = adis16209_spi_read_reg_16(dev, ADIS16209_MSC_CTRL, &msc);
292 if (ret)
293 goto error_ret;
294
295 msc |= ADIS16209_MSC_CTRL_ACTIVE_HIGH;
296 msc &= ~ADIS16209_MSC_CTRL_DATA_RDY_DIO2;
297 if (enable)
298 msc |= ADIS16209_MSC_CTRL_DATA_RDY_EN;
299 else
300 msc &= ~ADIS16209_MSC_CTRL_DATA_RDY_EN;
301
302 ret = adis16209_spi_write_reg_16(dev, ADIS16209_MSC_CTRL, msc);
303
304error_ret:
305 return ret;
306}
307
308static int adis16209_check_status(struct device *dev)
309{
310 u16 status;
311 int ret;
312
313 ret = adis16209_spi_read_reg_16(dev, ADIS16209_DIAG_STAT, &status);
314 if (ret < 0) {
315 dev_err(dev, "Reading status failed\n");
316 goto error_ret;
317 }
318 ret = status & 0x1F;
319
320 if (status & ADIS16209_DIAG_STAT_SELFTEST_FAIL)
321 dev_err(dev, "Self test failure\n");
322 if (status & ADIS16209_DIAG_STAT_SPI_FAIL)
323 dev_err(dev, "SPI failure\n");
324 if (status & ADIS16209_DIAG_STAT_FLASH_UPT)
325 dev_err(dev, "Flash update failed\n");
326 if (status & ADIS16209_DIAG_STAT_POWER_HIGH)
327 dev_err(dev, "Power supply above 3.625V\n");
328 if (status & ADIS16209_DIAG_STAT_POWER_LOW)
329 dev_err(dev, "Power supply below 3.15V\n");
330
331error_ret:
332 return ret;
333}
334
335static int adis16209_self_test(struct device *dev)
336{
337 int ret;
338 ret = adis16209_spi_write_reg_16(dev,
339 ADIS16209_MSC_CTRL,
340 ADIS16209_MSC_CTRL_SELF_TEST_EN);
341 if (ret) {
342 dev_err(dev, "problem starting self test");
343 goto err_ret;
344 }
345
346 adis16209_check_status(dev);
347
348err_ret:
349 return ret;
350}
351
352static int adis16209_initial_setup(struct adis16209_state *st)
353{
354 int ret;
355 struct device *dev = &st->indio_dev->dev;
356
357 /* Disable IRQ */
358 ret = adis16209_set_irq(dev, false);
359 if (ret) {
360 dev_err(dev, "disable irq failed");
361 goto err_ret;
362 }
363
364 /* Do self test */
365 ret = adis16209_self_test(dev);
366 if (ret) {
367 dev_err(dev, "self test failure");
368 goto err_ret;
369 }
370
371 /* Read status register to check the result */
372 ret = adis16209_check_status(dev);
373 if (ret) {
374 adis16209_reset(dev);
375 dev_err(dev, "device not playing ball -> reset");
376 msleep(ADIS16209_STARTUP_DELAY);
377 ret = adis16209_check_status(dev);
378 if (ret) {
379 dev_err(dev, "giving up");
380 goto err_ret;
381 }
382 }
383
384 printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
385 st->us->chip_select, st->us->irq);
386
387err_ret:
388 return ret;
389}
390
391static IIO_DEV_ATTR_IN_NAMED_RAW(supply, adis16209_read_14bit_unsigned,
392 ADIS16209_SUPPLY_OUT);
393static IIO_CONST_ATTR(in_supply_scale, "0.30518");
394static IIO_DEV_ATTR_IN_RAW(0, adis16209_read_12bit_unsigned,
395 ADIS16209_AUX_ADC);
396static IIO_CONST_ATTR(in0_scale, "0.6105");
397
398static IIO_DEV_ATTR_ACCEL_X(adis16209_read_14bit_signed,
399 ADIS16209_XACCL_OUT);
400static IIO_DEV_ATTR_ACCEL_Y(adis16209_read_14bit_signed,
401 ADIS16209_YACCL_OUT);
402static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
403 adis16209_read_14bit_signed,
404 adis16209_write_16bit,
405 ADIS16209_XACCL_NULL);
406static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
407 adis16209_read_14bit_signed,
408 adis16209_write_16bit,
409 ADIS16209_YACCL_NULL);
410static IIO_CONST_ATTR(accel_scale, "0.24414");
411
412static IIO_DEV_ATTR_INCLI_X(adis16209_read_14bit_signed,
413 ADIS16209_XINCL_OUT);
414static IIO_DEV_ATTR_INCLI_Y(adis16209_read_14bit_signed,
415 ADIS16209_YINCL_OUT);
416static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO,
417 adis16209_read_14bit_signed,
418 adis16209_write_16bit,
419 ADIS16209_XACCL_NULL);
420static IIO_DEV_ATTR_INCLI_Y_OFFSET(S_IWUSR | S_IRUGO,
421 adis16209_read_14bit_signed,
422 adis16209_write_16bit,
423 ADIS16209_YACCL_NULL);
424static IIO_CONST_ATTR(incli_scale, "0.025");
425
426static IIO_DEVICE_ATTR(rot_raw, S_IRUGO, adis16209_read_14bit_signed,
427 NULL, ADIS16209_ROT_OUT);
428
429static IIO_DEV_ATTR_TEMP(adis16209_read_temp);
430static IIO_CONST_ATTR(temp_offset, "25");
431static IIO_CONST_ATTR(temp_scale, "-0.47");
432
433static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16209_write_reset, 0);
434
435static IIO_CONST_ATTR(name, "adis16209");
436
437static struct attribute *adis16209_event_attributes[] = {
438 NULL
439};
440
441static struct attribute_group adis16209_event_attribute_group = {
442 .attrs = adis16209_event_attributes,
443};
444
445static struct attribute *adis16209_attributes[] = {
446 &iio_dev_attr_in_supply_raw.dev_attr.attr,
447 &iio_const_attr_in_supply_scale.dev_attr.attr,
448 &iio_dev_attr_temp.dev_attr.attr,
449 &iio_const_attr_temp_offset.dev_attr.attr,
450 &iio_const_attr_temp_scale.dev_attr.attr,
451 &iio_dev_attr_reset.dev_attr.attr,
452 &iio_const_attr_name.dev_attr.attr,
453 &iio_dev_attr_in0_raw.dev_attr.attr,
454 &iio_const_attr_in0_scale.dev_attr.attr,
455 &iio_dev_attr_accel_x_raw.dev_attr.attr,
456 &iio_dev_attr_accel_y_raw.dev_attr.attr,
457 &iio_dev_attr_accel_x_offset.dev_attr.attr,
458 &iio_dev_attr_accel_y_offset.dev_attr.attr,
459 &iio_const_attr_accel_scale.dev_attr.attr,
460 &iio_dev_attr_incli_x_raw.dev_attr.attr,
461 &iio_dev_attr_incli_y_raw.dev_attr.attr,
462 &iio_dev_attr_incli_x_offset.dev_attr.attr,
463 &iio_dev_attr_incli_y_offset.dev_attr.attr,
464 &iio_const_attr_incli_scale.dev_attr.attr,
465 &iio_dev_attr_rot_raw.dev_attr.attr,
466 NULL
467};
468
469static const struct attribute_group adis16209_attribute_group = {
470 .attrs = adis16209_attributes,
471};
472
473static int __devinit adis16209_probe(struct spi_device *spi)
474{
475 int ret, regdone = 0;
476 struct adis16209_state *st = kzalloc(sizeof *st, GFP_KERNEL);
477 if (!st) {
478 ret = -ENOMEM;
479 goto error_ret;
480 }
481 /* this is only used for removal purposes */
482 spi_set_drvdata(spi, st);
483
484 /* Allocate the comms buffers */
485 st->rx = kzalloc(sizeof(*st->rx)*ADIS16209_MAX_RX, GFP_KERNEL);
486 if (st->rx == NULL) {
487 ret = -ENOMEM;
488 goto error_free_st;
489 }
490 st->tx = kzalloc(sizeof(*st->tx)*ADIS16209_MAX_TX, GFP_KERNEL);
491 if (st->tx == NULL) {
492 ret = -ENOMEM;
493 goto error_free_rx;
494 }
495 st->us = spi;
496 mutex_init(&st->buf_lock);
497 /* setup the industrialio driver allocated elements */
498 st->indio_dev = iio_allocate_device();
499 if (st->indio_dev == NULL) {
500 ret = -ENOMEM;
501 goto error_free_tx;
502 }
503
504 st->indio_dev->dev.parent = &spi->dev;
505 st->indio_dev->num_interrupt_lines = 1;
506 st->indio_dev->event_attrs = &adis16209_event_attribute_group;
507 st->indio_dev->attrs = &adis16209_attribute_group;
508 st->indio_dev->dev_data = (void *)(st);
509 st->indio_dev->driver_module = THIS_MODULE;
510 st->indio_dev->modes = INDIO_DIRECT_MODE;
511
512 ret = adis16209_configure_ring(st->indio_dev);
513 if (ret)
514 goto error_free_dev;
515
516 ret = iio_device_register(st->indio_dev);
517 if (ret)
518 goto error_unreg_ring_funcs;
519 regdone = 1;
520
521 ret = adis16209_initialize_ring(st->indio_dev->ring);
522 if (ret) {
523 printk(KERN_ERR "failed to initialize the ring\n");
524 goto error_unreg_ring_funcs;
525 }
526
527 if (spi->irq) {
528 ret = iio_register_interrupt_line(spi->irq,
529 st->indio_dev,
530 0,
531 IRQF_TRIGGER_RISING,
532 "adis16209");
533 if (ret)
534 goto error_uninitialize_ring;
535
536 ret = adis16209_probe_trigger(st->indio_dev);
537 if (ret)
538 goto error_unregister_line;
539 }
540
541 /* Get the device into a sane initial state */
542 ret = adis16209_initial_setup(st);
543 if (ret)
544 goto error_remove_trigger;
545 return 0;
546
547error_remove_trigger:
548 adis16209_remove_trigger(st->indio_dev);
549error_unregister_line:
550 if (spi->irq)
551 iio_unregister_interrupt_line(st->indio_dev, 0);
552error_uninitialize_ring:
553 adis16209_uninitialize_ring(st->indio_dev->ring);
554error_unreg_ring_funcs:
555 adis16209_unconfigure_ring(st->indio_dev);
556error_free_dev:
557 if (regdone)
558 iio_device_unregister(st->indio_dev);
559 else
560 iio_free_device(st->indio_dev);
561error_free_tx:
562 kfree(st->tx);
563error_free_rx:
564 kfree(st->rx);
565error_free_st:
566 kfree(st);
567error_ret:
568 return ret;
569}
570
571static int adis16209_remove(struct spi_device *spi)
572{
573 struct adis16209_state *st = spi_get_drvdata(spi);
574 struct iio_dev *indio_dev = st->indio_dev;
575
576 flush_scheduled_work();
577
578 adis16209_remove_trigger(indio_dev);
579 if (spi->irq)
580 iio_unregister_interrupt_line(indio_dev, 0);
581
582 adis16209_uninitialize_ring(indio_dev->ring);
583 iio_device_unregister(indio_dev);
584 adis16209_unconfigure_ring(indio_dev);
585 kfree(st->tx);
586 kfree(st->rx);
587 kfree(st);
588
589 return 0;
590}
591
592static struct spi_driver adis16209_driver = {
593 .driver = {
594 .name = "adis16209",
595 .owner = THIS_MODULE,
596 },
597 .probe = adis16209_probe,
598 .remove = __devexit_p(adis16209_remove),
599};
600
601static __init int adis16209_init(void)
602{
603 return spi_register_driver(&adis16209_driver);
604}
605module_init(adis16209_init);
606
607static __exit void adis16209_exit(void)
608{
609 spi_unregister_driver(&adis16209_driver);
610}
611module_exit(adis16209_exit);
612
613MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
614MODULE_DESCRIPTION("Analog Devices ADIS16209 Digital Vibration Sensor driver");
615MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
new file mode 100644
index 00000000000..533e2857491
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -0,0 +1,266 @@
1#include <linux/interrupt.h>
2#include <linux/irq.h>
3#include <linux/gpio.h>
4#include <linux/workqueue.h>
5#include <linux/mutex.h>
6#include <linux/device.h>
7#include <linux/kernel.h>
8#include <linux/spi/spi.h>
9#include <linux/sysfs.h>
10#include <linux/list.h>
11
12#include "../iio.h"
13#include "../sysfs.h"
14#include "../ring_sw.h"
15#include "accel.h"
16#include "../trigger.h"
17#include "adis16209.h"
18
19/**
20 * combine_8_to_16() utility function to munge to u8s into u16
21 **/
22static inline u16 combine_8_to_16(u8 lower, u8 upper)
23{
24 u16 _lower = lower;
25 u16 _upper = upper;
26 return _lower | (_upper << 8);
27}
28
29static IIO_SCAN_EL_C(supply, ADIS16209_SCAN_SUPPLY, IIO_UNSIGNED(14),
30 ADIS16209_SUPPLY_OUT, NULL);
31static IIO_SCAN_EL_C(accel_x, ADIS16209_SCAN_ACC_X, IIO_SIGNED(14),
32 ADIS16209_XACCL_OUT, NULL);
33static IIO_SCAN_EL_C(accel_y, ADIS16209_SCAN_ACC_Y, IIO_SIGNED(14),
34 ADIS16209_YACCL_OUT, NULL);
35static IIO_SCAN_EL_C(aux_adc, ADIS16209_SCAN_AUX_ADC, IIO_UNSIGNED(12),
36 ADIS16209_AUX_ADC, NULL);
37static IIO_SCAN_EL_C(temp, ADIS16209_SCAN_TEMP, IIO_UNSIGNED(12),
38 ADIS16209_TEMP_OUT, NULL);
39static IIO_SCAN_EL_C(incli_x, ADIS16209_SCAN_INCLI_X, IIO_SIGNED(14),
40 ADIS16209_XINCL_OUT, NULL);
41static IIO_SCAN_EL_C(incli_y, ADIS16209_SCAN_INCLI_Y, IIO_SIGNED(14),
42 ADIS16209_YINCL_OUT, NULL);
43static IIO_SCAN_EL_C(rot, ADIS16209_SCAN_ROT, IIO_SIGNED(14),
44 ADIS16209_ROT_OUT, NULL);
45
46static IIO_SCAN_EL_TIMESTAMP(8);
47
48static struct attribute *adis16209_scan_el_attrs[] = {
49 &iio_scan_el_supply.dev_attr.attr,
50 &iio_scan_el_accel_x.dev_attr.attr,
51 &iio_scan_el_accel_y.dev_attr.attr,
52 &iio_scan_el_aux_adc.dev_attr.attr,
53 &iio_scan_el_temp.dev_attr.attr,
54 &iio_scan_el_incli_x.dev_attr.attr,
55 &iio_scan_el_incli_y.dev_attr.attr,
56 &iio_scan_el_rot.dev_attr.attr,
57 &iio_scan_el_timestamp.dev_attr.attr,
58 NULL,
59};
60
61static struct attribute_group adis16209_scan_el_group = {
62 .attrs = adis16209_scan_el_attrs,
63 .name = "scan_elements",
64};
65
66/**
67 * adis16209_poll_func_th() top half interrupt handler called by trigger
68 * @private_data: iio_dev
69 **/
70static void adis16209_poll_func_th(struct iio_dev *indio_dev)
71{
72 struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
73 st->last_timestamp = indio_dev->trig->timestamp;
74 schedule_work(&st->work_trigger_to_ring);
75}
76
77/**
78 * adis16209_read_ring_data() read data registers which will be placed into ring
79 * @dev: device associated with child of actual device (iio_dev or iio_trig)
80 * @rx: somewhere to pass back the value read
81 **/
82static int adis16209_read_ring_data(struct device *dev, u8 *rx)
83{
84 struct spi_message msg;
85 struct iio_dev *indio_dev = dev_get_drvdata(dev);
86 struct adis16209_state *st = iio_dev_get_devdata(indio_dev);
87 struct spi_transfer xfers[ADIS16209_OUTPUTS + 1];
88 int ret;
89 int i;
90
91 mutex_lock(&st->buf_lock);
92
93 spi_message_init(&msg);
94
95 memset(xfers, 0, sizeof(xfers));
96 for (i = 0; i <= ADIS16209_OUTPUTS; i++) {
97 xfers[i].bits_per_word = 8;
98 xfers[i].cs_change = 1;
99 xfers[i].len = 2;
100 xfers[i].delay_usecs = 20;
101 xfers[i].tx_buf = st->tx + 2 * i;
102 st->tx[2 * i]
103 = ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i);
104 st->tx[2 * i + 1] = 0;
105 if (i >= 1)
106 xfers[i].rx_buf = rx + 2 * (i - 1);
107 spi_message_add_tail(&xfers[i], &msg);
108 }
109
110 ret = spi_sync(st->us, &msg);
111 if (ret)
112 dev_err(&st->us->dev, "problem when burst reading");
113
114 mutex_unlock(&st->buf_lock);
115
116 return ret;
117}
118
119/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
120 * specific to be rolled into the core.
121 */
122static void adis16209_trigger_bh_to_ring(struct work_struct *work_s)
123{
124 struct adis16209_state *st
125 = container_of(work_s, struct adis16209_state,
126 work_trigger_to_ring);
127
128 int i = 0;
129 s16 *data;
130 size_t datasize = st->indio_dev
131 ->ring->access.get_bpd(st->indio_dev->ring);
132
133 data = kmalloc(datasize , GFP_KERNEL);
134 if (data == NULL) {
135 dev_err(&st->us->dev, "memory alloc failed in ring bh");
136 return;
137 }
138
139 if (st->indio_dev->scan_count)
140 if (adis16209_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
141 for (; i < st->indio_dev->scan_count; i++) {
142 data[i] = combine_8_to_16(st->rx[i*2+1],
143 st->rx[i*2]);
144 }
145
146 /* Guaranteed to be aligned with 8 byte boundary */
147 if (st->indio_dev->scan_timestamp)
148 *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
149
150 st->indio_dev->ring->access.store_to(st->indio_dev->ring,
151 (u8 *)data,
152 st->last_timestamp);
153
154 iio_trigger_notify_done(st->indio_dev->trig);
155 kfree(data);
156
157 return;
158}
159
160/* in these circumstances is it better to go with unaligned packing and
161 * deal with the cost?*/
162static int adis16209_data_rdy_ring_preenable(struct iio_dev *indio_dev)
163{
164 size_t size;
165 dev_dbg(&indio_dev->dev, "%s\n", __func__);
166 /* Check if there are any scan elements enabled, if not fail*/
167 if (!(indio_dev->scan_count || indio_dev->scan_timestamp))
168 return -EINVAL;
169
170 if (indio_dev->ring->access.set_bpd) {
171 if (indio_dev->scan_timestamp)
172 if (indio_dev->scan_count)
173 /* Timestamp (aligned to s64) and data */
174 size = (((indio_dev->scan_count * sizeof(s16))
175 + sizeof(s64) - 1)
176 & ~(sizeof(s64) - 1))
177 + sizeof(s64);
178 else /* Timestamp only */
179 size = sizeof(s64);
180 else /* Data only */
181 size = indio_dev->scan_count*sizeof(s16);
182 indio_dev->ring->access.set_bpd(indio_dev->ring, size);
183 }
184
185 return 0;
186}
187
188static int adis16209_data_rdy_ring_postenable(struct iio_dev *indio_dev)
189{
190 return indio_dev->trig
191 ? iio_trigger_attach_poll_func(indio_dev->trig,
192 indio_dev->pollfunc)
193 : 0;
194}
195
196static int adis16209_data_rdy_ring_predisable(struct iio_dev *indio_dev)
197{
198 return indio_dev->trig
199 ? iio_trigger_dettach_poll_func(indio_dev->trig,
200 indio_dev->pollfunc)
201 : 0;
202}
203
204void adis16209_unconfigure_ring(struct iio_dev *indio_dev)
205{
206 kfree(indio_dev->pollfunc);
207 iio_sw_rb_free(indio_dev->ring);
208}
209
210int adis16209_configure_ring(struct iio_dev *indio_dev)
211{
212 int ret = 0;
213 struct adis16209_state *st = indio_dev->dev_data;
214 struct iio_ring_buffer *ring;
215 INIT_WORK(&st->work_trigger_to_ring, adis16209_trigger_bh_to_ring);
216 /* Set default scan mode */
217
218 iio_scan_mask_set(indio_dev, iio_scan_el_supply.number);
219 iio_scan_mask_set(indio_dev, iio_scan_el_rot.number);
220 iio_scan_mask_set(indio_dev, iio_scan_el_accel_x.number);
221 iio_scan_mask_set(indio_dev, iio_scan_el_accel_y.number);
222 iio_scan_mask_set(indio_dev, iio_scan_el_temp.number);
223 iio_scan_mask_set(indio_dev, iio_scan_el_aux_adc.number);
224 iio_scan_mask_set(indio_dev, iio_scan_el_incli_x.number);
225 iio_scan_mask_set(indio_dev, iio_scan_el_incli_y.number);
226 indio_dev->scan_timestamp = true;
227
228 indio_dev->scan_el_attrs = &adis16209_scan_el_group;
229
230 ring = iio_sw_rb_allocate(indio_dev);
231 if (!ring) {
232 ret = -ENOMEM;
233 return ret;
234 }
235 indio_dev->ring = ring;
236 /* Effectively select the ring buffer implementation */
237 iio_ring_sw_register_funcs(&ring->access);
238 ring->preenable = &adis16209_data_rdy_ring_preenable;
239 ring->postenable = &adis16209_data_rdy_ring_postenable;
240 ring->predisable = &adis16209_data_rdy_ring_predisable;
241 ring->owner = THIS_MODULE;
242
243 indio_dev->pollfunc = kzalloc(sizeof(*indio_dev->pollfunc), GFP_KERNEL);
244 if (indio_dev->pollfunc == NULL) {
245 ret = -ENOMEM;
246 goto error_iio_sw_rb_free;;
247 }
248 indio_dev->pollfunc->poll_func_main = &adis16209_poll_func_th;
249 indio_dev->pollfunc->private_data = indio_dev;
250 indio_dev->modes |= INDIO_RING_TRIGGERED;
251 return 0;
252
253error_iio_sw_rb_free:
254 iio_sw_rb_free(indio_dev->ring);
255 return ret;
256}
257
258int adis16209_initialize_ring(struct iio_ring_buffer *ring)
259{
260 return iio_ring_buffer_register(ring, 0);
261}
262
263void adis16209_uninitialize_ring(struct iio_ring_buffer *ring)
264{
265 iio_ring_buffer_unregister(ring);
266}
diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c
new file mode 100644
index 00000000000..4a0507c9a13
--- /dev/null
+++ b/drivers/staging/iio/accel/adis16209_trigger.c
@@ -0,0 +1,124 @@
1#include <linux/interrupt.h>
2#include <linux/irq.h>
3#include <linux/mutex.h>
4#include <linux/device.h>
5#include <linux/kernel.h>
6#include <linux/sysfs.h>
7#include <linux/list.h>
8#include <linux/spi/spi.h>
9
10#include "../iio.h"
11#include "../sysfs.h"
12#include "../trigger.h"
13#include "adis16209.h"
14
15/**
16 * adis16209_data_rdy_trig_poll() the event handler for the data rdy trig
17 **/
18static int adis16209_data_rdy_trig_poll(struct iio_dev *dev_info,
19 int index,
20 s64 timestamp,
21 int no_test)
22{
23 struct adis16209_state *st = iio_dev_get_devdata(dev_info);
24 struct iio_trigger *trig = st->trig;
25
26 trig->timestamp = timestamp;
27 iio_trigger_poll(trig);
28
29 return IRQ_HANDLED;
30}
31
32IIO_EVENT_SH(data_rdy_trig, &adis16209_data_rdy_trig_poll);
33
34static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
35
36static struct attribute *adis16209_trigger_attrs[] = {
37 &dev_attr_name.attr,
38 NULL,
39};
40
41static const struct attribute_group adis16209_trigger_attr_group = {
42 .attrs = adis16209_trigger_attrs,
43};
44
45/**
46 * adis16209_data_rdy_trigger_set_state() set datardy interrupt state
47 **/
48static int adis16209_data_rdy_trigger_set_state(struct iio_trigger *trig,
49 bool state)
50{
51 struct adis16209_state *st = trig->private_data;
52 struct iio_dev *indio_dev = st->indio_dev;
53 int ret = 0;
54
55 dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
56 ret = adis16209_set_irq(&st->indio_dev->dev, state);
57 if (state == false) {
58 iio_remove_event_from_list(&iio_event_data_rdy_trig,
59 &indio_dev->interrupts[0]
60 ->ev_list);
61 flush_scheduled_work();
62 } else {
63 iio_add_event_to_list(&iio_event_data_rdy_trig,
64 &indio_dev->interrupts[0]->ev_list);
65 }
66 return ret;
67}
68
69/**
70 * adis16209_trig_try_reen() try renabling irq for data rdy trigger
71 * @trig: the datardy trigger
72 **/
73static int adis16209_trig_try_reen(struct iio_trigger *trig)
74{
75 struct adis16209_state *st = trig->private_data;
76 enable_irq(st->us->irq);
77 return 0;
78}
79
80int adis16209_probe_trigger(struct iio_dev *indio_dev)
81{
82 int ret;
83 struct adis16209_state *st = indio_dev->dev_data;
84
85 st->trig = iio_allocate_trigger();
86 st->trig->name = kmalloc(IIO_TRIGGER_NAME_LENGTH, GFP_KERNEL);
87 if (!st->trig->name) {
88 ret = -ENOMEM;
89 goto error_free_trig;
90 }
91 snprintf((char *)st->trig->name,
92 IIO_TRIGGER_NAME_LENGTH,
93 "adis16209-dev%d", indio_dev->id);
94 st->trig->dev.parent = &st->us->dev;
95 st->trig->owner = THIS_MODULE;
96 st->trig->private_data = st;
97 st->trig->set_trigger_state = &adis16209_data_rdy_trigger_set_state;
98 st->trig->try_reenable = &adis16209_trig_try_reen;
99 st->trig->control_attrs = &adis16209_trigger_attr_group;
100 ret = iio_trigger_register(st->trig);
101
102 /* select default trigger */
103 indio_dev->trig = st->trig;
104 if (ret)
105 goto error_free_trig_name;
106
107 return 0;
108
109error_free_trig_name:
110 kfree(st->trig->name);
111error_free_trig:
112 iio_free_trigger(st->trig);
113
114 return ret;
115}
116
117void adis16209_remove_trigger(struct iio_dev *indio_dev)
118{
119 struct adis16209_state *state = indio_dev->dev_data;
120
121 iio_trigger_unregister(state->trig);
122 kfree(state->trig->name);
123 iio_free_trigger(state->trig);
124}