tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / iio / magnetometer / inv_compass / inv_yas53x_ring.c
1 /*
2 * Copyright (C) 2012 Invensense, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 */
14
15 /**
16  *  @addtogroup  DRIVERS
17  *  @brief       Hardware drivers.
18  *
19  *  @{
20  *      @file    inv_yas53x_ring.c
21  *      @brief   Invensense implementation for yas530/yas532/yas533.
22  *      @details This driver currently works for the yas530/yas532/yas533.
23  */
24
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/slab.h>
28 #include <linux/i2c.h>
29 #include <linux/err.h>
30 #include <linux/delay.h>
31 #include <linux/sysfs.h>
32 #include <linux/jiffies.h>
33 #include <linux/irq.h>
34 #include <linux/interrupt.h>
35 #include <linux/kfifo.h>
36 #include <linux/poll.h>
37 #include <linux/miscdevice.h>
38
39 #include "iio.h"
40 #include "kfifo_buf.h"
41 #include "trigger_consumer.h"
42 #include "sysfs.h"
43
44 #include "inv_yas53x_iio.h"
45
46 static s64 get_time_ns(void)
47 {
48         struct timespec ts;
49         ktime_get_ts(&ts);
50
51         return timespec_to_ns(&ts);
52 }
53
54 static int put_scan_to_buf(struct iio_dev *indio_dev, unsigned char *d,
55                                 short *s, int scan_index)
56 {
57         struct iio_buffer *ring = indio_dev->buffer;
58         int st;
59         int i, d_ind;
60
61         d_ind = 0;
62         for (i = 0; i < 3; i++) {
63                 st = iio_scan_mask_query(indio_dev, ring, scan_index + i);
64                 if (st) {
65                         memcpy(&d[d_ind], &s[i], sizeof(s[i]));
66                         d_ind += sizeof(s[i]);
67                 }
68         }
69
70         return d_ind;
71 }
72
73 /**
74  *  inv_read_yas53x_fifo() - Transfer data from FIFO to ring buffer.
75  */
76 void inv_read_yas53x_fifo(struct iio_dev *indio_dev)
77 {
78         struct inv_compass_state *st = iio_priv(indio_dev);
79         struct iio_buffer *ring = indio_dev->buffer;
80         int d_ind;
81         s32 overunderflow;
82         s8 *tmp;
83         s64 tmp_buf[2];
84
85         if (!yas53x_read(st, st->compass_data, &overunderflow)) {
86                 tmp = (u8 *)tmp_buf;
87                 d_ind = put_scan_to_buf(indio_dev, tmp, st->compass_data,
88                                                 INV_YAS53X_SCAN_MAGN_X);
89                 if (ring->scan_timestamp)
90                         tmp_buf[(d_ind + 7) / 8] = get_time_ns();
91                 ring->access->store_to(indio_dev->buffer, tmp, 0);
92
93                 if (overunderflow) {
94                         yas53x_resume(st);
95                         if (!st->overunderflow)
96                                 st->overunderflow = 1;
97                 }
98         }
99 }
100
101 void inv_yas53x_unconfigure_ring(struct iio_dev *indio_dev)
102 {
103         iio_kfifo_free(indio_dev->buffer);
104 };
105
106 static int inv_yas53x_postenable(struct iio_dev *indio_dev)
107 {
108         struct inv_compass_state *st = iio_priv(indio_dev);
109         struct iio_buffer *ring = indio_dev->buffer;
110
111         /* when all the outputs are disabled, even though buffer/enable is on,
112            do nothing */
113         if (!(iio_scan_mask_query(indio_dev, ring, INV_YAS53X_SCAN_MAGN_X) ||
114             iio_scan_mask_query(indio_dev, ring, INV_YAS53X_SCAN_MAGN_Y) ||
115             iio_scan_mask_query(indio_dev, ring, INV_YAS53X_SCAN_MAGN_Z)))
116                 return 0;
117
118         set_yas53x_enable(indio_dev, true);
119         schedule_delayed_work(&st->work,
120                 msecs_to_jiffies(st->delay));
121
122         return 0;
123 }
124
125 static int inv_yas53x_predisable(struct iio_dev *indio_dev)
126 {
127         struct inv_compass_state *st = iio_priv(indio_dev);
128         struct iio_buffer *ring = indio_dev->buffer;
129
130         cancel_delayed_work_sync(&st->work);
131         clear_bit(INV_YAS53X_SCAN_MAGN_X, ring->scan_mask);
132         clear_bit(INV_YAS53X_SCAN_MAGN_Y, ring->scan_mask);
133         clear_bit(INV_YAS53X_SCAN_MAGN_Z, ring->scan_mask);
134
135         return 0;
136 }
137
138 static const struct iio_buffer_setup_ops inv_yas53x_ring_setup_ops = {
139         .preenable = &iio_sw_buffer_preenable,
140         .postenable = &inv_yas53x_postenable,
141         .predisable = &inv_yas53x_predisable,
142 };
143
144 int inv_yas53x_configure_ring(struct iio_dev *indio_dev)
145 {
146         int ret = 0;
147         struct iio_buffer *ring;
148
149         ring = iio_kfifo_allocate(indio_dev);
150         if (!ring) {
151                 ret = -ENOMEM;
152                 return ret;
153         }
154         indio_dev->buffer = ring;
155         /* setup ring buffer */
156         ring->scan_timestamp = true;
157         indio_dev->setup_ops = &inv_yas53x_ring_setup_ops;
158
159         indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
160         return 0;
161 }
162 /**
163  *  @}
164  */
165