Merge branch 'lpc32xx/dts' of git://git.antcom.de/linux-2.6 into next/dt
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / iio / adc / ad7887_ring.c
1 /*
2  * Copyright 2010-2012 Analog Devices Inc.
3  * Copyright (C) 2008 Jonathan Cameron
4  *
5  * Licensed under the GPL-2.
6  *
7  * ad7887_ring.c
8  */
9
10 #include <linux/interrupt.h>
11 #include <linux/kernel.h>
12 #include <linux/slab.h>
13 #include <linux/spi/spi.h>
14
15 #include <linux/iio/iio.h>
16 #include <linux/iio/buffer.h>
17 #include <linux/iio/trigger_consumer.h>
18 #include <linux/iio/triggered_buffer.h>
19
20 #include "ad7887.h"
21
22 /**
23  * ad7887_ring_preenable() setup the parameters of the ring before enabling
24  *
25  * The complex nature of the setting of the nuber of bytes per datum is due
26  * to this driver currently ensuring that the timestamp is stored at an 8
27  * byte boundary.
28  **/
29 static int ad7887_ring_preenable(struct iio_dev *indio_dev)
30 {
31         struct ad7887_state *st = iio_priv(indio_dev);
32         int ret;
33
34         ret = iio_sw_buffer_preenable(indio_dev);
35         if (ret < 0)
36                 return ret;
37
38         /* We know this is a single long so can 'cheat' */
39         switch (*indio_dev->active_scan_mask) {
40         case (1 << 0):
41                 st->ring_msg = &st->msg[AD7887_CH0];
42                 break;
43         case (1 << 1):
44                 st->ring_msg = &st->msg[AD7887_CH1];
45                 /* Dummy read: push CH1 setting down to hardware */
46                 spi_sync(st->spi, st->ring_msg);
47                 break;
48         case ((1 << 1) | (1 << 0)):
49                 st->ring_msg = &st->msg[AD7887_CH0_CH1];
50                 break;
51         }
52
53         return 0;
54 }
55
56 static int ad7887_ring_postdisable(struct iio_dev *indio_dev)
57 {
58         struct ad7887_state *st = iio_priv(indio_dev);
59
60         /* dummy read: restore default CH0 settin */
61         return spi_sync(st->spi, &st->msg[AD7887_CH0]);
62 }
63
64 /**
65  * ad7887_trigger_handler() bh of trigger launched polling to ring buffer
66  *
67  * Currently there is no option in this driver to disable the saving of
68  * timestamps within the ring.
69  **/
70 static irqreturn_t ad7887_trigger_handler(int irq, void *p)
71 {
72         struct iio_poll_func *pf = p;
73         struct iio_dev *indio_dev = pf->indio_dev;
74         struct ad7887_state *st = iio_priv(indio_dev);
75         s64 time_ns;
76         __u8 *buf;
77         int b_sent;
78
79         unsigned int bytes = bitmap_weight(indio_dev->active_scan_mask,
80                                            indio_dev->masklength) *
81                 st->chip_info->channel[0].scan_type.storagebits / 8;
82
83         buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
84         if (buf == NULL)
85                 goto done;
86
87         b_sent = spi_sync(st->spi, st->ring_msg);
88         if (b_sent)
89                 goto done;
90
91         time_ns = iio_get_time_ns();
92
93         memcpy(buf, st->data, bytes);
94         if (indio_dev->scan_timestamp)
95                 memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
96                        &time_ns, sizeof(time_ns));
97
98         indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
99 done:
100         kfree(buf);
101         iio_trigger_notify_done(indio_dev->trig);
102
103         return IRQ_HANDLED;
104 }
105
106 static const struct iio_buffer_setup_ops ad7887_ring_setup_ops = {
107         .preenable = &ad7887_ring_preenable,
108         .postenable = &iio_triggered_buffer_postenable,
109         .predisable = &iio_triggered_buffer_predisable,
110         .postdisable = &ad7887_ring_postdisable,
111 };
112
113 int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
114 {
115         return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
116                         &ad7887_trigger_handler, &ad7887_ring_setup_ops);
117 }
118
119 void ad7887_ring_cleanup(struct iio_dev *indio_dev)
120 {
121         iio_triggered_buffer_cleanup(indio_dev);
122 }