aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGe Gao <ggao@invensense.com>2013-02-01 19:26:00 -0500
committerJonathan Cameron <jic23@kernel.org>2013-02-10 12:42:43 -0500
commit09a642b78523e9f4c5970c806ad218aa3de31551 (patch)
treed233f7f645b66e8a02ff1128fcc6673a7183b047
parent8ce4a56a52bf566659768a9e46e759e7cd5f33d9 (diff)
Invensense MPU6050 Device Driver.
This the basic functional Invensense MPU6050 Device driver. Signed-off-by: Ge Gao <ggao@invensense.com> Reviewed-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio-mpu605013
-rw-r--r--drivers/iio/imu/Kconfig2
-rw-r--r--drivers/iio/imu/Makefile2
-rw-r--r--drivers/iio/imu/inv_mpu6050/Kconfig13
-rw-r--r--drivers/iio/imu/inv_mpu6050/Makefile6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c795
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h246
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c196
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c155
-rw-r--r--include/linux/platform_data/invensense_mpu6050.h31
10 files changed, 1459 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-mpu6050 b/Documentation/ABI/testing/sysfs-bus-iio-mpu6050
new file mode 100644
index 000000000000..cb53737aacbf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-mpu6050
@@ -0,0 +1,13 @@
1What: /sys/bus/iio/devices/iio:deviceX/in_gyro_matrix
2What: /sys/bus/iio/devices/iio:deviceX/in_accel_matrix
3What: /sys/bus/iio/devices/iio:deviceX/in_magn_matrix
4KernelVersion: 3.4.0
5Contact: linux-iio@vger.kernel.org
6Description:
7 This is mounting matrix for motion sensors. Mounting matrix
8 is a 3x3 unitary matrix. A typical mounting matrix would look like
9 [0, 1, 0; 1, 0, 0; 0, 0, -1]. Using this information, it would be
10 easy to tell the relative positions among sensors as well as their
11 positions relative to the board that holds these sensors. Identity matrix
12 [1, 0, 0; 0, 1, 0; 0, 0, 1] means sensor chip and device are perfectly
13 aligned with each other. All axes are exactly the same.
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 47f66ed9c4ef..4f40a10cb74f 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -36,3 +36,5 @@ config IIO_ADIS_LIB_BUFFER
36 help 36 help
37 A set of buffer helper functions for the Analog Devices ADIS* device 37 A set of buffer helper functions for the Analog Devices ADIS* device
38 family. 38 family.
39
40source "drivers/iio/imu/inv_mpu6050/Kconfig"
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 019b717c5ff1..f2f56ceaed26 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -11,3 +11,5 @@ adis_lib-y += adis.o
11adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o 11adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_trigger.o
12adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o 12adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
13obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o 13obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
14
15obj-y += inv_mpu6050/
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
new file mode 100644
index 000000000000..b5cfa3a354cf
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -0,0 +1,13 @@
1#
2# inv-mpu6050 drivers for Invensense MPU devices and combos
3#
4
5config INV_MPU6050_IIO
6 tristate "Invensense MPU6050 devices"
7 depends on I2C && SYSFS
8 select IIO_TRIGGERED_BUFFER
9 help
10 This driver supports the Invensense MPU6050 devices.
11 It is a gyroscope/accelerometer combo device.
12 This driver can be built as a module. The module will be called
13 inv-mpu6050.
diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile
new file mode 100644
index 000000000000..3a677c778afb
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for Invensense MPU6050 device.
3#
4
5obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o
6inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
new file mode 100644
index 000000000000..37ca05b47e4b
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -0,0 +1,795 @@
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#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/i2c.h>
18#include <linux/err.h>
19#include <linux/delay.h>
20#include <linux/sysfs.h>
21#include <linux/jiffies.h>
22#include <linux/irq.h>
23#include <linux/interrupt.h>
24#include <linux/kfifo.h>
25#include <linux/spinlock.h>
26#include "inv_mpu_iio.h"
27
28/*
29 * this is the gyro scale translated from dynamic range plus/minus
30 * {250, 500, 1000, 2000} to rad/s
31 */
32static const int gyro_scale_6050[] = {133090, 266181, 532362, 1064724};
33
34/*
35 * this is the accel scale translated from dynamic range plus/minus
36 * {2, 4, 8, 16} to m/s^2
37 */
38static const int accel_scale[] = {598, 1196, 2392, 4785};
39
40static const struct inv_mpu6050_reg_map reg_set_6050 = {
41 .sample_rate_div = INV_MPU6050_REG_SAMPLE_RATE_DIV,
42 .lpf = INV_MPU6050_REG_CONFIG,
43 .user_ctrl = INV_MPU6050_REG_USER_CTRL,
44 .fifo_en = INV_MPU6050_REG_FIFO_EN,
45 .gyro_config = INV_MPU6050_REG_GYRO_CONFIG,
46 .accl_config = INV_MPU6050_REG_ACCEL_CONFIG,
47 .fifo_count_h = INV_MPU6050_REG_FIFO_COUNT_H,
48 .fifo_r_w = INV_MPU6050_REG_FIFO_R_W,
49 .raw_gyro = INV_MPU6050_REG_RAW_GYRO,
50 .raw_accl = INV_MPU6050_REG_RAW_ACCEL,
51 .temperature = INV_MPU6050_REG_TEMPERATURE,
52 .int_enable = INV_MPU6050_REG_INT_ENABLE,
53 .pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
54 .pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
55};
56
57static const struct inv_mpu6050_chip_config chip_config_6050 = {
58 .fsr = INV_MPU6050_FSR_2000DPS,
59 .lpf = INV_MPU6050_FILTER_20HZ,
60 .fifo_rate = INV_MPU6050_INIT_FIFO_RATE,
61 .gyro_fifo_enable = false,
62 .accl_fifo_enable = false,
63 .accl_fs = INV_MPU6050_FS_02G,
64};
65
66static const struct inv_mpu6050_hw hw_info[INV_NUM_PARTS] = {
67 {
68 .num_reg = 117,
69 .name = "MPU6050",
70 .reg = &reg_set_6050,
71 .config = &chip_config_6050,
72 },
73};
74
75int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d)
76{
77 return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d);
78}
79
80int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
81{
82 u8 d, mgmt_1;
83 int result;
84
85 /* switch clock needs to be careful. Only when gyro is on, can
86 clock source be switched to gyro. Otherwise, it must be set to
87 internal clock */
88 if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
89 result = i2c_smbus_read_i2c_block_data(st->client,
90 st->reg->pwr_mgmt_1, 1, &mgmt_1);
91 if (result != 1)
92 return result;
93
94 mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK;
95 }
96
97 if ((INV_MPU6050_BIT_PWR_GYRO_STBY == mask) && (!en)) {
98 /* turning off gyro requires switch to internal clock first.
99 Then turn off gyro engine */
100 mgmt_1 |= INV_CLK_INTERNAL;
101 result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, mgmt_1);
102 if (result)
103 return result;
104 }
105
106 result = i2c_smbus_read_i2c_block_data(st->client,
107 st->reg->pwr_mgmt_2, 1, &d);
108 if (result != 1)
109 return result;
110 if (en)
111 d &= ~mask;
112 else
113 d |= mask;
114 result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_2, d);
115 if (result)
116 return result;
117
118 if (en) {
119 /* Wait for output stablize */
120 msleep(INV_MPU6050_TEMP_UP_TIME);
121 if (INV_MPU6050_BIT_PWR_GYRO_STBY == mask) {
122 /* switch internal clock to PLL */
123 mgmt_1 |= INV_CLK_PLL;
124 result = inv_mpu6050_write_reg(st,
125 st->reg->pwr_mgmt_1, mgmt_1);
126 if (result)
127 return result;
128 }
129 }
130
131 return 0;
132}
133
134int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
135{
136 int result;
137
138 if (power_on)
139 result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0);
140 else
141 result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
142 INV_MPU6050_BIT_SLEEP);
143 if (result)
144 return result;
145
146 if (power_on)
147 msleep(INV_MPU6050_REG_UP_TIME);
148
149 return 0;
150}
151
152/**
153 * inv_mpu6050_init_config() - Initialize hardware, disable FIFO.
154 *
155 * Initial configuration:
156 * FSR: ± 2000DPS
157 * DLPF: 20Hz
158 * FIFO rate: 50Hz
159 * Clock source: Gyro PLL
160 */
161static int inv_mpu6050_init_config(struct iio_dev *indio_dev)
162{
163 int result;
164 u8 d;
165 struct inv_mpu6050_state *st = iio_priv(indio_dev);
166
167 result = inv_mpu6050_set_power_itg(st, true);
168 if (result)
169 return result;
170 d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
171 result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
172 if (result)
173 return result;
174
175 d = INV_MPU6050_FILTER_20HZ;
176 result = inv_mpu6050_write_reg(st, st->reg->lpf, d);
177 if (result)
178 return result;
179
180 d = INV_MPU6050_ONE_K_HZ / INV_MPU6050_INIT_FIFO_RATE - 1;
181 result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d);
182 if (result)
183 return result;
184
185 d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
186 result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
187 if (result)
188 return result;
189
190 memcpy(&st->chip_config, hw_info[st->chip_type].config,
191 sizeof(struct inv_mpu6050_chip_config));
192 result = inv_mpu6050_set_power_itg(st, false);
193
194 return result;
195}
196
197static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg,
198 int axis, int *val)
199{
200 int ind, result;
201 __be16 d;
202
203 ind = (axis - IIO_MOD_X) * 2;
204 result = i2c_smbus_read_i2c_block_data(st->client, reg + ind, 2,
205 (u8 *)&d);
206 if (result != 2)
207 return -EINVAL;
208 *val = (short)be16_to_cpup(&d);
209
210 return IIO_VAL_INT;
211}
212
213static int inv_mpu6050_read_raw(struct iio_dev *indio_dev,
214 struct iio_chan_spec const *chan,
215 int *val,
216 int *val2,
217 long mask) {
218 struct inv_mpu6050_state *st = iio_priv(indio_dev);
219
220 switch (mask) {
221 case IIO_CHAN_INFO_RAW:
222 {
223 int ret, result;
224
225 ret = IIO_VAL_INT;
226 result = 0;
227 mutex_lock(&indio_dev->mlock);
228 if (!st->chip_config.enable) {
229 result = inv_mpu6050_set_power_itg(st, true);
230 if (result)
231 goto error_read_raw;
232 }
233 /* when enable is on, power is already on */
234 switch (chan->type) {
235 case IIO_ANGL_VEL:
236 if (!st->chip_config.gyro_fifo_enable ||
237 !st->chip_config.enable) {
238 result = inv_mpu6050_switch_engine(st, true,
239 INV_MPU6050_BIT_PWR_GYRO_STBY);
240 if (result)
241 goto error_read_raw;
242 }
243 ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro,
244 chan->channel2, val);
245 if (!st->chip_config.gyro_fifo_enable ||
246 !st->chip_config.enable) {
247 result = inv_mpu6050_switch_engine(st, false,
248 INV_MPU6050_BIT_PWR_GYRO_STBY);
249 if (result)
250 goto error_read_raw;
251 }
252 break;
253 case IIO_ACCEL:
254 if (!st->chip_config.accl_fifo_enable ||
255 !st->chip_config.enable) {
256 result = inv_mpu6050_switch_engine(st, true,
257 INV_MPU6050_BIT_PWR_ACCL_STBY);
258 if (result)
259 goto error_read_raw;
260 }
261 ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl,
262 chan->channel2, val);
263 if (!st->chip_config.accl_fifo_enable ||
264 !st->chip_config.enable) {
265 result = inv_mpu6050_switch_engine(st, false,
266 INV_MPU6050_BIT_PWR_ACCL_STBY);
267 if (result)
268 goto error_read_raw;
269 }
270 break;
271 case IIO_TEMP:
272 /* wait for stablization */
273 msleep(INV_MPU6050_SENSOR_UP_TIME);
274 inv_mpu6050_sensor_show(st, st->reg->temperature,
275 IIO_MOD_X, val);
276 break;
277 default:
278 ret = -EINVAL;
279 break;
280 }
281error_read_raw:
282 if (!st->chip_config.enable)
283 result |= inv_mpu6050_set_power_itg(st, false);
284 mutex_unlock(&indio_dev->mlock);
285 if (result)
286 return result;
287
288 return ret;
289 }
290 case IIO_CHAN_INFO_SCALE:
291 switch (chan->type) {
292 case IIO_ANGL_VEL:
293 *val = 0;
294 *val2 = gyro_scale_6050[st->chip_config.fsr];
295
296 return IIO_VAL_INT_PLUS_NANO;
297 case IIO_ACCEL:
298 *val = 0;
299 *val2 = accel_scale[st->chip_config.accl_fs];
300
301 return IIO_VAL_INT_PLUS_MICRO;
302 case IIO_TEMP:
303 *val = 0;
304 *val2 = INV_MPU6050_TEMP_SCALE;
305
306 return IIO_VAL_INT_PLUS_MICRO;
307 default:
308 return -EINVAL;
309 }
310 case IIO_CHAN_INFO_OFFSET:
311 switch (chan->type) {
312 case IIO_TEMP:
313 *val = INV_MPU6050_TEMP_OFFSET;
314
315 return IIO_VAL_INT;
316 default:
317 return -EINVAL;
318 }
319 default:
320 return -EINVAL;
321 }
322}
323
324static int inv_mpu6050_write_fsr(struct inv_mpu6050_state *st, int fsr)
325{
326 int result;
327 u8 d;
328
329 if (fsr < 0 || fsr > INV_MPU6050_MAX_GYRO_FS_PARAM)
330 return -EINVAL;
331 if (fsr == st->chip_config.fsr)
332 return 0;
333
334 d = (fsr << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT);
335 result = inv_mpu6050_write_reg(st, st->reg->gyro_config, d);
336 if (result)
337 return result;
338 st->chip_config.fsr = fsr;
339
340 return 0;
341}
342
343static int inv_mpu6050_write_accel_fs(struct inv_mpu6050_state *st, int fs)
344{
345 int result;
346 u8 d;
347
348 if (fs < 0 || fs > INV_MPU6050_MAX_ACCL_FS_PARAM)
349 return -EINVAL;
350 if (fs == st->chip_config.accl_fs)
351 return 0;
352
353 d = (fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT);
354 result = inv_mpu6050_write_reg(st, st->reg->accl_config, d);
355 if (result)
356 return result;
357 st->chip_config.accl_fs = fs;
358
359 return 0;
360}
361
362static int inv_mpu6050_write_raw(struct iio_dev *indio_dev,
363 struct iio_chan_spec const *chan,
364 int val,
365 int val2,
366 long mask) {
367 struct inv_mpu6050_state *st = iio_priv(indio_dev);
368 int result;
369
370 mutex_lock(&indio_dev->mlock);
371 /* we should only update scale when the chip is disabled, i.e.,
372 not running */
373 if (st->chip_config.enable) {
374 result = -EBUSY;
375 goto error_write_raw;
376 }
377 result = inv_mpu6050_set_power_itg(st, true);
378 if (result)
379 goto error_write_raw;
380
381 switch (mask) {
382 case IIO_CHAN_INFO_SCALE:
383 switch (chan->type) {
384 case IIO_ANGL_VEL:
385 result = inv_mpu6050_write_fsr(st, val);
386 break;
387 case IIO_ACCEL:
388 result = inv_mpu6050_write_accel_fs(st, val);
389 break;
390 default:
391 result = -EINVAL;
392 break;
393 }
394 break;
395 default:
396 result = -EINVAL;
397 break;
398 }
399
400error_write_raw:
401 result |= inv_mpu6050_set_power_itg(st, false);
402 mutex_unlock(&indio_dev->mlock);
403
404 return result;
405}
406
407/**
408 * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate.
409 *
410 * Based on the Nyquist principle, the sampling rate must
411 * exceed twice of the bandwidth of the signal, or there
412 * would be alising. This function basically search for the
413 * correct low pass parameters based on the fifo rate, e.g,
414 * sampling frequency.
415 */
416static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate)
417{
418 const int hz[] = {188, 98, 42, 20, 10, 5};
419 const int d[] = {INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ,
420 INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ,
421 INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ};
422 int i, h, result;
423 u8 data;
424
425 h = (rate >> 1);
426 i = 0;
427 while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1))
428 i++;
429 data = d[i];
430 result = inv_mpu6050_write_reg(st, st->reg->lpf, data);
431 if (result)
432 return result;
433 st->chip_config.lpf = data;
434
435 return 0;
436}
437
438/**
439 * inv_mpu6050_fifo_rate_store() - Set fifo rate.
440 */
441static ssize_t inv_mpu6050_fifo_rate_store(struct device *dev,
442 struct device_attribute *attr, const char *buf, size_t count)
443{
444 s32 fifo_rate;
445 u8 d;
446 int result;
447 struct iio_dev *indio_dev = dev_to_iio_dev(dev);
448 struct inv_mpu6050_state *st = iio_priv(indio_dev);
449
450 if (kstrtoint(buf, 10, &fifo_rate))
451 return -EINVAL;
452 if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE ||
453 fifo_rate > INV_MPU6050_MAX_FIFO_RATE)
454 return -EINVAL;
455 if (fifo_rate == st->chip_config.fifo_rate)
456 return count;
457
458 mutex_lock(&indio_dev->mlock);
459 if (st->chip_config.enable) {
460 result = -EBUSY;
461 goto fifo_rate_fail;
462 }
463 result = inv_mpu6050_set_power_itg(st, true);
464 if (result)
465 goto fifo_rate_fail;
466
467 d = INV_MPU6050_ONE_K_HZ / fifo_rate - 1;
468 result = inv_mpu6050_write_reg(st, st->reg->sample_rate_div, d);
469 if (result)
470 goto fifo_rate_fail;
471 st->chip_config.fifo_rate = fifo_rate;
472
473 result = inv_mpu6050_set_lpf(st, fifo_rate);
474 if (result)
475 goto fifo_rate_fail;
476
477fifo_rate_fail:
478 result |= inv_mpu6050_set_power_itg(st, false);
479 mutex_unlock(&indio_dev->mlock);
480 if (result)
481 return result;
482
483 return count;
484}
485
486/**
487 * inv_fifo_rate_show() - Get the current sampling rate.
488 */
489static ssize_t inv_fifo_rate_show(struct device *dev,
490 struct device_attribute *attr, char *buf)
491{
492 struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
493
494 return sprintf(buf, "%d\n", st->chip_config.fifo_rate);
495}
496
497/**
498 * inv_attr_show() - calling this function will show current
499 * parameters.
500 */
501static ssize_t inv_attr_show(struct device *dev,
502 struct device_attribute *attr, char *buf)
503{
504 struct inv_mpu6050_state *st = iio_priv(dev_to_iio_dev(dev));
505 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
506 s8 *m;
507
508 switch (this_attr->address) {
509 /* In MPU6050, the two matrix are the same because gyro and accel
510 are integrated in one chip */
511 case ATTR_GYRO_MATRIX:
512 case ATTR_ACCL_MATRIX:
513 m = st->plat_data.orientation;
514
515 return sprintf(buf, "%d, %d, %d; %d, %d, %d; %d, %d, %d\n",
516 m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]);
517 default:
518 return -EINVAL;
519 }
520}
521
522/**
523 * inv_mpu6050_validate_trigger() - validate_trigger callback for invensense
524 * MPU6050 device.
525 * @indio_dev: The IIO device
526 * @trig: The new trigger
527 *
528 * Returns: 0 if the 'trig' matches the trigger registered by the MPU6050
529 * device, -EINVAL otherwise.
530 */
531static int inv_mpu6050_validate_trigger(struct iio_dev *indio_dev,
532 struct iio_trigger *trig)
533{
534 struct inv_mpu6050_state *st = iio_priv(indio_dev);
535
536 if (st->trig != trig)
537 return -EINVAL;
538
539 return 0;
540}
541
542#define INV_MPU6050_CHAN(_type, _channel2, _index) \
543 { \
544 .type = _type, \
545 .modified = 1, \
546 .channel2 = _channel2, \
547 .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT \
548 | IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
549 .scan_index = _index, \
550 .scan_type = { \
551 .sign = 's', \
552 .realbits = 16, \
553 .storagebits = 16, \
554 .shift = 0 , \
555 .endianness = IIO_BE, \
556 }, \
557 }
558
559static const struct iio_chan_spec inv_mpu_channels[] = {
560 IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP),
561 /*
562 * Note that temperature should only be via polled reading only,
563 * not the final scan elements output.
564 */
565 {
566 .type = IIO_TEMP,
567 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT
568 | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT
569 | IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
570 .scan_index = -1,
571 },
572 INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X),
573 INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y),
574 INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z),
575
576 INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X),
577 INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y),
578 INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z),
579};
580
581/* constant IIO attribute */
582static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("10 20 50 100 200 500");
583static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, inv_fifo_rate_show,
584 inv_mpu6050_fifo_rate_store);
585static IIO_DEVICE_ATTR(in_gyro_matrix, S_IRUGO, inv_attr_show, NULL,
586 ATTR_GYRO_MATRIX);
587static IIO_DEVICE_ATTR(in_accel_matrix, S_IRUGO, inv_attr_show, NULL,
588 ATTR_ACCL_MATRIX);
589
590static struct attribute *inv_attributes[] = {
591 &iio_dev_attr_in_gyro_matrix.dev_attr.attr,
592 &iio_dev_attr_in_accel_matrix.dev_attr.attr,
593 &iio_dev_attr_sampling_frequency.dev_attr.attr,
594 &iio_const_attr_sampling_frequency_available.dev_attr.attr,
595 NULL,
596};
597
598static const struct attribute_group inv_attribute_group = {
599 .attrs = inv_attributes
600};
601
602static const struct iio_info mpu_info = {
603 .driver_module = THIS_MODULE,
604 .read_raw = &inv_mpu6050_read_raw,
605 .write_raw = &inv_mpu6050_write_raw,
606 .attrs = &inv_attribute_group,
607 .validate_trigger = inv_mpu6050_validate_trigger,
608};
609
610/**
611 * inv_check_and_setup_chip() - check and setup chip.
612 */
613static int inv_check_and_setup_chip(struct inv_mpu6050_state *st,
614 const struct i2c_device_id *id)
615{
616 int result;
617
618 st->chip_type = INV_MPU6050;
619 st->hw = &hw_info[st->chip_type];
620 st->reg = hw_info[st->chip_type].reg;
621
622 /* reset to make sure previous state are not there */
623 result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
624 INV_MPU6050_BIT_H_RESET);
625 if (result)
626 return result;
627 msleep(INV_MPU6050_POWER_UP_TIME);
628 /* toggle power state. After reset, the sleep bit could be on
629 or off depending on the OTP settings. Toggling power would
630 make it in a definite state as well as making the hardware
631 state align with the software state */
632 result = inv_mpu6050_set_power_itg(st, false);
633 if (result)
634 return result;
635 result = inv_mpu6050_set_power_itg(st, true);
636 if (result)
637 return result;
638
639 result = inv_mpu6050_switch_engine(st, false,
640 INV_MPU6050_BIT_PWR_ACCL_STBY);
641 if (result)
642 return result;
643 result = inv_mpu6050_switch_engine(st, false,
644 INV_MPU6050_BIT_PWR_GYRO_STBY);
645 if (result)
646 return result;
647
648 return 0;
649}
650
651/**
652 * inv_mpu_probe() - probe function.
653 * @client: i2c client.
654 * @id: i2c device id.
655 *
656 * Returns 0 on success, a negative error code otherwise.
657 */
658static int inv_mpu_probe(struct i2c_client *client,
659 const struct i2c_device_id *id)
660{
661 struct inv_mpu6050_state *st;
662 struct iio_dev *indio_dev;
663 int result;
664
665 if (!i2c_check_functionality(client->adapter,
666 I2C_FUNC_SMBUS_READ_I2C_BLOCK |
667 I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
668 result = -ENOSYS;
669 goto out_no_free;
670 }
671 indio_dev = iio_device_alloc(sizeof(*st));
672 if (indio_dev == NULL) {
673 result = -ENOMEM;
674 goto out_no_free;
675 }
676 st = iio_priv(indio_dev);
677 st->client = client;
678 st->plat_data = *(struct inv_mpu6050_platform_data
679 *)dev_get_platdata(&client->dev);
680 /* power is turned on inside check chip type*/
681 result = inv_check_and_setup_chip(st, id);
682 if (result)
683 goto out_free;
684
685 result = inv_mpu6050_init_config(indio_dev);
686 if (result) {
687 dev_err(&client->dev,
688 "Could not initialize device.\n");
689 goto out_free;
690 }
691
692 i2c_set_clientdata(client, indio_dev);
693 indio_dev->dev.parent = &client->dev;
694 indio_dev->name = id->name;
695 indio_dev->channels = inv_mpu_channels;
696 indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
697
698 indio_dev->info = &mpu_info;
699 indio_dev->modes = INDIO_BUFFER_TRIGGERED;
700
701 result = iio_triggered_buffer_setup(indio_dev,
702 inv_mpu6050_irq_handler,
703 inv_mpu6050_read_fifo,
704 NULL);
705 if (result) {
706 dev_err(&st->client->dev, "configure buffer fail %d\n",
707 result);
708 goto out_free;
709 }
710 result = inv_mpu6050_probe_trigger(indio_dev);
711 if (result) {
712 dev_err(&st->client->dev, "trigger probe fail %d\n", result);
713 goto out_unreg_ring;
714 }
715
716 INIT_KFIFO(st->timestamps);
717 spin_lock_init(&st->time_stamp_lock);
718 result = iio_device_register(indio_dev);
719 if (result) {
720 dev_err(&st->client->dev, "IIO register fail %d\n", result);
721 goto out_remove_trigger;
722 }
723
724 return 0;
725
726out_remove_trigger:
727 inv_mpu6050_remove_trigger(st);
728out_unreg_ring:
729 iio_triggered_buffer_cleanup(indio_dev);
730out_free:
731 iio_device_free(indio_dev);
732out_no_free:
733
734 return result;
735}
736
737static int inv_mpu_remove(struct i2c_client *client)
738{
739 struct iio_dev *indio_dev = i2c_get_clientdata(client);
740 struct inv_mpu6050_state *st = iio_priv(indio_dev);
741
742 iio_device_unregister(indio_dev);
743 inv_mpu6050_remove_trigger(st);
744 iio_triggered_buffer_cleanup(indio_dev);
745 iio_device_free(indio_dev);
746
747 return 0;
748}
749#ifdef CONFIG_PM_SLEEP
750
751static int inv_mpu_resume(struct device *dev)
752{
753 return inv_mpu6050_set_power_itg(
754 iio_priv(i2c_get_clientdata(to_i2c_client(dev))), true);
755}
756
757static int inv_mpu_suspend(struct device *dev)
758{
759 return inv_mpu6050_set_power_itg(
760 iio_priv(i2c_get_clientdata(to_i2c_client(dev))), false);
761}
762static SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume);
763
764#define INV_MPU6050_PMOPS (&inv_mpu_pmops)
765#else
766#define INV_MPU6050_PMOPS NULL
767#endif /* CONFIG_PM_SLEEP */
768
769/*
770 * device id table is used to identify what device can be
771 * supported by this driver
772 */
773static const struct i2c_device_id inv_mpu_id[] = {
774 {"mpu6050", INV_MPU6050},
775 {}
776};
777
778MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
779
780static struct i2c_driver inv_mpu_driver = {
781 .probe = inv_mpu_probe,
782 .remove = inv_mpu_remove,
783 .id_table = inv_mpu_id,
784 .driver = {
785 .owner = THIS_MODULE,
786 .name = "inv-mpu6050",
787 .pm = INV_MPU6050_PMOPS,
788 },
789};
790
791module_i2c_driver(inv_mpu_driver);
792
793MODULE_AUTHOR("Invensense Corporation");
794MODULE_DESCRIPTION("Invensense device MPU6050 driver");
795MODULE_LICENSE("GPL");
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
new file mode 100644
index 000000000000..f38395529a44
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -0,0 +1,246 @@
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#include <linux/i2c.h>
14#include <linux/kfifo.h>
15#include <linux/spinlock.h>
16#include <linux/iio/iio.h>
17#include <linux/iio/buffer.h>
18#include <linux/iio/sysfs.h>
19#include <linux/iio/kfifo_buf.h>
20#include <linux/iio/trigger.h>
21#include <linux/iio/triggered_buffer.h>
22#include <linux/iio/trigger_consumer.h>
23#include <linux/platform_data/invensense_mpu6050.h>
24
25/**
26 * struct inv_mpu6050_reg_map - Notable registers.
27 * @sample_rate_div: Divider applied to gyro output rate.
28 * @lpf: Configures internal low pass filter.
29 * @user_ctrl: Enables/resets the FIFO.
30 * @fifo_en: Determines which data will appear in FIFO.
31 * @gyro_config: gyro config register.
32 * @accl_config: accel config register
33 * @fifo_count_h: Upper byte of FIFO count.
34 * @fifo_r_w: FIFO register.
35 * @raw_gyro: Address of first gyro register.
36 * @raw_accl: Address of first accel register.
37 * @temperature: temperature register
38 * @int_enable: Interrupt enable register.
39 * @pwr_mgmt_1: Controls chip's power state and clock source.
40 * @pwr_mgmt_2: Controls power state of individual sensors.
41 */
42struct inv_mpu6050_reg_map {
43 u8 sample_rate_div;
44 u8 lpf;
45 u8 user_ctrl;
46 u8 fifo_en;
47 u8 gyro_config;
48 u8 accl_config;
49 u8 fifo_count_h;
50 u8 fifo_r_w;
51 u8 raw_gyro;
52 u8 raw_accl;
53 u8 temperature;
54 u8 int_enable;
55 u8 pwr_mgmt_1;
56 u8 pwr_mgmt_2;
57};
58
59/*device enum */
60enum inv_devices {
61 INV_MPU6050,
62 INV_NUM_PARTS
63};
64
65/**
66 * struct inv_mpu6050_chip_config - Cached chip configuration data.
67 * @fsr: Full scale range.
68 * @lpf: Digital low pass filter frequency.
69 * @accl_fs: accel full scale range.
70 * @enable: master enable state.
71 * @accl_fifo_enable: enable accel data output
72 * @gyro_fifo_enable: enable gyro data output
73 * @fifo_rate: FIFO update rate.
74 */
75struct inv_mpu6050_chip_config {
76 unsigned int fsr:2;
77 unsigned int lpf:3;
78 unsigned int accl_fs:2;
79 unsigned int enable:1;
80 unsigned int accl_fifo_enable:1;
81 unsigned int gyro_fifo_enable:1;
82 u16 fifo_rate;
83};
84
85/**
86 * struct inv_mpu6050_hw - Other important hardware information.
87 * @num_reg: Number of registers on device.
88 * @name: name of the chip.
89 * @reg: register map of the chip.
90 * @config: configuration of the chip.
91 */
92struct inv_mpu6050_hw {
93 u8 num_reg;
94 u8 *name;
95 const struct inv_mpu6050_reg_map *reg;
96 const struct inv_mpu6050_chip_config *config;
97};
98
99/*
100 * struct inv_mpu6050_state - Driver state variables.
101 * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp.
102 * @trig: IIO trigger.
103 * @chip_config: Cached attribute information.
104 * @reg: Map of important registers.
105 * @hw: Other hardware-specific information.
106 * @chip_type: chip type.
107 * @time_stamp_lock: spin lock to time stamp.
108 * @client: i2c client handle.
109 * @plat_data: platform data.
110 * @timestamps: kfifo queue to store time stamp.
111 */
112struct inv_mpu6050_state {
113#define TIMESTAMP_FIFO_SIZE 16
114 struct iio_trigger *trig;
115 struct inv_mpu6050_chip_config chip_config;
116 const struct inv_mpu6050_reg_map *reg;
117 const struct inv_mpu6050_hw *hw;
118 enum inv_devices chip_type;
119 spinlock_t time_stamp_lock;
120 struct i2c_client *client;
121 struct inv_mpu6050_platform_data plat_data;
122 DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
123};
124
125/*register and associated bit definition*/
126#define INV_MPU6050_REG_SAMPLE_RATE_DIV 0x19
127#define INV_MPU6050_REG_CONFIG 0x1A
128#define INV_MPU6050_REG_GYRO_CONFIG 0x1B
129#define INV_MPU6050_REG_ACCEL_CONFIG 0x1C
130
131#define INV_MPU6050_REG_FIFO_EN 0x23
132#define INV_MPU6050_BIT_ACCEL_OUT 0x08
133#define INV_MPU6050_BITS_GYRO_OUT 0x70
134
135#define INV_MPU6050_REG_INT_ENABLE 0x38
136#define INV_MPU6050_BIT_DATA_RDY_EN 0x01
137#define INV_MPU6050_BIT_DMP_INT_EN 0x02
138
139#define INV_MPU6050_REG_RAW_ACCEL 0x3B
140#define INV_MPU6050_REG_TEMPERATURE 0x41
141#define INV_MPU6050_REG_RAW_GYRO 0x43
142
143#define INV_MPU6050_REG_USER_CTRL 0x6A
144#define INV_MPU6050_BIT_FIFO_RST 0x04
145#define INV_MPU6050_BIT_DMP_RST 0x08
146#define INV_MPU6050_BIT_I2C_MST_EN 0x20
147#define INV_MPU6050_BIT_FIFO_EN 0x40
148#define INV_MPU6050_BIT_DMP_EN 0x80
149
150#define INV_MPU6050_REG_PWR_MGMT_1 0x6B
151#define INV_MPU6050_BIT_H_RESET 0x80
152#define INV_MPU6050_BIT_SLEEP 0x40
153#define INV_MPU6050_BIT_CLK_MASK 0x7
154
155#define INV_MPU6050_REG_PWR_MGMT_2 0x6C
156#define INV_MPU6050_BIT_PWR_ACCL_STBY 0x38
157#define INV_MPU6050_BIT_PWR_GYRO_STBY 0x07
158
159#define INV_MPU6050_REG_FIFO_COUNT_H 0x72
160#define INV_MPU6050_REG_FIFO_R_W 0x74
161
162#define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6
163#define INV_MPU6050_FIFO_COUNT_BYTE 2
164#define INV_MPU6050_FIFO_THRESHOLD 500
165#define INV_MPU6050_POWER_UP_TIME 100
166#define INV_MPU6050_TEMP_UP_TIME 100
167#define INV_MPU6050_SENSOR_UP_TIME 30
168#define INV_MPU6050_REG_UP_TIME 5
169
170#define INV_MPU6050_TEMP_OFFSET 12421
171#define INV_MPU6050_TEMP_SCALE 2941
172#define INV_MPU6050_MAX_GYRO_FS_PARAM 3
173#define INV_MPU6050_MAX_ACCL_FS_PARAM 3
174#define INV_MPU6050_THREE_AXIS 3
175#define INV_MPU6050_GYRO_CONFIG_FSR_SHIFT 3
176#define INV_MPU6050_ACCL_CONFIG_FSR_SHIFT 3
177
178/* 6 + 6 round up and plus 8 */
179#define INV_MPU6050_OUTPUT_DATA_SIZE 24
180
181/* init parameters */
182#define INV_MPU6050_INIT_FIFO_RATE 50
183#define INV_MPU6050_TIME_STAMP_TOR 5
184#define INV_MPU6050_MAX_FIFO_RATE 1000
185#define INV_MPU6050_MIN_FIFO_RATE 4
186#define INV_MPU6050_ONE_K_HZ 1000
187
188/* scan element definition */
189enum inv_mpu6050_scan {
190 INV_MPU6050_SCAN_ACCL_X,
191 INV_MPU6050_SCAN_ACCL_Y,
192 INV_MPU6050_SCAN_ACCL_Z,
193 INV_MPU6050_SCAN_GYRO_X,
194 INV_MPU6050_SCAN_GYRO_Y,
195 INV_MPU6050_SCAN_GYRO_Z,
196 INV_MPU6050_SCAN_TIMESTAMP,
197};
198
199enum inv_mpu6050_filter_e {
200 INV_MPU6050_FILTER_256HZ_NOLPF2 = 0,
201 INV_MPU6050_FILTER_188HZ,
202 INV_MPU6050_FILTER_98HZ,
203 INV_MPU6050_FILTER_42HZ,
204 INV_MPU6050_FILTER_20HZ,
205 INV_MPU6050_FILTER_10HZ,
206 INV_MPU6050_FILTER_5HZ,
207 INV_MPU6050_FILTER_2100HZ_NOLPF,
208 NUM_MPU6050_FILTER
209};
210
211/* IIO attribute address */
212enum INV_MPU6050_IIO_ATTR_ADDR {
213 ATTR_GYRO_MATRIX,
214 ATTR_ACCL_MATRIX,
215};
216
217enum inv_mpu6050_accl_fs_e {
218 INV_MPU6050_FS_02G = 0,
219 INV_MPU6050_FS_04G,
220 INV_MPU6050_FS_08G,
221 INV_MPU6050_FS_16G,
222 NUM_ACCL_FSR
223};
224
225enum inv_mpu6050_fsr_e {
226 INV_MPU6050_FSR_250DPS = 0,
227 INV_MPU6050_FSR_500DPS,
228 INV_MPU6050_FSR_1000DPS,
229 INV_MPU6050_FSR_2000DPS,
230 NUM_MPU6050_FSR
231};
232
233enum inv_mpu6050_clock_sel_e {
234 INV_CLK_INTERNAL = 0,
235 INV_CLK_PLL,
236 NUM_CLK
237};
238
239irqreturn_t inv_mpu6050_irq_handler(int irq, void *p);
240irqreturn_t inv_mpu6050_read_fifo(int irq, void *p);
241int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev);
242void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st);
243int inv_reset_fifo(struct iio_dev *indio_dev);
244int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask);
245int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val);
246int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on);
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
new file mode 100644
index 000000000000..331781ffbb15
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
@@ -0,0 +1,196 @@
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#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/i2c.h>
18#include <linux/err.h>
19#include <linux/delay.h>
20#include <linux/sysfs.h>
21#include <linux/jiffies.h>
22#include <linux/irq.h>
23#include <linux/interrupt.h>
24#include <linux/kfifo.h>
25#include <linux/poll.h>
26#include "inv_mpu_iio.h"
27
28int inv_reset_fifo(struct iio_dev *indio_dev)
29{
30 int result;
31 u8 d;
32 struct inv_mpu6050_state *st = iio_priv(indio_dev);
33
34 /* disable interrupt */
35 result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0);
36 if (result) {
37 dev_err(&st->client->dev, "int_enable failed %d\n", result);
38 return result;
39 }
40 /* disable the sensor output to FIFO */
41 result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0);
42 if (result)
43 goto reset_fifo_fail;
44 /* disable fifo reading */
45 result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0);
46 if (result)
47 goto reset_fifo_fail;
48
49 /* reset FIFO*/
50 result = inv_mpu6050_write_reg(st, st->reg->user_ctrl,
51 INV_MPU6050_BIT_FIFO_RST);
52 if (result)
53 goto reset_fifo_fail;
54 /* enable interrupt */
55 if (st->chip_config.accl_fifo_enable ||
56 st->chip_config.gyro_fifo_enable) {
57 result = inv_mpu6050_write_reg(st, st->reg->int_enable,
58 INV_MPU6050_BIT_DATA_RDY_EN);
59 if (result)
60 return result;
61 }
62 /* enable FIFO reading and I2C master interface*/
63 result = inv_mpu6050_write_reg(st, st->reg->user_ctrl,
64 INV_MPU6050_BIT_FIFO_EN);
65 if (result)
66 goto reset_fifo_fail;
67 /* enable sensor output to FIFO */
68 d = 0;
69 if (st->chip_config.gyro_fifo_enable)
70 d |= INV_MPU6050_BITS_GYRO_OUT;
71 if (st->chip_config.accl_fifo_enable)
72 d |= INV_MPU6050_BIT_ACCEL_OUT;
73 result = inv_mpu6050_write_reg(st, st->reg->fifo_en, d);
74 if (result)
75 goto reset_fifo_fail;
76
77 return 0;
78
79reset_fifo_fail:
80 dev_err(&st->client->dev, "reset fifo failed %d\n", result);
81 result = inv_mpu6050_write_reg(st, st->reg->int_enable,
82 INV_MPU6050_BIT_DATA_RDY_EN);
83
84 return result;
85}
86
87static void inv_clear_kfifo(struct inv_mpu6050_state *st)
88{
89 unsigned long flags;
90
91 /* take the spin lock sem to avoid interrupt kick in */
92 spin_lock_irqsave(&st->time_stamp_lock, flags);
93 kfifo_reset(&st->timestamps);
94 spin_unlock_irqrestore(&st->time_stamp_lock, flags);
95}
96
97/**
98 * inv_mpu6050_irq_handler() - Cache a timestamp at each data ready interrupt.
99 */
100irqreturn_t inv_mpu6050_irq_handler(int irq, void *p)
101{
102 struct iio_poll_func *pf = p;
103 struct iio_dev *indio_dev = pf->indio_dev;
104 struct inv_mpu6050_state *st = iio_priv(indio_dev);
105 s64 timestamp;
106
107 timestamp = iio_get_time_ns();
108 spin_lock(&st->time_stamp_lock);
109 kfifo_in(&st->timestamps, &timestamp, 1);
110 spin_unlock(&st->time_stamp_lock);
111
112 return IRQ_WAKE_THREAD;
113}
114
115/**
116 * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO.
117 */
118irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
119{
120 struct iio_poll_func *pf = p;
121 struct iio_dev *indio_dev = pf->indio_dev;
122 struct inv_mpu6050_state *st = iio_priv(indio_dev);
123 size_t bytes_per_datum;
124 int result;
125 u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
126 u16 fifo_count;
127 s64 timestamp;
128 u64 *tmp;
129
130 mutex_lock(&indio_dev->mlock);
131 if (!(st->chip_config.accl_fifo_enable |
132 st->chip_config.gyro_fifo_enable))
133 goto end_session;
134 bytes_per_datum = 0;
135 if (st->chip_config.accl_fifo_enable)
136 bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
137
138 if (st->chip_config.gyro_fifo_enable)
139 bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
140
141 /*
142 * read fifo_count register to know how many bytes inside FIFO
143 * right now
144 */
145 result = i2c_smbus_read_i2c_block_data(st->client,
146 st->reg->fifo_count_h,
147 INV_MPU6050_FIFO_COUNT_BYTE, data);
148 if (result != INV_MPU6050_FIFO_COUNT_BYTE)
149 goto end_session;
150 fifo_count = be16_to_cpup((__be16 *)(&data[0]));
151 if (fifo_count < bytes_per_datum)
152 goto end_session;
153 /* fifo count can't be odd number, if it is odd, reset fifo*/
154 if (fifo_count & 1)
155 goto flush_fifo;
156 if (fifo_count > INV_MPU6050_FIFO_THRESHOLD)
157 goto flush_fifo;
158 /* Timestamp mismatch. */
159 if (kfifo_len(&st->timestamps) >
160 fifo_count / bytes_per_datum + INV_MPU6050_TIME_STAMP_TOR)
161 goto flush_fifo;
162 while (fifo_count >= bytes_per_datum) {
163 result = i2c_smbus_read_i2c_block_data(st->client,
164 st->reg->fifo_r_w,
165 bytes_per_datum, data);
166 if (result != bytes_per_datum)
167 goto flush_fifo;
168
169 result = kfifo_out(&st->timestamps, &timestamp, 1);
170 /* when there is no timestamp, put timestamp as 0 */
171 if (0 == result)
172 timestamp = 0;
173
174 tmp = (u64 *)data;
175 tmp[DIV_ROUND_UP(bytes_per_datum, 8)] = timestamp;
176 result = iio_push_to_buffers(indio_dev, data);
177 if (result)
178 goto flush_fifo;
179 fifo_count -= bytes_per_datum;
180 }
181
182end_session:
183 mutex_unlock(&indio_dev->mlock);
184 iio_trigger_notify_done(indio_dev->trig);
185
186 return IRQ_HANDLED;
187
188flush_fifo:
189 /* Flush HW and SW FIFOs. */
190 inv_reset_fifo(indio_dev);
191 inv_clear_kfifo(st);
192 mutex_unlock(&indio_dev->mlock);
193 iio_trigger_notify_done(indio_dev->trig);
194
195 return IRQ_HANDLED;
196}
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
new file mode 100644
index 000000000000..e1d0869e0ad1
--- /dev/null
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -0,0 +1,155 @@
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#include "inv_mpu_iio.h"
15
16static void inv_scan_query(struct iio_dev *indio_dev)
17{
18 struct inv_mpu6050_state *st = iio_priv(indio_dev);
19
20 st->chip_config.gyro_fifo_enable =
21 test_bit(INV_MPU6050_SCAN_GYRO_X,
22 indio_dev->active_scan_mask) ||
23 test_bit(INV_MPU6050_SCAN_GYRO_Y,
24 indio_dev->active_scan_mask) ||
25 test_bit(INV_MPU6050_SCAN_GYRO_Z,
26 indio_dev->active_scan_mask);
27
28 st->chip_config.accl_fifo_enable =
29 test_bit(INV_MPU6050_SCAN_ACCL_X,
30 indio_dev->active_scan_mask) ||
31 test_bit(INV_MPU6050_SCAN_ACCL_Y,
32 indio_dev->active_scan_mask) ||
33 test_bit(INV_MPU6050_SCAN_ACCL_Z,
34 indio_dev->active_scan_mask);
35}
36
37/**
38 * inv_mpu6050_set_enable() - enable chip functions.
39 * @indio_dev: Device driver instance.
40 * @enable: enable/disable
41 */
42static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable)
43{
44 struct inv_mpu6050_state *st = iio_priv(indio_dev);
45 int result;
46
47 if (enable) {
48 result = inv_mpu6050_set_power_itg(st, true);
49 if (result)
50 return result;
51 inv_scan_query(indio_dev);
52 if (st->chip_config.gyro_fifo_enable) {
53 result = inv_mpu6050_switch_engine(st, true,
54 INV_MPU6050_BIT_PWR_GYRO_STBY);
55 if (result)
56 return result;
57 }
58 if (st->chip_config.accl_fifo_enable) {
59 result = inv_mpu6050_switch_engine(st, true,
60 INV_MPU6050_BIT_PWR_ACCL_STBY);
61 if (result)
62 return result;
63 }
64 result = inv_reset_fifo(indio_dev);
65 if (result)
66 return result;
67 } else {
68 result = inv_mpu6050_write_reg(st, st->reg->fifo_en, 0);
69 if (result)
70 return result;
71
72 result = inv_mpu6050_write_reg(st, st->reg->int_enable, 0);
73 if (result)
74 return result;
75
76 result = inv_mpu6050_write_reg(st, st->reg->user_ctrl, 0);
77 if (result)
78 return result;
79
80 result = inv_mpu6050_switch_engine(st, false,
81 INV_MPU6050_BIT_PWR_GYRO_STBY);
82 if (result)
83 return result;
84
85 result = inv_mpu6050_switch_engine(st, false,
86 INV_MPU6050_BIT_PWR_ACCL_STBY);
87 if (result)
88 return result;
89 result = inv_mpu6050_set_power_itg(st, false);
90 if (result)
91 return result;
92 }
93 st->chip_config.enable = enable;
94
95 return 0;
96}
97
98/**
99 * inv_mpu_data_rdy_trigger_set_state() - set data ready interrupt state
100 * @trig: Trigger instance
101 * @state: Desired trigger state
102 */
103static int inv_mpu_data_rdy_trigger_set_state(struct iio_trigger *trig,
104 bool state)
105{
106 return inv_mpu6050_set_enable(trig->private_data, state);
107}
108
109static const struct iio_trigger_ops inv_mpu_trigger_ops = {
110 .owner = THIS_MODULE,
111 .set_trigger_state = &inv_mpu_data_rdy_trigger_set_state,
112};
113
114int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
115{
116 int ret;
117 struct inv_mpu6050_state *st = iio_priv(indio_dev);
118
119 st->trig = iio_trigger_alloc("%s-dev%d",
120 indio_dev->name,
121 indio_dev->id);
122 if (st->trig == NULL) {
123 ret = -ENOMEM;
124 goto error_ret;
125 }
126 ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll,
127 IRQF_TRIGGER_RISING,
128 "inv_mpu",
129 st->trig);
130 if (ret)
131 goto error_free_trig;
132 st->trig->dev.parent = &st->client->dev;
133 st->trig->private_data = indio_dev;
134 st->trig->ops = &inv_mpu_trigger_ops;
135 ret = iio_trigger_register(st->trig);
136 if (ret)
137 goto error_free_irq;
138 indio_dev->trig = st->trig;
139
140 return 0;
141
142error_free_irq:
143 free_irq(st->client->irq, st->trig);
144error_free_trig:
145 iio_trigger_free(st->trig);
146error_ret:
147 return ret;
148}
149
150void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st)
151{
152 iio_trigger_unregister(st->trig);
153 free_irq(st->client->irq, st->trig);
154 iio_trigger_free(st->trig);
155}
diff --git a/include/linux/platform_data/invensense_mpu6050.h b/include/linux/platform_data/invensense_mpu6050.h
new file mode 100644
index 000000000000..ad3aa7b95f35
--- /dev/null
+++ b/include/linux/platform_data/invensense_mpu6050.h
@@ -0,0 +1,31 @@
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#ifndef __INV_MPU6050_PLATFORM_H_
15#define __INV_MPU6050_PLATFORM_H_
16
17/**
18 * struct inv_mpu6050_platform_data - Platform data for the mpu driver
19 * @orientation: Orientation matrix of the chip
20 *
21 * Contains platform specific information on how to configure the MPU6050 to
22 * work on this platform. The orientation matricies are 3x3 rotation matricies
23 * that are applied to the data to rotate from the mounting orientation to the
24 * platform orientation. The values must be one of 0, 1, or -1 and each row and
25 * column should have exactly 1 non-zero value.
26 */
27struct inv_mpu6050_platform_data {
28 __s8 orientation[9];
29};
30
31#endif