1
2
3
4
5
6#include <linux/module.h>
7#include <linux/slab.h>
8#include <linux/err.h>
9#include <linux/delay.h>
10#include <linux/sysfs.h>
11#include <linux/jiffies.h>
12#include <linux/irq.h>
13#include <linux/interrupt.h>
14#include <linux/poll.h>
15#include <linux/math64.h>
16#include <asm/unaligned.h>
17#include "inv_mpu_iio.h"
18
19
20
21
22
23
24
25
26
27
28
29static void inv_mpu6050_update_period(struct inv_mpu6050_state *st,
30 s64 timestamp, size_t nb)
31{
32
33 const s64 period_min =
34 (NSEC_PER_MSEC * (100 - INV_MPU6050_TS_PERIOD_JITTER)) / 100;
35 const s64 period_max =
36 (NSEC_PER_MSEC * (100 + INV_MPU6050_TS_PERIOD_JITTER)) / 100;
37 const s32 divider = INV_MPU6050_FREQ_DIVIDER(st);
38 s64 delta, interval;
39 bool use_it_timestamp = false;
40
41 if (st->it_timestamp == 0) {
42
43 use_it_timestamp = true;
44 } else if (nb == 1) {
45
46
47
48
49
50
51
52 delta = div_s64(timestamp - st->it_timestamp, divider);
53 if (delta > period_min && delta < period_max) {
54
55 st->chip_period = (st->chip_period + delta) / 2;
56 use_it_timestamp = true;
57 }
58 }
59
60 if (use_it_timestamp) {
61
62
63
64
65
66 interval = (nb - 1) * st->chip_period * divider;
67 st->data_timestamp = timestamp - interval;
68 }
69
70
71 st->it_timestamp = timestamp;
72}
73
74
75
76
77
78
79
80
81
82static s64 inv_mpu6050_get_timestamp(struct inv_mpu6050_state *st)
83{
84 s64 ts;
85
86
87 ts = st->data_timestamp;
88 st->data_timestamp += st->chip_period * INV_MPU6050_FREQ_DIVIDER(st);
89
90 return ts;
91}
92
93static int inv_reset_fifo(struct iio_dev *indio_dev)
94{
95 int result;
96 struct inv_mpu6050_state *st = iio_priv(indio_dev);
97
98
99 inv_mpu6050_prepare_fifo(st, false);
100 result = inv_mpu6050_prepare_fifo(st, true);
101 if (result)
102 goto reset_fifo_fail;
103
104 return 0;
105
106reset_fifo_fail:
107 dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result);
108 result = regmap_write(st->map, st->reg->int_enable,
109 INV_MPU6050_BIT_DATA_RDY_EN);
110
111 return result;
112}
113
114
115
116
117irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
118{
119 struct iio_poll_func *pf = p;
120 struct iio_dev *indio_dev = pf->indio_dev;
121 struct inv_mpu6050_state *st = iio_priv(indio_dev);
122 size_t bytes_per_datum;
123 int result;
124 u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
125 u16 fifo_count;
126 s64 timestamp;
127 int int_status;
128 size_t i, nb;
129
130 mutex_lock(&st->lock);
131
132
133 result = regmap_read(st->map, st->reg->int_status, &int_status);
134 if (result) {
135 dev_err(regmap_get_device(st->map),
136 "failed to ack interrupt\n");
137 goto flush_fifo;
138 }
139 if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT))
140 goto end_session;
141
142 if (!(st->chip_config.accl_fifo_enable |
143 st->chip_config.gyro_fifo_enable |
144 st->chip_config.magn_fifo_enable))
145 goto end_session;
146 bytes_per_datum = 0;
147 if (st->chip_config.accl_fifo_enable)
148 bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
149
150 if (st->chip_config.gyro_fifo_enable)
151 bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
152
153 if (st->chip_config.temp_fifo_enable)
154 bytes_per_datum += INV_MPU6050_BYTES_PER_TEMP_SENSOR;
155
156 if (st->chip_config.magn_fifo_enable)
157 bytes_per_datum += INV_MPU9X50_BYTES_MAGN;
158
159
160
161
162
163 result = regmap_bulk_read(st->map, st->reg->fifo_count_h, data,
164 INV_MPU6050_FIFO_COUNT_BYTE);
165 if (result)
166 goto end_session;
167 fifo_count = get_unaligned_be16(&data[0]);
168
169
170
171
172
173
174 nb = 3 * bytes_per_datum;
175 if (fifo_count >= st->hw->fifo_size - nb) {
176 dev_warn(regmap_get_device(st->map), "fifo overflow reset\n");
177 goto flush_fifo;
178 }
179
180
181 nb = fifo_count / bytes_per_datum;
182 inv_mpu6050_update_period(st, pf->timestamp, nb);
183 for (i = 0; i < nb; ++i) {
184 result = regmap_bulk_read(st->map, st->reg->fifo_r_w,
185 data, bytes_per_datum);
186 if (result)
187 goto flush_fifo;
188
189 if (st->skip_samples) {
190 st->skip_samples--;
191 continue;
192 }
193 timestamp = inv_mpu6050_get_timestamp(st);
194 iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
195 }
196
197end_session:
198 mutex_unlock(&st->lock);
199 iio_trigger_notify_done(indio_dev->trig);
200
201 return IRQ_HANDLED;
202
203flush_fifo:
204
205 inv_reset_fifo(indio_dev);
206 mutex_unlock(&st->lock);
207 iio_trigger_notify_done(indio_dev->trig);
208
209 return IRQ_HANDLED;
210}
211