blob: a812e3e165360f0973286f6274fa9301c6a145c1 [file] [log] [blame]
Jonathan Cameron66533b42009-08-18 18:06:22 +01001/*
2 * lis3l02dq.c support STMicroelectronics LISD02DQ
3 * 3d 2g Linear Accelerometers via SPI
4 *
5 * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Settings:
12 * 16 bit left justified mode used.
13 */
14
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/gpio.h>
18#include <linux/workqueue.h>
19#include <linux/mutex.h>
20#include <linux/device.h>
21#include <linux/kernel.h>
22#include <linux/spi/spi.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Jonathan Cameron66533b42009-08-18 18:06:22 +010024
25#include <linux/sysfs.h>
26#include <linux/list.h>
27
28#include "../iio.h"
29#include "../sysfs.h"
Jonathan Cameron26620512010-07-11 16:39:14 +010030#include "../ring_generic.h"
Jonathan Cameron73bce122010-07-11 16:39:19 +010031#include "../ring_sw.h"
32
Jonathan Cameron66533b42009-08-18 18:06:22 +010033#include "accel.h"
34
35#include "lis3l02dq.h"
36
37/* At the moment the spi framework doesn't allow global setting of cs_change.
38 * It's in the likely to be added comment at the top of spi.h.
39 * This means that use cannot be made of spi_write etc.
40 */
41
Jonathan Cameron1b076b52011-05-18 14:40:58 +010042/**
43 * lis3l02dq_spi_read_reg_8() - read single byte from a single register
44 * @indio_dev: iio_dev for this actual device
45 * @reg_address: the address of the register to be read
46 * @val: pass back the resulting value
47 **/
48int lis3l02dq_spi_read_reg_8(struct iio_dev *indio_dev,
49 u8 reg_address, u8 *val)
Jonathan Cameron66533b42009-08-18 18:06:22 +010050{
Jonathan Cameron1b076b52011-05-18 14:40:58 +010051 struct iio_sw_ring_helper_state *h = iio_dev_get_devdata(indio_dev);
52 struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
Jonathan Cameron66533b42009-08-18 18:06:22 +010053 struct spi_message msg;
Jonathan Cameronf3736412011-05-18 14:40:52 +010054 int ret;
Jonathan Cameron66533b42009-08-18 18:06:22 +010055 struct spi_transfer xfer = {
56 .tx_buf = st->tx,
57 .rx_buf = st->rx,
58 .bits_per_word = 8,
59 .len = 2,
Jonathan Cameron66533b42009-08-18 18:06:22 +010060 };
61
62 mutex_lock(&st->buf_lock);
63 st->tx[0] = LIS3L02DQ_READ_REG(reg_address);
64 st->tx[1] = 0;
65
66 spi_message_init(&msg);
67 spi_message_add_tail(&xfer, &msg);
68 ret = spi_sync(st->us, &msg);
69 *val = st->rx[1];
70 mutex_unlock(&st->buf_lock);
71
72 return ret;
73}
74
75/**
76 * lis3l02dq_spi_write_reg_8() - write single byte to a register
Jonathan Cameron1b076b52011-05-18 14:40:58 +010077 * @indio_dev: iio_dev for this device
Lucas De Marchi25985ed2011-03-30 22:57:33 -030078 * @reg_address: the address of the register to be written
Jonathan Cameron66533b42009-08-18 18:06:22 +010079 * @val: the value to write
80 **/
Jonathan Cameron1b076b52011-05-18 14:40:58 +010081int lis3l02dq_spi_write_reg_8(struct iio_dev *indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +010082 u8 reg_address,
83 u8 *val)
84{
85 int ret;
Jonathan Cameron73bce122010-07-11 16:39:19 +010086 struct iio_sw_ring_helper_state *h
87 = iio_dev_get_devdata(indio_dev);
88 struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
Jonathan Cameron66533b42009-08-18 18:06:22 +010089
90 mutex_lock(&st->buf_lock);
91 st->tx[0] = LIS3L02DQ_WRITE_REG(reg_address);
92 st->tx[1] = *val;
Jonathan Cameron1b076b52011-05-18 14:40:58 +010093 ret = spi_write(st->us, st->tx, 2);
Jonathan Cameron66533b42009-08-18 18:06:22 +010094 mutex_unlock(&st->buf_lock);
95
96 return ret;
97}
98
99/**
100 * lisl302dq_spi_write_reg_s16() - write 2 bytes to a pair of registers
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100101 * @indio_dev: iio_dev for this device
102 * @lower_reg_address: the address of the lower of the two registers.
103 * Second register is assumed to have address one greater.
104 * @value: value to be written
Jonathan Cameron66533b42009-08-18 18:06:22 +0100105 **/
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100106static int lis3l02dq_spi_write_reg_s16(struct iio_dev *indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100107 u8 lower_reg_address,
108 s16 value)
109{
110 int ret;
111 struct spi_message msg;
Jonathan Cameron73bce122010-07-11 16:39:19 +0100112 struct iio_sw_ring_helper_state *h
113 = iio_dev_get_devdata(indio_dev);
114 struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100115 struct spi_transfer xfers[] = { {
116 .tx_buf = st->tx,
117 .bits_per_word = 8,
118 .len = 2,
119 .cs_change = 1,
120 }, {
121 .tx_buf = st->tx + 2,
122 .bits_per_word = 8,
123 .len = 2,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100124 },
125 };
126
127 mutex_lock(&st->buf_lock);
128 st->tx[0] = LIS3L02DQ_WRITE_REG(lower_reg_address);
129 st->tx[1] = value & 0xFF;
130 st->tx[2] = LIS3L02DQ_WRITE_REG(lower_reg_address + 1);
131 st->tx[3] = (value >> 8) & 0xFF;
132
133 spi_message_init(&msg);
134 spi_message_add_tail(&xfers[0], &msg);
135 spi_message_add_tail(&xfers[1], &msg);
136 ret = spi_sync(st->us, &msg);
137 mutex_unlock(&st->buf_lock);
138
139 return ret;
140}
141
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100142static int lis3l02dq_read_reg_s16(struct iio_dev *indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100143 u8 lower_reg_address,
144 int *val)
Jonathan Cameron66533b42009-08-18 18:06:22 +0100145{
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100146 struct iio_sw_ring_helper_state *h
147 = iio_dev_get_devdata(indio_dev);
148 struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
149
Jonathan Cameron66533b42009-08-18 18:06:22 +0100150 struct spi_message msg;
Jonathan Cameron66533b42009-08-18 18:06:22 +0100151 int ret;
Jonathan Cameronf3736412011-05-18 14:40:52 +0100152 s16 tempval;
Jonathan Cameron66533b42009-08-18 18:06:22 +0100153 struct spi_transfer xfers[] = { {
154 .tx_buf = st->tx,
155 .rx_buf = st->rx,
156 .bits_per_word = 8,
157 .len = 2,
158 .cs_change = 1,
159 }, {
160 .tx_buf = st->tx + 2,
161 .rx_buf = st->rx + 2,
162 .bits_per_word = 8,
163 .len = 2,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100164 },
165 };
166
167 mutex_lock(&st->buf_lock);
168 st->tx[0] = LIS3L02DQ_READ_REG(lower_reg_address);
169 st->tx[1] = 0;
Jonathan Cameronf3736412011-05-18 14:40:52 +0100170 st->tx[2] = LIS3L02DQ_READ_REG(lower_reg_address + 1);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100171 st->tx[3] = 0;
172
173 spi_message_init(&msg);
174 spi_message_add_tail(&xfers[0], &msg);
175 spi_message_add_tail(&xfers[1], &msg);
176 ret = spi_sync(st->us, &msg);
177 if (ret) {
178 dev_err(&st->us->dev, "problem when reading 16 bit register");
179 goto error_ret;
180 }
Jonathan Cameronf3736412011-05-18 14:40:52 +0100181 tempval = (s16)(st->rx[1]) | ((s16)(st->rx[3]) << 8);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100182
Jonathan Cameronf3736412011-05-18 14:40:52 +0100183 *val = tempval;
Jonathan Cameron66533b42009-08-18 18:06:22 +0100184error_ret:
185 mutex_unlock(&st->buf_lock);
186 return ret;
187}
188
Jonathan Cameronf3736412011-05-18 14:40:52 +0100189enum lis3l02dq_rm_ind {
190 LIS3L02DQ_ACCEL,
191 LIS3L02DQ_GAIN,
192 LIS3L02DQ_BIAS,
193};
194
195static u8 lis3l02dq_axis_map[3][3] = {
196 [LIS3L02DQ_ACCEL] = { LIS3L02DQ_REG_OUT_X_L_ADDR,
197 LIS3L02DQ_REG_OUT_Y_L_ADDR,
198 LIS3L02DQ_REG_OUT_Z_L_ADDR },
199 [LIS3L02DQ_GAIN] = { LIS3L02DQ_REG_GAIN_X_ADDR,
200 LIS3L02DQ_REG_GAIN_Y_ADDR,
201 LIS3L02DQ_REG_GAIN_Z_ADDR },
202 [LIS3L02DQ_BIAS] = { LIS3L02DQ_REG_OFFSET_X_ADDR,
203 LIS3L02DQ_REG_OFFSET_Y_ADDR,
204 LIS3L02DQ_REG_OFFSET_Z_ADDR }
205};
206
207static int lis3l02dq_read_thresh(struct iio_dev *indio_dev,
208 int e,
209 int *val)
Jonathan Cameron66533b42009-08-18 18:06:22 +0100210{
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100211 return lis3l02dq_read_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, val);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100212}
213
Jonathan Cameronf3736412011-05-18 14:40:52 +0100214static int lis3l02dq_write_thresh(struct iio_dev *indio_dev,
215 int event_code,
216 int val)
Jonathan Cameron66533b42009-08-18 18:06:22 +0100217{
Jonathan Cameronf3736412011-05-18 14:40:52 +0100218 u16 value = val;
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100219 return lis3l02dq_spi_write_reg_s16(indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100220 LIS3L02DQ_REG_THS_L_ADDR,
221 value);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100222}
223
Jonathan Cameronf3736412011-05-18 14:40:52 +0100224static int lis3l02dq_read_raw(struct iio_dev *indio_dev,
225 struct iio_chan_spec const *chan,
226 int *val,
227 int *val2,
228 long mask)
Jonathan Cameron66533b42009-08-18 18:06:22 +0100229{
Jonathan Cameronf3736412011-05-18 14:40:52 +0100230 u8 utemp;
231 s8 stemp;
232 ssize_t ret = 0;
Jonathan Cameronf3736412011-05-18 14:40:52 +0100233 u8 reg;
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100234
Jonathan Cameronf3736412011-05-18 14:40:52 +0100235 switch (mask) {
236 case 0:
237 /* Take the iio_dev status lock */
238 mutex_lock(&indio_dev->mlock);
239 if (indio_dev->currentmode == INDIO_RING_TRIGGERED)
240 ret = lis3l02dq_read_accel_from_ring(indio_dev->ring,
241 chan->scan_index,
242 val);
243 else {
244 reg = lis3l02dq_axis_map
245 [LIS3L02DQ_ACCEL][chan->address];
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100246 ret = lis3l02dq_read_reg_s16(indio_dev, reg, val);
Jonathan Cameronf3736412011-05-18 14:40:52 +0100247 }
248 mutex_unlock(&indio_dev->mlock);
249 return IIO_VAL_INT;
250 case (1 << IIO_CHAN_INFO_SCALE_SHARED):
251 *val = 0;
252 *val2 = 9580;
253 return IIO_VAL_INT_PLUS_MICRO;
254 case (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE):
255 reg = lis3l02dq_axis_map[LIS3L02DQ_GAIN][chan->address];
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100256 ret = lis3l02dq_spi_read_reg_8(indio_dev, reg, &utemp);
Jonathan Cameronf3736412011-05-18 14:40:52 +0100257 if (ret)
258 goto error_ret;
259 /* to match with what previous code does */
260 *val = utemp;
261 return IIO_VAL_INT;
Jonathan Cameron66533b42009-08-18 18:06:22 +0100262
Jonathan Cameronf3736412011-05-18 14:40:52 +0100263 case (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE):
264 reg = lis3l02dq_axis_map[LIS3L02DQ_BIAS][chan->address];
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100265 ret = lis3l02dq_spi_read_reg_8(indio_dev, reg, (u8 *)&stemp);
Jonathan Cameronf3736412011-05-18 14:40:52 +0100266 /* to match with what previous code does */
267 *val = stemp;
268 return IIO_VAL_INT;
269 }
Jonathan Cameron66533b42009-08-18 18:06:22 +0100270error_ret:
Jonathan Cameron66533b42009-08-18 18:06:22 +0100271 return ret;
272}
273
Jonathan Cameron66533b42009-08-18 18:06:22 +0100274static ssize_t lis3l02dq_read_frequency(struct device *dev,
275 struct device_attribute *attr,
276 char *buf)
277{
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100278 struct iio_dev *indio_dev = dev_get_drvdata(dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100279 int ret, len = 0;
280 s8 t;
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100281 ret = lis3l02dq_spi_read_reg_8(indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100282 LIS3L02DQ_REG_CTRL_1_ADDR,
283 (u8 *)&t);
284 if (ret)
285 return ret;
286 t &= LIS3L02DQ_DEC_MASK;
287 switch (t) {
288 case LIS3L02DQ_REG_CTRL_1_DF_128:
289 len = sprintf(buf, "280\n");
290 break;
291 case LIS3L02DQ_REG_CTRL_1_DF_64:
292 len = sprintf(buf, "560\n");
293 break;
294 case LIS3L02DQ_REG_CTRL_1_DF_32:
295 len = sprintf(buf, "1120\n");
296 break;
297 case LIS3L02DQ_REG_CTRL_1_DF_8:
298 len = sprintf(buf, "4480\n");
299 break;
300 }
301 return len;
302}
303
304static ssize_t lis3l02dq_write_frequency(struct device *dev,
305 struct device_attribute *attr,
306 const char *buf,
307 size_t len)
308{
309 struct iio_dev *indio_dev = dev_get_drvdata(dev);
310 long val;
311 int ret;
312 u8 t;
313
314 ret = strict_strtol(buf, 10, &val);
315 if (ret)
316 return ret;
317
318 mutex_lock(&indio_dev->mlock);
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100319 ret = lis3l02dq_spi_read_reg_8(indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100320 LIS3L02DQ_REG_CTRL_1_ADDR,
321 &t);
322 if (ret)
323 goto error_ret_mutex;
324 /* Wipe the bits clean */
325 t &= ~LIS3L02DQ_DEC_MASK;
326 switch (val) {
327 case 280:
328 t |= LIS3L02DQ_REG_CTRL_1_DF_128;
329 break;
330 case 560:
331 t |= LIS3L02DQ_REG_CTRL_1_DF_64;
332 break;
333 case 1120:
334 t |= LIS3L02DQ_REG_CTRL_1_DF_32;
335 break;
336 case 4480:
337 t |= LIS3L02DQ_REG_CTRL_1_DF_8;
338 break;
339 default:
340 ret = -EINVAL;
341 goto error_ret_mutex;
Joe Perches95cd17c2011-04-10 14:31:35 -0700342 }
Jonathan Cameron66533b42009-08-18 18:06:22 +0100343
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100344 ret = lis3l02dq_spi_write_reg_8(indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100345 LIS3L02DQ_REG_CTRL_1_ADDR,
346 &t);
347
348error_ret_mutex:
349 mutex_unlock(&indio_dev->mlock);
350
351 return ret ? ret : len;
352}
353
354static int lis3l02dq_initial_setup(struct lis3l02dq_state *st)
355{
356 int ret;
357 u8 val, valtest;
358
359 st->us->mode = SPI_MODE_3;
360
361 spi_setup(st->us);
362
363 val = LIS3L02DQ_DEFAULT_CTRL1;
364 /* Write suitable defaults to ctrl1 */
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100365 ret = lis3l02dq_spi_write_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100366 LIS3L02DQ_REG_CTRL_1_ADDR,
367 &val);
368 if (ret) {
369 dev_err(&st->us->dev, "problem with setup control register 1");
370 goto err_ret;
371 }
372 /* Repeat as sometimes doesn't work first time?*/
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100373 ret = lis3l02dq_spi_write_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100374 LIS3L02DQ_REG_CTRL_1_ADDR,
375 &val);
376 if (ret) {
377 dev_err(&st->us->dev, "problem with setup control register 1");
378 goto err_ret;
379 }
380
381 /* Read back to check this has worked acts as loose test of correct
382 * chip */
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100383 ret = lis3l02dq_spi_read_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100384 LIS3L02DQ_REG_CTRL_1_ADDR,
385 &valtest);
386 if (ret || (valtest != val)) {
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100387 dev_err(&st->help.indio_dev->dev,
388 "device not playing ball %d %d\n", valtest, val);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100389 ret = -EINVAL;
390 goto err_ret;
391 }
392
393 val = LIS3L02DQ_DEFAULT_CTRL2;
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100394 ret = lis3l02dq_spi_write_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100395 LIS3L02DQ_REG_CTRL_2_ADDR,
396 &val);
397 if (ret) {
398 dev_err(&st->us->dev, "problem with setup control register 2");
399 goto err_ret;
400 }
401
402 val = LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC;
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100403 ret = lis3l02dq_spi_write_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100404 LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
405 &val);
406 if (ret)
407 dev_err(&st->us->dev, "problem with interrupt cfg register");
408err_ret:
409
410 return ret;
411}
412
Jonathan Cameron66533b42009-08-18 18:06:22 +0100413static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
414 lis3l02dq_read_frequency,
415 lis3l02dq_write_frequency);
416
Jonathan Cameronf3fb0012010-05-04 14:42:58 +0100417static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("280 560 1120 4480");
Jonathan Cameron66533b42009-08-18 18:06:22 +0100418
Jonathan Cameron73bce122010-07-11 16:39:19 +0100419static int lis3l02dq_thresh_handler_th(struct iio_dev *indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100420 int index,
421 s64 timestamp,
422 int no_test)
423{
Jonathan Cameron73bce122010-07-11 16:39:19 +0100424 struct iio_sw_ring_helper_state *h
425 = iio_dev_get_devdata(indio_dev);
426 struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100427
428 /* Stash the timestamp somewhere convenient for the bh */
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100429 st->thresh_timestamp = timestamp;
Jonathan Camerond0348e52010-06-26 12:54:15 +0100430 schedule_work(&st->work_thresh);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100431
432 return 0;
433}
434
Jonathan Cameronf3736412011-05-18 14:40:52 +0100435/* A shared handler for a number of threshold types */
436IIO_EVENT_SH(threshold, &lis3l02dq_thresh_handler_th);
437
438
439#define LIS3L02DQ_INFO_MASK \
440 ((1 << IIO_CHAN_INFO_SCALE_SHARED) | \
441 (1 << IIO_CHAN_INFO_CALIBSCALE_SEPARATE) | \
442 (1 << IIO_CHAN_INFO_CALIBBIAS_SEPARATE))
443
444#define LIS3L02DQ_EVENT_MASK \
445 (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
446 IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
447
448static struct iio_chan_spec lis3l02dq_channels[] = {
449 IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK,
450 0, 0, IIO_ST('s', 12, 16, 0),
451 LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
452 IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK,
453 1, 1, IIO_ST('s', 12, 16, 0),
454 LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
455 IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK,
456 2, 2, IIO_ST('s', 12, 16, 0),
457 LIS3L02DQ_EVENT_MASK, &iio_event_threshold),
458 IIO_CHAN_SOFT_TIMESTAMP(3)
459};
460
461
462static ssize_t lis3l02dq_read_event_config(struct iio_dev *indio_dev,
463 int event_code)
464{
465
466 u8 val;
467 int ret;
468 u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
469 (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
470 IIO_EV_DIR_RISING)));
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100471 ret = lis3l02dq_spi_read_reg_8(indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100472 LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
473 &val);
474 if (ret < 0)
475 return ret;
476
477 return !!(val & mask);
478}
479
480static int lis3l02dq_write_event_config(struct iio_dev *indio_dev,
481 int event_code,
482 struct iio_event_handler_list *list_el,
483 int state)
484{
485 int ret = 0;
486 u8 val, control;
487 u8 currentlyset;
488 bool changed = false;
489 u8 mask = (1 << (IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code)*2 +
490 (IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
491 IIO_EV_DIR_RISING)));
492
493 mutex_lock(&indio_dev->mlock);
494 /* read current control */
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100495 ret = lis3l02dq_spi_read_reg_8(indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100496 LIS3L02DQ_REG_CTRL_2_ADDR,
497 &control);
498 if (ret)
499 goto error_ret;
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100500 ret = lis3l02dq_spi_read_reg_8(indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100501 LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
502 &val);
503 if (ret < 0)
504 goto error_ret;
505 currentlyset = val & mask;
506
507 if (!currentlyset && state) {
508 changed = true;
509 val |= mask;
510 iio_add_event_to_list(list_el,
511 &indio_dev->interrupts[0]->ev_list);
512
513 } else if (currentlyset && !state) {
514 changed = true;
515 val &= ~mask;
516 iio_remove_event_from_list(list_el,
517 &indio_dev->interrupts[0]->ev_list);
518 }
519 if (changed) {
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100520 ret = lis3l02dq_spi_write_reg_8(indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100521 LIS3L02DQ_REG_WAKE_UP_CFG_ADDR,
522 &val);
523 if (ret)
524 goto error_ret;
525 control = list_el->refcount ?
526 (control | LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT) :
527 (control & ~LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT);
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100528 ret = lis3l02dq_spi_write_reg_8(indio_dev,
Jonathan Cameronf3736412011-05-18 14:40:52 +0100529 LIS3L02DQ_REG_CTRL_2_ADDR,
530 &control);
531 }
532
533error_ret:
534 mutex_unlock(&indio_dev->mlock);
535 return ret;
536}
Jonathan Cameron66533b42009-08-18 18:06:22 +0100537
538/* Unforunately it appears the interrupt won't clear unless you read from the
539 * src register.
540 */
541static void lis3l02dq_thresh_handler_bh_no_check(struct work_struct *work_s)
542{
Jonathan Cameronf3736412011-05-18 14:40:52 +0100543 struct lis3l02dq_state *st
544 = container_of(work_s,
545 struct lis3l02dq_state, work_thresh);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100546 u8 t;
547
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100548 lis3l02dq_spi_read_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100549 LIS3L02DQ_REG_WAKE_UP_SRC_ADDR,
550 &t);
551
552 if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100553 iio_push_event(st->help.indio_dev, 0,
Jonathan Cameron18e69a92010-10-08 12:14:02 +0100554 IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
555 0,
556 IIO_EV_MOD_Z,
557 IIO_EV_TYPE_THRESH,
558 IIO_EV_DIR_RISING),
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100559 st->thresh_timestamp);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100560
561 if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_LOW)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100562 iio_push_event(st->help.indio_dev, 0,
Jonathan Cameron18e69a92010-10-08 12:14:02 +0100563 IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
564 0,
565 IIO_EV_MOD_Z,
566 IIO_EV_TYPE_THRESH,
567 IIO_EV_DIR_FALLING),
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100568 st->thresh_timestamp);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100569
570 if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_HIGH)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100571 iio_push_event(st->help.indio_dev, 0,
Jonathan Cameron18e69a92010-10-08 12:14:02 +0100572 IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
573 0,
574 IIO_EV_MOD_Y,
575 IIO_EV_TYPE_THRESH,
576 IIO_EV_DIR_RISING),
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100577 st->thresh_timestamp);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100578
579 if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Y_LOW)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100580 iio_push_event(st->help.indio_dev, 0,
Jonathan Cameron18e69a92010-10-08 12:14:02 +0100581 IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
582 0,
583 IIO_EV_MOD_Y,
584 IIO_EV_TYPE_THRESH,
585 IIO_EV_DIR_FALLING),
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100586 st->thresh_timestamp);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100587
588 if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_HIGH)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100589 iio_push_event(st->help.indio_dev, 0,
Jonathan Cameron18e69a92010-10-08 12:14:02 +0100590 IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
591 0,
592 IIO_EV_MOD_X,
593 IIO_EV_TYPE_THRESH,
594 IIO_EV_DIR_RISING),
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100595 st->thresh_timestamp);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100596
597 if (t & LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_X_LOW)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100598 iio_push_event(st->help.indio_dev, 0,
Jonathan Cameron18e69a92010-10-08 12:14:02 +0100599 IIO_MOD_EVENT_CODE(IIO_EV_CLASS_ACCEL,
600 0,
601 IIO_EV_MOD_X,
602 IIO_EV_TYPE_THRESH,
603 IIO_EV_DIR_FALLING),
Jonathan Cameronb98c9e62010-07-29 17:50:47 +0100604 st->thresh_timestamp);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100605 /* reenable the irq */
606 enable_irq(st->us->irq);
607 /* Ack and allow for new interrupts */
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100608 lis3l02dq_spi_read_reg_8(st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100609 LIS3L02DQ_REG_WAKE_UP_ACK_ADDR,
610 &t);
611
612 return;
613}
614
Manuel Stahl51a0a5b2010-08-31 11:32:54 +0200615static IIO_CONST_ATTR_NAME("lis3l02dq");
Jonathan Cameron66533b42009-08-18 18:06:22 +0100616
617static struct attribute *lis3l02dq_attributes[] = {
Jonathan Cameron66533b42009-08-18 18:06:22 +0100618 &iio_dev_attr_sampling_frequency.dev_attr.attr,
Jonathan Cameronf3fb0012010-05-04 14:42:58 +0100619 &iio_const_attr_sampling_frequency_available.dev_attr.attr,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100620 &iio_const_attr_name.dev_attr.attr,
621 NULL
622};
623
624static const struct attribute_group lis3l02dq_attribute_group = {
625 .attrs = lis3l02dq_attributes,
626};
627
628static int __devinit lis3l02dq_probe(struct spi_device *spi)
629{
630 int ret, regdone = 0;
631 struct lis3l02dq_state *st = kzalloc(sizeof *st, GFP_KERNEL);
632 if (!st) {
633 ret = -ENOMEM;
634 goto error_ret;
635 }
Jonathan Camerond0348e52010-06-26 12:54:15 +0100636 INIT_WORK(&st->work_thresh, lis3l02dq_thresh_handler_bh_no_check);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100637 /* this is only used tor removal purposes */
638 spi_set_drvdata(spi, st);
639
640 /* Allocate the comms buffers */
641 st->rx = kzalloc(sizeof(*st->rx)*LIS3L02DQ_MAX_RX, GFP_KERNEL);
642 if (st->rx == NULL) {
643 ret = -ENOMEM;
644 goto error_free_st;
645 }
646 st->tx = kzalloc(sizeof(*st->tx)*LIS3L02DQ_MAX_TX, GFP_KERNEL);
647 if (st->tx == NULL) {
648 ret = -ENOMEM;
649 goto error_free_rx;
650 }
651 st->us = spi;
652 mutex_init(&st->buf_lock);
653 /* setup the industrialio driver allocated elements */
Jonathan Cameron6f7c8ee2011-04-15 18:55:56 +0100654 st->help.indio_dev = iio_allocate_device(0);
Jonathan Cameron73bce122010-07-11 16:39:19 +0100655 if (st->help.indio_dev == NULL) {
Jonathan Cameron66533b42009-08-18 18:06:22 +0100656 ret = -ENOMEM;
657 goto error_free_tx;
658 }
659
Jonathan Cameron73bce122010-07-11 16:39:19 +0100660 st->help.indio_dev->dev.parent = &spi->dev;
661 st->help.indio_dev->num_interrupt_lines = 1;
Jonathan Cameronf3736412011-05-18 14:40:52 +0100662 st->help.indio_dev->channels = lis3l02dq_channels;
663 st->help.indio_dev->num_channels = ARRAY_SIZE(lis3l02dq_channels);
664 st->help.indio_dev->read_raw = &lis3l02dq_read_raw;
665 st->help.indio_dev->read_event_value = &lis3l02dq_read_thresh;
666 st->help.indio_dev->write_event_value = &lis3l02dq_write_thresh;
667 st->help.indio_dev->write_event_config = &lis3l02dq_write_event_config;
668 st->help.indio_dev->read_event_config = &lis3l02dq_read_event_config;
Jonathan Cameron73bce122010-07-11 16:39:19 +0100669 st->help.indio_dev->attrs = &lis3l02dq_attribute_group;
670 st->help.indio_dev->dev_data = (void *)(&st->help);
671 st->help.indio_dev->driver_module = THIS_MODULE;
672 st->help.indio_dev->modes = INDIO_DIRECT_MODE;
Jonathan Cameron66533b42009-08-18 18:06:22 +0100673
Jonathan Cameron73bce122010-07-11 16:39:19 +0100674 ret = lis3l02dq_configure_ring(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100675 if (ret)
676 goto error_free_dev;
677
Jonathan Cameron73bce122010-07-11 16:39:19 +0100678 ret = iio_device_register(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100679 if (ret)
680 goto error_unreg_ring_funcs;
681 regdone = 1;
682
Jonathan Cameronf3736412011-05-18 14:40:52 +0100683 ret = iio_ring_buffer_register_ex(st->help.indio_dev->ring, 0,
684 lis3l02dq_channels,
685 ARRAY_SIZE(lis3l02dq_channels));
Jonathan Cameron66533b42009-08-18 18:06:22 +0100686 if (ret) {
687 printk(KERN_ERR "failed to initialize the ring\n");
688 goto error_unreg_ring_funcs;
689 }
690
691 if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
Jonathan Cameron66533b42009-08-18 18:06:22 +0100692 st->inter = 0;
693 ret = iio_register_interrupt_line(spi->irq,
Jonathan Cameron73bce122010-07-11 16:39:19 +0100694 st->help.indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100695 0,
696 IRQF_TRIGGER_RISING,
697 "lis3l02dq");
698 if (ret)
699 goto error_uninitialize_ring;
700
Jonathan Cameron73bce122010-07-11 16:39:19 +0100701 ret = lis3l02dq_probe_trigger(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100702 if (ret)
703 goto error_unregister_line;
704 }
705
706 /* Get the device into a sane initial state */
707 ret = lis3l02dq_initial_setup(st);
708 if (ret)
709 goto error_remove_trigger;
710 return 0;
711
712error_remove_trigger:
Jonathan Cameron73bce122010-07-11 16:39:19 +0100713 if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED)
714 lis3l02dq_remove_trigger(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100715error_unregister_line:
Jonathan Cameron73bce122010-07-11 16:39:19 +0100716 if (st->help.indio_dev->modes & INDIO_RING_TRIGGERED)
717 iio_unregister_interrupt_line(st->help.indio_dev, 0);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100718error_uninitialize_ring:
Jonathan Cameron73bce122010-07-11 16:39:19 +0100719 iio_ring_buffer_unregister(st->help.indio_dev->ring);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100720error_unreg_ring_funcs:
Jonathan Cameron73bce122010-07-11 16:39:19 +0100721 lis3l02dq_unconfigure_ring(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100722error_free_dev:
723 if (regdone)
Jonathan Cameron73bce122010-07-11 16:39:19 +0100724 iio_device_unregister(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100725 else
Jonathan Cameron73bce122010-07-11 16:39:19 +0100726 iio_free_device(st->help.indio_dev);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100727error_free_tx:
728 kfree(st->tx);
729error_free_rx:
730 kfree(st->rx);
731error_free_st:
732 kfree(st);
733error_ret:
734 return ret;
735}
736
737/* Power down the device */
738static int lis3l02dq_stop_device(struct iio_dev *indio_dev)
739{
740 int ret;
Jonathan Cameron73bce122010-07-11 16:39:19 +0100741 struct iio_sw_ring_helper_state *h
742 = iio_dev_get_devdata(indio_dev);
743 struct lis3l02dq_state *st = lis3l02dq_h_to_s(h);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100744 u8 val = 0;
745
746 mutex_lock(&indio_dev->mlock);
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100747 ret = lis3l02dq_spi_write_reg_8(indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100748 LIS3L02DQ_REG_CTRL_1_ADDR,
749 &val);
750 if (ret) {
751 dev_err(&st->us->dev, "problem with turning device off: ctrl1");
752 goto err_ret;
753 }
754
Jonathan Cameron1b076b52011-05-18 14:40:58 +0100755 ret = lis3l02dq_spi_write_reg_8(indio_dev,
Jonathan Cameron66533b42009-08-18 18:06:22 +0100756 LIS3L02DQ_REG_CTRL_2_ADDR,
757 &val);
758 if (ret)
759 dev_err(&st->us->dev, "problem with turning device off: ctrl2");
760err_ret:
761 mutex_unlock(&indio_dev->mlock);
762 return ret;
763}
764
765/* fixme, confirm ordering in this function */
766static int lis3l02dq_remove(struct spi_device *spi)
767{
768 int ret;
769 struct lis3l02dq_state *st = spi_get_drvdata(spi);
Jonathan Cameron73bce122010-07-11 16:39:19 +0100770 struct iio_dev *indio_dev = st->help.indio_dev;
Jonathan Cameron66533b42009-08-18 18:06:22 +0100771
772 ret = lis3l02dq_stop_device(indio_dev);
773 if (ret)
774 goto err_ret;
775
776 flush_scheduled_work();
777
778 lis3l02dq_remove_trigger(indio_dev);
779 if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
780 iio_unregister_interrupt_line(indio_dev, 0);
781
Jonathan Cameron26620512010-07-11 16:39:14 +0100782 iio_ring_buffer_unregister(indio_dev->ring);
Jonathan Cameron66533b42009-08-18 18:06:22 +0100783 lis3l02dq_unconfigure_ring(indio_dev);
784 iio_device_unregister(indio_dev);
785 kfree(st->tx);
786 kfree(st->rx);
787 kfree(st);
788
789 return 0;
790
791err_ret:
792 return ret;
793}
794
795static struct spi_driver lis3l02dq_driver = {
796 .driver = {
797 .name = "lis3l02dq",
798 .owner = THIS_MODULE,
799 },
800 .probe = lis3l02dq_probe,
801 .remove = __devexit_p(lis3l02dq_remove),
802};
803
804static __init int lis3l02dq_init(void)
805{
806 return spi_register_driver(&lis3l02dq_driver);
807}
808module_init(lis3l02dq_init);
809
810static __exit void lis3l02dq_exit(void)
811{
812 spi_unregister_driver(&lis3l02dq_driver);
813}
814module_exit(lis3l02dq_exit);
815
816MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
817MODULE_DESCRIPTION("ST LIS3L02DQ Accelerometer SPI driver");
818MODULE_LICENSE("GPL v2");