aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/mpu3050
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/misc/mpu3050
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/misc/mpu3050')
-rw-r--r--drivers/misc/mpu3050/Kconfig65
-rw-r--r--drivers/misc/mpu3050/Makefile132
-rw-r--r--drivers/misc/mpu3050/accel/kxtf9.c669
-rw-r--r--drivers/misc/mpu3050/compass/ak8975.c258
-rw-r--r--drivers/misc/mpu3050/log.h306
-rw-r--r--drivers/misc/mpu3050/mldl_cfg.c1739
-rw-r--r--drivers/misc/mpu3050/mldl_cfg.h199
-rw-r--r--drivers/misc/mpu3050/mlos-kernel.c89
-rw-r--r--drivers/misc/mpu3050/mlos.h73
-rw-r--r--drivers/misc/mpu3050/mlsl-kernel.c331
-rw-r--r--drivers/misc/mpu3050/mlsl.h103
-rw-r--r--drivers/misc/mpu3050/mltypes.h227
-rw-r--r--drivers/misc/mpu3050/mpu-dev.c1310
-rw-r--r--drivers/misc/mpu3050/mpu-i2c.c196
-rw-r--r--drivers/misc/mpu3050/mpu-i2c.h58
-rw-r--r--drivers/misc/mpu3050/mpuirq.c319
-rw-r--r--drivers/misc/mpu3050/mpuirq.h42
-rw-r--r--drivers/misc/mpu3050/slaveirq.c273
-rw-r--r--drivers/misc/mpu3050/slaveirq.h43
-rw-r--r--drivers/misc/mpu3050/timerirq.c299
-rw-r--r--drivers/misc/mpu3050/timerirq.h30
21 files changed, 6761 insertions, 0 deletions
diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig
new file mode 100644
index 00000000000..de240fa0ad8
--- /dev/null
+++ b/drivers/misc/mpu3050/Kconfig
@@ -0,0 +1,65 @@
1
2menu "Motion Sensors Support"
3
4choice
5 tristate "Motion Processing Unit"
6 depends on I2C
7 optional
8
9config MPU_SENSORS_MPU3050
10 tristate "MPU3050"
11 help
12 If you say yes here you get support for the MPU3050 Gyroscope driver
13 This driver can also be built as a module. If so, the module
14 will be called mpu3050.
15
16config MPU_SENSORS_MPU6000
17 tristate "MPU6000"
18 help
19 If you say yes here you get support for the MPU6000 Gyroscope driver
20 This driver can also be built as a module. If so, the module
21 will be called mpu6000.
22
23endchoice
24
25choice
26 prompt "Accelerometer Type"
27 depends on MPU_SENSORS_MPU3050
28 optional
29
30config MPU_SENSORS_KXTF9
31 bool "Kionix KXTF9"
32 help
33 This enables support for the Kionix KXFT9 accelerometer
34
35endchoice
36
37choice
38 prompt "Compass Type"
39 depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050
40 optional
41
42config MPU_SENSORS_AK8975
43 bool "AKM ak8975"
44 help
45 This enables support for the AKM ak8975 compass
46
47endchoice
48
49config MPU_SENSORS_TIMERIRQ
50 tristate "Timer IRQ"
51 help
52 If you say yes here you get access to the timerirq device handle which
53 can be used to select on. This can be used instead of IRQ's, sleeping,
54 or timer threads. Reading from this device returns the same type of
55 information as reading from the MPU and slave IRQ's.
56
57config MPU_SENSORS_DEBUG
58 bool "MPU debug"
59 depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000 || MPU_SENSORS_TIMERIRQ
60 help
61 If you say yes here you get extra debug messages from the MPU3050
62 and other slave sensors.
63
64endmenu
65
diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile
new file mode 100644
index 00000000000..89ac46fdac5
--- /dev/null
+++ b/drivers/misc/mpu3050/Makefile
@@ -0,0 +1,132 @@
1
2# Kernel makefile for motions sensors
3#
4#
5
6# MPU
7obj-$(CONFIG_MPU_SENSORS_MPU3050) += mpu3050.o
8mpu3050-objs += mpuirq.o \
9 slaveirq.o \
10 mpu-dev.o \
11 mpu-i2c.o \
12 mlsl-kernel.o \
13 mlos-kernel.o \
14 $(MLLITE_DIR)mldl_cfg.o
15
16#
17# Accel options
18#
19ifdef CONFIG_MPU_SENSORS_ADXL346
20mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o
21endif
22
23ifdef CONFIG_MPU_SENSORS_BMA150
24mpu3050-objs += $(MLLITE_DIR)accel/bma150.o
25endif
26
27ifdef CONFIG_MPU_SENSORS_BMA222
28mpu3050-objs += $(MLLITE_DIR)accel/bma222.o
29endif
30
31ifdef CONFIG_MPU_SENSORS_KXSD9
32mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o
33endif
34
35ifdef CONFIG_MPU_SENSORS_KXTF9
36mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o
37endif
38
39ifdef CONFIG_MPU_SENSORS_LIS331DLH
40mpu3050-objs += $(MLLITE_DIR)accel/lis331.o
41endif
42
43ifdef CONFIG_MPU_SENSORS_LIS3DH
44mpu3050-objs += $(MLLITE_DIR)accel/lis3dh.o
45endif
46
47ifdef CONFIG_MPU_SENSORS_LSM303DLHA
48mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o
49endif
50
51ifdef CONFIG_MPU_SENSORS_MMA8450
52mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o
53endif
54
55ifdef CONFIG_MPU_SENSORS_MMA845X
56mpu3050-objs += $(MLLITE_DIR)accel/mma845x.o
57endif
58
59#
60# Compass options
61#
62ifdef CONFIG_MPU_SENSORS_AK8975
63mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o
64endif
65
66ifdef CONFIG_MPU_SENSORS_AMI30X
67mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o
68endif
69
70ifdef CONFIG_MPU_SENSORS_AMI306
71mpu3050-objs += $(MLLITE_DIR)compass/ami306.o
72endif
73
74ifdef CONFIG_MPU_SENSORS_HMC5883
75mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o
76endif
77
78ifdef CONFIG_MPU_SENSORS_LSM303DLHM
79mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o
80endif
81
82ifdef CONFIG_MPU_SENSORS_MMC314X
83mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o
84endif
85
86ifdef CONFIG_MPU_SENSORS_YAS529
87mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o
88endif
89
90ifdef CONFIG_MPU_SENSORS_YAS530
91mpu3050-objs += $(MLLITE_DIR)compass/yas530.o
92endif
93
94ifdef CONFIG_MPU_SENSORS_HSCDTD002B
95mpu3050-objs += $(MLLITE_DIR)compass/hscdtd002b.o
96endif
97
98ifdef CONFIG_MPU_SENSORS_HSCDTD004A
99mpu3050-objs += $(MLLITE_DIR)compass/hscdtd004a.o
100endif
101#
102# Pressure options
103#
104ifdef CONFIG_MPU_SENSORS_BMA085
105mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o
106endif
107
108EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \
109 -I$(M)/../../include \
110 -Idrivers/misc/mpu3050 \
111 -Iinclude/linux
112
113obj-$(CONFIG_MPU_SENSORS_MPU6000)+= mpu6000.o
114mpu6000-objs += mpuirq.o \
115 slaveirq.o \
116 mpu-dev.o \
117 mpu-i2c.o \
118 mlsl-kernel.o \
119 mlos-kernel.o \
120 $(MLLITE_DIR)mldl_cfg.o \
121 $(MLLITE_DIR)accel/mantis.o
122
123ifdef CONFIG_MPU_SENSORS_AK8975
124mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o
125endif
126
127ifdef CONFIG_MPU_SENSORS_MPU6000
128EXTRA_CFLAGS += -DM_HW
129endif
130
131obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o
132
diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c
new file mode 100644
index 00000000000..938cd572a8f
--- /dev/null
+++ b/drivers/misc/mpu3050/accel/kxtf9.c
@@ -0,0 +1,669 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @defgroup ACCELDL (Motion Library - Accelerometer Driver Layer)
22 * @brief Provides the interface to setup and handle an accelerometers
23 * connected to the secondary I2C interface of the gyroscope.
24 *
25 * @{
26 * @file kxtf9.c
27 * @brief Accelerometer setup and handling methods.
28*/
29
30/* ------------------ */
31/* - Include Files. - */
32/* ------------------ */
33
34#undef MPL_LOG_NDEBUG
35#define MPL_LOG_NDEBUG 1
36
37#ifdef __KERNEL__
38#include <linux/module.h>
39#endif
40
41#include "mpu.h"
42#include "mlsl.h"
43#include "mlos.h"
44
45#include <log.h>
46#undef MPL_LOG_TAG
47#define MPL_LOG_TAG "MPL-acc"
48
49#define KXTF9_XOUT_HPF_L (0x00) /* 0000 0000 */
50#define KXTF9_XOUT_HPF_H (0x01) /* 0000 0001 */
51#define KXTF9_YOUT_HPF_L (0x02) /* 0000 0010 */
52#define KXTF9_YOUT_HPF_H (0x03) /* 0000 0011 */
53#define KXTF9_ZOUT_HPF_L (0x04) /* 0001 0100 */
54#define KXTF9_ZOUT_HPF_H (0x05) /* 0001 0101 */
55#define KXTF9_XOUT_L (0x06) /* 0000 0110 */
56#define KXTF9_XOUT_H (0x07) /* 0000 0111 */
57#define KXTF9_YOUT_L (0x08) /* 0000 1000 */
58#define KXTF9_YOUT_H (0x09) /* 0000 1001 */
59#define KXTF9_ZOUT_L (0x0A) /* 0001 1010 */
60#define KXTF9_ZOUT_H (0x0B) /* 0001 1011 */
61#define KXTF9_ST_RESP (0x0C) /* 0000 1100 */
62#define KXTF9_WHO_AM_I (0x0F) /* 0000 1111 */
63#define KXTF9_TILT_POS_CUR (0x10) /* 0001 0000 */
64#define KXTF9_TILT_POS_PRE (0x11) /* 0001 0001 */
65#define KXTF9_INT_SRC_REG1 (0x15) /* 0001 0101 */
66#define KXTF9_INT_SRC_REG2 (0x16) /* 0001 0110 */
67#define KXTF9_STATUS_REG (0x18) /* 0001 1000 */
68#define KXTF9_INT_REL (0x1A) /* 0001 1010 */
69#define KXTF9_CTRL_REG1 (0x1B) /* 0001 1011 */
70#define KXTF9_CTRL_REG2 (0x1C) /* 0001 1100 */
71#define KXTF9_CTRL_REG3 (0x1D) /* 0001 1101 */
72#define KXTF9_INT_CTRL_REG1 (0x1E) /* 0001 1110 */
73#define KXTF9_INT_CTRL_REG2 (0x1F) /* 0001 1111 */
74#define KXTF9_INT_CTRL_REG3 (0x20) /* 0010 0000 */
75#define KXTF9_DATA_CTRL_REG (0x21) /* 0010 0001 */
76#define KXTF9_TILT_TIMER (0x28) /* 0010 1000 */
77#define KXTF9_WUF_TIMER (0x29) /* 0010 1001 */
78#define KXTF9_TDT_TIMER (0x2B) /* 0010 1011 */
79#define KXTF9_TDT_H_THRESH (0x2C) /* 0010 1100 */
80#define KXTF9_TDT_L_THRESH (0x2D) /* 0010 1101 */
81#define KXTF9_TDT_TAP_TIMER (0x2E) /* 0010 1110 */
82#define KXTF9_TDT_TOTAL_TIMER (0x2F) /* 0010 1111 */
83#define KXTF9_TDT_LATENCY_TIMER (0x30) /* 0011 0000 */
84#define KXTF9_TDT_WINDOW_TIMER (0x31) /* 0011 0001 */
85#define KXTF9_WUF_THRESH (0x5A) /* 0101 1010 */
86#define KXTF9_TILT_ANGLE (0x5C) /* 0101 1100 */
87#define KXTF9_HYST_SET (0x5F) /* 0101 1111 */
88
89#define KXTF9_MAX_DUR (0xFF)
90#define KXTF9_MAX_THS (0xFF)
91#define KXTF9_THS_COUNTS_P_G (32)
92
93/* --------------------- */
94/* - Variables. - */
95/* --------------------- */
96
97struct kxtf9_config {
98 unsigned int odr; /* Output data rate mHz */
99 unsigned int fsr; /* full scale range mg */
100 unsigned int ths; /* Motion no-motion thseshold mg */
101 unsigned int dur; /* Motion no-motion duration ms */
102 unsigned int irq_type;
103 unsigned char reg_ths;
104 unsigned char reg_dur;
105 unsigned char reg_odr;
106 unsigned char reg_int_cfg1;
107 unsigned char reg_int_cfg2;
108 unsigned char ctrl_reg1;
109};
110
111struct kxtf9_private_data {
112 struct kxtf9_config suspend;
113 struct kxtf9_config resume;
114};
115
116/*****************************************
117 Accelerometer Initialization Functions
118*****************************************/
119
120static int kxtf9_set_ths(void *mlsl_handle,
121 struct ext_slave_platform_data *pdata,
122 struct kxtf9_config *config,
123 int apply,
124 long ths)
125{
126 int result = ML_SUCCESS;
127 if ((ths * KXTF9_THS_COUNTS_P_G / 1000) > KXTF9_MAX_THS)
128 ths = (KXTF9_MAX_THS * 1000) / KXTF9_THS_COUNTS_P_G;
129
130 if (ths < 0)
131 ths = 0;
132
133 config->ths = ths;
134 config->reg_ths = (unsigned char)
135 ((long)(ths * KXTF9_THS_COUNTS_P_G) / 1000);
136 MPL_LOGV("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
137 if (apply)
138 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
139 KXTF9_WUF_THRESH,
140 config->reg_ths);
141 return result;
142}
143
144static int kxtf9_set_dur(void *mlsl_handle,
145 struct ext_slave_platform_data *pdata,
146 struct kxtf9_config *config,
147 int apply,
148 long dur)
149{
150 int result = ML_SUCCESS;
151 long reg_dur = (dur * config->odr) / 1000000;
152 config->dur = dur;
153
154 if (reg_dur > KXTF9_MAX_DUR)
155 reg_dur = KXTF9_MAX_DUR;
156
157 config->reg_dur = (unsigned char) reg_dur;
158 MPL_LOGV("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
159 if (apply)
160 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
161 KXTF9_WUF_TIMER,
162 (unsigned char)reg_dur);
163 return result;
164}
165
166/**
167 * Sets the IRQ to fire when one of the IRQ events occur. Threshold and
168 * duration will not be used uless the type is MOT or NMOT.
169 *
170 * @param config configuration to apply to, suspend or resume
171 * @param irq_type The type of IRQ. Valid values are
172 * - MPU_SLAVE_IRQ_TYPE_NONE
173 * - MPU_SLAVE_IRQ_TYPE_MOTION
174 * - MPU_SLAVE_IRQ_TYPE_DATA_READY
175 */
176static int kxtf9_set_irq(void *mlsl_handle,
177 struct ext_slave_platform_data *pdata,
178 struct kxtf9_config *config,
179 int apply,
180 long irq_type)
181{
182 int result = ML_SUCCESS;
183 struct kxtf9_private_data *private_data = pdata->private_data;
184
185 config->irq_type = (unsigned char)irq_type;
186 config->ctrl_reg1 &= ~0x22;
187 if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
188 config->ctrl_reg1 |= 0x20;
189 config->reg_int_cfg1 = 0x38;
190 config->reg_int_cfg2 = 0x00;
191 } else if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION) {
192 config->ctrl_reg1 |= 0x02;
193 if ((unsigned long) config ==
194 (unsigned long) &private_data->suspend)
195 config->reg_int_cfg1 = 0x34;
196 else
197 config->reg_int_cfg1 = 0x24;
198 config->reg_int_cfg2 = 0xE0;
199 } else {
200 config->reg_int_cfg1 = 0x00;
201 config->reg_int_cfg2 = 0x00;
202 }
203
204 if (apply) {
205 /* Must clear bit 7 before writing new configuration */
206 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
207 KXTF9_CTRL_REG1, 0x40);
208 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
209 KXTF9_INT_CTRL_REG1,
210 config->reg_int_cfg1);
211 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
212 KXTF9_INT_CTRL_REG2,
213 config->reg_int_cfg2);
214 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
215 KXTF9_CTRL_REG1,
216 config->ctrl_reg1);
217 }
218 MPL_LOGV("CTRL_REG1: %lx, INT_CFG1: %lx, INT_CFG2: %lx\n",
219 (unsigned long)config->ctrl_reg1,
220 (unsigned long)config->reg_int_cfg1,
221 (unsigned long)config->reg_int_cfg2);
222
223 return result;
224}
225
226/**
227 * Set the Output data rate for the particular configuration
228 *
229 * @param config Config to modify with new ODR
230 * @param odr Output data rate in units of 1/1000Hz
231 */
232static int kxtf9_set_odr(void *mlsl_handle,
233 struct ext_slave_platform_data *pdata,
234 struct kxtf9_config *config,
235 int apply,
236 long odr)
237{
238 unsigned char bits;
239 int result = ML_SUCCESS;
240
241 /* Data sheet says there is 12.5 hz, but that seems to produce a single
242 * correct data value, thus we remove it from the table */
243 if (odr > 400000) {
244 config->odr = 800000;
245 bits = 0x06;
246 } else if (odr > 200000) {
247 config->odr = 400000;
248 bits = 0x05;
249 } else if (odr > 100000) {
250 config->odr = 200000;
251 bits = 0x04;
252 } else if (odr > 50000) {
253 config->odr = 100000;
254 bits = 0x03;
255 } else if (odr > 25000) {
256 config->odr = 50000;
257 bits = 0x02;
258 } else if (odr != 0) {
259 config->odr = 25000;
260 bits = 0x01;
261 } else {
262 config->odr = 0;
263 bits = 0;
264 }
265
266 config->reg_odr = bits;
267 kxtf9_set_dur(mlsl_handle, pdata,
268 config, apply, config->dur);
269 MPL_LOGV("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
270 if (apply) {
271 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
272 KXTF9_DATA_CTRL_REG,
273 config->reg_odr);
274 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
275 KXTF9_CTRL_REG1,
276 0x40);
277 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
278 KXTF9_CTRL_REG1,
279 config->ctrl_reg1);
280 }
281 return result;
282}
283
284/**
285 * Set the full scale range of the accels
286 *
287 * @param config pointer to configuration
288 * @param fsr requested full scale range
289 */
290static int kxtf9_set_fsr(void *mlsl_handle,
291 struct ext_slave_platform_data *pdata,
292 struct kxtf9_config *config,
293 int apply,
294 long fsr)
295{
296 int result = ML_SUCCESS;
297
298 config->ctrl_reg1 = (config->ctrl_reg1 & 0xE7);
299 if (fsr <= 2000) {
300 config->fsr = 2000;
301 config->ctrl_reg1 |= 0x00;
302 } else if (fsr <= 4000) {
303 config->fsr = 4000;
304 config->ctrl_reg1 |= 0x08;
305 } else {
306 config->fsr = 8000;
307 config->ctrl_reg1 |= 0x10;
308 }
309
310 MPL_LOGV("FSR: %d\n", config->fsr);
311 if (apply) {
312 /* Must clear bit 7 before writing new configuration */
313 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
314 KXTF9_CTRL_REG1, 0x40);
315 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
316 KXTF9_CTRL_REG1, config->ctrl_reg1);
317 }
318 return result;
319}
320
321static int kxtf9_suspend(void *mlsl_handle,
322 struct ext_slave_descr *slave,
323 struct ext_slave_platform_data *pdata)
324{
325 int result;
326 unsigned char data;
327 struct kxtf9_private_data *private_data = pdata->private_data;
328
329 /* Wake up */
330 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
331 KXTF9_CTRL_REG1, 0x40);
332 ERROR_CHECK(result);
333 /* INT_CTRL_REG1: */
334 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
335 KXTF9_INT_CTRL_REG1,
336 private_data->suspend.reg_int_cfg1);
337 ERROR_CHECK(result);
338 /* WUF_THRESH: */
339 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
340 KXTF9_WUF_THRESH,
341 private_data->suspend.reg_ths);
342 ERROR_CHECK(result);
343 /* DATA_CTRL_REG */
344 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
345 KXTF9_DATA_CTRL_REG,
346 private_data->suspend.reg_odr);
347 ERROR_CHECK(result);
348 /* WUF_TIMER */
349 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
350 KXTF9_WUF_TIMER, private_data->suspend.reg_dur);
351 ERROR_CHECK(result);
352
353 /* Normal operation */
354 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
355 KXTF9_CTRL_REG1,
356 private_data->suspend.ctrl_reg1);
357 ERROR_CHECK(result);
358 result = MLSLSerialRead(mlsl_handle, pdata->address,
359 KXTF9_INT_REL, 1, &data);
360 ERROR_CHECK(result);
361
362 return result;
363}
364
365/* full scale setting - register and mask */
366#define ACCEL_KIONIX_CTRL_REG (0x1b)
367#define ACCEL_KIONIX_CTRL_MASK (0x18)
368
369static int kxtf9_resume(void *mlsl_handle,
370 struct ext_slave_descr *slave,
371 struct ext_slave_platform_data *pdata)
372{
373 int result = ML_SUCCESS;
374 unsigned char data;
375 struct kxtf9_private_data *private_data = pdata->private_data;
376
377 /* Wake up */
378 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
379 KXTF9_CTRL_REG1, 0x40);
380 ERROR_CHECK(result);
381 /* INT_CTRL_REG1: */
382 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
383 KXTF9_INT_CTRL_REG1,
384 private_data->resume.reg_int_cfg1);
385 ERROR_CHECK(result);
386 /* WUF_THRESH: */
387 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
388 KXTF9_WUF_THRESH, private_data->resume.reg_ths);
389 ERROR_CHECK(result);
390 /* DATA_CTRL_REG */
391 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
392 KXTF9_DATA_CTRL_REG,
393 private_data->resume.reg_odr);
394 ERROR_CHECK(result);
395 /* WUF_TIMER */
396 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
397 KXTF9_WUF_TIMER, private_data->resume.reg_dur);
398 ERROR_CHECK(result);
399
400 /* Normal operation */
401 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
402 KXTF9_CTRL_REG1,
403 private_data->resume.ctrl_reg1);
404 ERROR_CHECK(result);
405 result = MLSLSerialRead(mlsl_handle, pdata->address,
406 KXTF9_INT_REL, 1, &data);
407 ERROR_CHECK(result);
408
409 return ML_SUCCESS;
410}
411
412static int kxtf9_init(void *mlsl_handle,
413 struct ext_slave_descr *slave,
414 struct ext_slave_platform_data *pdata)
415{
416
417 struct kxtf9_private_data *private_data;
418 int result = ML_SUCCESS;
419
420 private_data = (struct kxtf9_private_data *)
421 MLOSMalloc(sizeof(struct kxtf9_private_data));
422
423 if (!private_data)
424 return ML_ERROR_MEMORY_EXAUSTED;
425
426 /* RAM reset */
427 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
428 KXTF9_CTRL_REG1,
429 0x40); /* Fastest Reset */
430 ERROR_CHECK(result);
431 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
432 KXTF9_DATA_CTRL_REG,
433 0x36); /* Fastest Reset */
434 ERROR_CHECK(result);
435 result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
436 KXTF9_CTRL_REG3, 0xcd); /* Reset */
437 ERROR_CHECK(result);
438 MLOSSleep(2);
439
440 pdata->private_data = private_data;
441
442 private_data->resume.ctrl_reg1 = 0xC0;
443 private_data->suspend.ctrl_reg1 = 0x40;
444
445 result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->suspend,
446 FALSE, 1000);
447 ERROR_CHECK(result);
448 result = kxtf9_set_dur(mlsl_handle, pdata, &private_data->resume,
449 FALSE, 2540);
450 ERROR_CHECK(result);
451
452 result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->suspend,
453 FALSE, 50000);
454 ERROR_CHECK(result);
455 result = kxtf9_set_odr(mlsl_handle, pdata, &private_data->resume,
456 FALSE, 200000);
457
458 result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->suspend,
459 FALSE, 2000);
460 ERROR_CHECK(result);
461 result = kxtf9_set_fsr(mlsl_handle, pdata, &private_data->resume,
462 FALSE, 2000);
463 ERROR_CHECK(result);
464
465 result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->suspend,
466 FALSE, 80);
467 ERROR_CHECK(result);
468 result = kxtf9_set_ths(mlsl_handle, pdata, &private_data->resume,
469 FALSE, 40);
470 ERROR_CHECK(result);
471
472 result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->suspend,
473 FALSE,
474 MPU_SLAVE_IRQ_TYPE_NONE);
475 ERROR_CHECK(result);
476 result = kxtf9_set_irq(mlsl_handle, pdata, &private_data->resume,
477 FALSE,
478 MPU_SLAVE_IRQ_TYPE_NONE);
479 ERROR_CHECK(result);
480 return result;
481}
482
483static int kxtf9_exit(void *mlsl_handle,
484 struct ext_slave_descr *slave,
485 struct ext_slave_platform_data *pdata)
486{
487 if (pdata->private_data)
488 return MLOSFree(pdata->private_data);
489 else
490 return ML_SUCCESS;
491}
492
493static int kxtf9_config(void *mlsl_handle,
494 struct ext_slave_descr *slave,
495 struct ext_slave_platform_data *pdata,
496 struct ext_slave_config *data)
497{
498 int retval;
499 long odr;
500 struct kxtf9_private_data *private_data = pdata->private_data;
501 if (!data->data)
502 return ML_ERROR_INVALID_PARAMETER;
503
504 switch (data->key) {
505 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
506 return kxtf9_set_odr(mlsl_handle, pdata,
507 &private_data->suspend,
508 data->apply,
509 *((long *)data->data));
510 case MPU_SLAVE_CONFIG_ODR_RESUME:
511 odr = *((long *)data->data);
512 if (odr != 0)
513 private_data->resume.ctrl_reg1 |= 0x80;
514
515 retval = kxtf9_set_odr(mlsl_handle, pdata,
516 &private_data->resume,
517 data->apply,
518 odr);
519 return retval;
520 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
521 return kxtf9_set_fsr(mlsl_handle, pdata,
522 &private_data->suspend,
523 data->apply,
524 *((long *)data->data));
525 case MPU_SLAVE_CONFIG_FSR_RESUME:
526 return kxtf9_set_fsr(mlsl_handle, pdata,
527 &private_data->resume,
528 data->apply,
529 *((long *)data->data));
530 case MPU_SLAVE_CONFIG_MOT_THS:
531 return kxtf9_set_ths(mlsl_handle, pdata,
532 &private_data->suspend,
533 data->apply,
534 *((long *)data->data));
535 case MPU_SLAVE_CONFIG_NMOT_THS:
536 return kxtf9_set_ths(mlsl_handle, pdata,
537 &private_data->resume,
538 data->apply,
539 *((long *)data->data));
540 case MPU_SLAVE_CONFIG_MOT_DUR:
541 return kxtf9_set_dur(mlsl_handle, pdata,
542 &private_data->suspend,
543 data->apply,
544 *((long *)data->data));
545 case MPU_SLAVE_CONFIG_NMOT_DUR:
546 return kxtf9_set_dur(mlsl_handle, pdata,
547 &private_data->resume,
548 data->apply,
549 *((long *)data->data));
550 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
551 return kxtf9_set_irq(mlsl_handle, pdata,
552 &private_data->suspend,
553 data->apply,
554 *((long *)data->data));
555 case MPU_SLAVE_CONFIG_IRQ_RESUME:
556 return kxtf9_set_irq(mlsl_handle, pdata,
557 &private_data->resume,
558 data->apply,
559 *((long *)data->data));
560 default:
561 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
562 };
563
564 return ML_SUCCESS;
565}
566
567static int kxtf9_get_config(void *mlsl_handle,
568 struct ext_slave_descr *slave,
569 struct ext_slave_platform_data *pdata,
570 struct ext_slave_config *data)
571{
572 struct kxtf9_private_data *private_data = pdata->private_data;
573 if (!data->data)
574 return ML_ERROR_INVALID_PARAMETER;
575
576 switch (data->key) {
577 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
578 (*(unsigned long *)data->data) =
579 (unsigned long) private_data->suspend.odr;
580 break;
581 case MPU_SLAVE_CONFIG_ODR_RESUME:
582 (*(unsigned long *)data->data) =
583 (unsigned long) private_data->resume.odr;
584 break;
585 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
586 (*(unsigned long *)data->data) =
587 (unsigned long) private_data->suspend.fsr;
588 break;
589 case MPU_SLAVE_CONFIG_FSR_RESUME:
590 (*(unsigned long *)data->data) =
591 (unsigned long) private_data->resume.fsr;
592 break;
593 case MPU_SLAVE_CONFIG_MOT_THS:
594 (*(unsigned long *)data->data) =
595 (unsigned long) private_data->suspend.ths;
596 break;
597 case MPU_SLAVE_CONFIG_NMOT_THS:
598 (*(unsigned long *)data->data) =
599 (unsigned long) private_data->resume.ths;
600 break;
601 case MPU_SLAVE_CONFIG_MOT_DUR:
602 (*(unsigned long *)data->data) =
603 (unsigned long) private_data->suspend.dur;
604 break;
605 case MPU_SLAVE_CONFIG_NMOT_DUR:
606 (*(unsigned long *)data->data) =
607 (unsigned long) private_data->resume.dur;
608 break;
609 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
610 (*(unsigned long *)data->data) =
611 (unsigned long) private_data->suspend.irq_type;
612 break;
613 case MPU_SLAVE_CONFIG_IRQ_RESUME:
614 (*(unsigned long *)data->data) =
615 (unsigned long) private_data->resume.irq_type;
616 break;
617 default:
618 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
619 };
620
621 return ML_SUCCESS;
622}
623
624static int kxtf9_read(void *mlsl_handle,
625 struct ext_slave_descr *slave,
626 struct ext_slave_platform_data *pdata,
627 unsigned char *data)
628{
629 int result;
630 unsigned char reg;
631 result = MLSLSerialRead(mlsl_handle, pdata->address,
632 KXTF9_INT_SRC_REG2, 1, &reg);
633 ERROR_CHECK(result);
634
635 if (!(reg & 0x10))
636 return ML_ERROR_ACCEL_DATA_NOT_READY;
637
638 result = MLSLSerialRead(mlsl_handle, pdata->address,
639 slave->reg, slave->len, data);
640 ERROR_CHECK(result);
641 return result;
642}
643
644static struct ext_slave_descr kxtf9_descr = {
645 /*.init = */ kxtf9_init,
646 /*.exit = */ kxtf9_exit,
647 /*.suspend = */ kxtf9_suspend,
648 /*.resume = */ kxtf9_resume,
649 /*.read = */ kxtf9_read,
650 /*.config = */ kxtf9_config,
651 /*.get_config = */ kxtf9_get_config,
652 /*.name = */ "kxtf9",
653 /*.type = */ EXT_SLAVE_TYPE_ACCELEROMETER,
654 /*.id = */ ACCEL_ID_KXTF9,
655 /*.reg = */ 0x06,
656 /*.len = */ 6,
657 /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN,
658 /*.range = */ {2, 0},
659};
660
661struct ext_slave_descr *kxtf9_get_slave_descr(void)
662{
663 return &kxtf9_descr;
664}
665EXPORT_SYMBOL(kxtf9_get_slave_descr);
666
667/**
668 * @}
669**/
diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c
new file mode 100644
index 00000000000..b8aed30ba39
--- /dev/null
+++ b/drivers/misc/mpu3050/compass/ak8975.c
@@ -0,0 +1,258 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @defgroup COMPASSDL (Motion Library - Accelerometer Driver Layer)
22 * @brief Provides the interface to setup and handle an accelerometers
23 * connected to the secondary I2C interface of the gyroscope.
24 *
25 * @{
26 * @file AK8975.c
27 * @brief Magnetometer setup and handling methods for AKM 8975 compass.
28 */
29
30/* ------------------ */
31/* - Include Files. - */
32/* ------------------ */
33
34#include <string.h>
35
36#ifdef __KERNEL__
37#include <linux/module.h>
38#endif
39
40#include "mpu.h"
41#include "mlsl.h"
42#include "mlos.h"
43
44#include <log.h>
45#undef MPL_LOG_TAG
46#define MPL_LOG_TAG "MPL-compass"
47
48
49#define AK8975_REG_ST1 (0x02)
50#define AK8975_REG_HXL (0x03)
51#define AK8975_REG_ST2 (0x09)
52
53#define AK8975_REG_CNTL (0x0A)
54
55#define AK8975_CNTL_MODE_POWER_DOWN (0x00)
56#define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x01)
57
58int ak8975_suspend(void *mlsl_handle,
59 struct ext_slave_descr *slave,
60 struct ext_slave_platform_data *pdata)
61{
62 int result = ML_SUCCESS;
63 result =
64 MLSLSerialWriteSingle(mlsl_handle, pdata->address,
65 AK8975_REG_CNTL,
66 AK8975_CNTL_MODE_POWER_DOWN);
67 MLOSSleep(1); /* wait at least 100us */
68 ERROR_CHECK(result);
69 return result;
70}
71
72int ak8975_resume(void *mlsl_handle,
73 struct ext_slave_descr *slave,
74 struct ext_slave_platform_data *pdata)
75{
76 int result = ML_SUCCESS;
77 result =
78 MLSLSerialWriteSingle(mlsl_handle, pdata->address,
79 AK8975_REG_CNTL,
80 AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
81 ERROR_CHECK(result);
82 return result;
83}
84
85int ak8975_read(void *mlsl_handle,
86 struct ext_slave_descr *slave,
87 struct ext_slave_platform_data *pdata, unsigned char *data)
88{
89 unsigned char regs[8];
90 unsigned char *stat = &regs[0];
91 unsigned char *stat2 = &regs[7];
92 int result = ML_SUCCESS;
93 int status = ML_SUCCESS;
94
95 result =
96 MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1,
97 8, regs);
98 ERROR_CHECK(result);
99
100 /*
101 * ST : data ready -
102 * Measurement has been completed and data is ready to be read.
103 */
104 if (*stat & 0x01) {
105 memcpy(data, &regs[1], 6);
106 status = ML_SUCCESS;
107 }
108
109 /*
110 * ST2 : data error -
111 * occurs when data read is started outside of a readable period;
112 * data read would not be correct.
113 * Valid in continuous measurement mode only.
114 * In single measurement mode this error should not occour but we
115 * stil account for it and return an error, since the data would be
116 * corrupted.
117 * DERR bit is self-clearing when ST2 register is read.
118 */
119 if (*stat2 & 0x04)
120 status = ML_ERROR_COMPASS_DATA_ERROR;
121 /*
122 * ST2 : overflow -
123 * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT.
124 * This is likely to happen in presence of an external magnetic
125 * disturbance; it indicates, the sensor data is incorrect and should
126 * be ignored.
127 * An error is returned.
128 * HOFL bit clears when a new measurement starts.
129 */
130 if (*stat2 & 0x08)
131 status = ML_ERROR_COMPASS_DATA_OVERFLOW;
132 /*
133 * ST : overrun -
134 * the previous sample was not fetched and lost.
135 * Valid in continuous measurement mode only.
136 * In single measurement mode this error should not occour and we
137 * don't consider this condition an error.
138 * DOR bit is self-clearing when ST2 or any meas. data register is
139 * read.
140 */
141 if (*stat & 0x02) {
142 /* status = ML_ERROR_COMPASS_DATA_UNDERFLOW; */
143 status = ML_SUCCESS;
144 }
145
146 /*
147 * trigger next measurement if:
148 * - stat is non zero;
149 * - if stat is zero and stat2 is non zero.
150 * Won't trigger if data is not ready and there was no error.
151 */
152 if (*stat != 0x00 || *stat2 != 0x00) {
153 result =
154 MLSLSerialWriteSingle(mlsl_handle, pdata->address,
155 AK8975_REG_CNTL,
156 AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
157 ERROR_CHECK(result);
158 }
159
160 return status;
161}
162
163static int ak8975_config(void *mlsl_handle,
164 struct ext_slave_descr *slave,
165 struct ext_slave_platform_data *pdata,
166 struct ext_slave_config *data)
167{
168 int result;
169 if (!data->data)
170 return ML_ERROR_INVALID_PARAMETER;
171
172 switch (data->key) {
173 case MPU_SLAVE_WRITE_REGISTERS:
174 result = MLSLSerialWrite(mlsl_handle, pdata->address,
175 data->len,
176 (unsigned char *)data->data);
177 ERROR_CHECK(result);
178 break;
179 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
180 case MPU_SLAVE_CONFIG_ODR_RESUME:
181 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
182 case MPU_SLAVE_CONFIG_FSR_RESUME:
183 case MPU_SLAVE_CONFIG_MOT_THS:
184 case MPU_SLAVE_CONFIG_NMOT_THS:
185 case MPU_SLAVE_CONFIG_MOT_DUR:
186 case MPU_SLAVE_CONFIG_NMOT_DUR:
187 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
188 case MPU_SLAVE_CONFIG_IRQ_RESUME:
189 default:
190 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
191 };
192
193 return ML_SUCCESS;
194}
195
196static int ak8975_get_config(void *mlsl_handle,
197 struct ext_slave_descr *slave,
198 struct ext_slave_platform_data *pdata,
199 struct ext_slave_config *data)
200{
201 int result;
202 if (!data->data)
203 return ML_ERROR_INVALID_PARAMETER;
204
205 switch (data->key) {
206 case MPU_SLAVE_READ_REGISTERS:
207 {
208 unsigned char *serial_data = (unsigned char *)data->data;
209 result = MLSLSerialRead(mlsl_handle, pdata->address,
210 serial_data[0],
211 data->len - 1,
212 &serial_data[1]);
213 ERROR_CHECK(result);
214 break;
215 }
216 case MPU_SLAVE_CONFIG_ODR_SUSPEND:
217 case MPU_SLAVE_CONFIG_ODR_RESUME:
218 case MPU_SLAVE_CONFIG_FSR_SUSPEND:
219 case MPU_SLAVE_CONFIG_FSR_RESUME:
220 case MPU_SLAVE_CONFIG_MOT_THS:
221 case MPU_SLAVE_CONFIG_NMOT_THS:
222 case MPU_SLAVE_CONFIG_MOT_DUR:
223 case MPU_SLAVE_CONFIG_NMOT_DUR:
224 case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
225 case MPU_SLAVE_CONFIG_IRQ_RESUME:
226 default:
227 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
228 };
229
230 return ML_SUCCESS;
231}
232
233struct ext_slave_descr ak8975_descr = {
234 /*.init = */ NULL,
235 /*.exit = */ NULL,
236 /*.suspend = */ ak8975_suspend,
237 /*.resume = */ ak8975_resume,
238 /*.read = */ ak8975_read,
239 /*.config = */ ak8975_config,
240 /*.get_config = */ ak8975_get_config,
241 /*.name = */ "ak8975",
242 /*.type = */ EXT_SLAVE_TYPE_COMPASS,
243 /*.id = */ COMPASS_ID_AKM,
244 /*.reg = */ 0x01,
245 /*.len = */ 9,
246 /*.endian = */ EXT_SLAVE_LITTLE_ENDIAN,
247 /*.range = */ {9830, 4000}
248};
249
250struct ext_slave_descr *ak8975_get_slave_descr(void)
251{
252 return &ak8975_descr;
253}
254EXPORT_SYMBOL(ak8975_get_slave_descr);
255
256/**
257 * @}
258 */
diff --git a/drivers/misc/mpu3050/log.h b/drivers/misc/mpu3050/log.h
new file mode 100644
index 00000000000..f2f9ea7ece8
--- /dev/null
+++ b/drivers/misc/mpu3050/log.h
@@ -0,0 +1,306 @@
1/*
2 * Copyright (C) 2010 InvenSense Inc
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * C/C++ logging functions. See the logging documentation for API details.
19 *
20 * We'd like these to be available from C code (in case we import some from
21 * somewhere), so this has a C interface.
22 *
23 * The output will be correct when the log file is shared between multiple
24 * threads and/or multiple processes so long as the operating system
25 * supports O_APPEND. These calls have mutex-protected data structures
26 * and so are NOT reentrant. Do not use MPL_LOG in a signal handler.
27 */
28#ifndef _LIBS_CUTILS_MPL_LOG_H
29#define _LIBS_CUTILS_MPL_LOG_H
30
31#include <stdarg.h>
32
33#ifdef ANDROID
34#include <utils/Log.h> /* For the LOG macro */
35#endif
36
37#ifdef __KERNEL__
38#include <linux/kernel.h>
39#endif
40
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45/* --------------------------------------------------------------------- */
46
47/*
48 * Normally we strip MPL_LOGV (VERBOSE messages) from release builds.
49 * You can modify this (for example with "#define MPL_LOG_NDEBUG 0"
50 * at the top of your source file) to change that behavior.
51 */
52#ifndef MPL_LOG_NDEBUG
53#ifdef NDEBUG
54#define MPL_LOG_NDEBUG 1
55#else
56#define MPL_LOG_NDEBUG 0
57#endif
58#endif
59
60#ifdef __KERNEL__
61#define MPL_LOG_UNKNOWN MPL_LOG_VERBOSE
62#define MPL_LOG_DEFAULT KERN_DEFAULT
63#define MPL_LOG_VERBOSE KERN_CONT
64#define MPL_LOG_DEBUG KERN_NOTICE
65#define MPL_LOG_INFO KERN_INFO
66#define MPL_LOG_WARN KERN_WARNING
67#define MPL_LOG_ERROR KERN_ERR
68#define MPL_LOG_SILENT MPL_LOG_VERBOSE
69
70#else
71 /* Based off the log priorities in android
72 /system/core/include/android/log.h */
73#define MPL_LOG_UNKNOWN (0)
74#define MPL_LOG_DEFAULT (1)
75#define MPL_LOG_VERBOSE (2)
76#define MPL_LOG_DEBUG (3)
77#define MPL_LOG_INFO (4)
78#define MPL_LOG_WARN (5)
79#define MPL_LOG_ERROR (6)
80#define MPL_LOG_SILENT (8)
81#endif
82
83
84/*
85 * This is the local tag used for the following simplified
86 * logging macros. You can change this preprocessor definition
87 * before using the other macros to change the tag.
88 */
89#ifndef MPL_LOG_TAG
90#ifdef __KERNEL__
91#define MPL_LOG_TAG
92#else
93#define MPL_LOG_TAG NULL
94#endif
95#endif
96
97/* --------------------------------------------------------------------- */
98
99/*
100 * Simplified macro to send a verbose log message using the current MPL_LOG_TAG.
101 */
102#ifndef MPL_LOGV
103#if MPL_LOG_NDEBUG
104#define MPL_LOGV(fmt, ...) \
105 do { \
106 if (0) \
107 MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__);\
108 } while (0)
109#else
110#define MPL_LOGV(fmt, ...) MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__)
111#endif
112#endif
113
114#ifndef CONDITION
115#define CONDITION(cond) ((cond) != 0)
116#endif
117
118#ifndef MPL_LOGV_IF
119#if MPL_LOG_NDEBUG
120#define MPL_LOGV_IF(cond, fmt, ...) \
121 do { if (0) MPL_LOG(fmt, ##__VA_ARGS__); } while (0)
122#else
123#define MPL_LOGV_IF(cond, fmt, ...) \
124 ((CONDITION(cond)) \
125 ? MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \
126 : (void)0)
127#endif
128#endif
129
130/*
131 * Simplified macro to send a debug log message using the current MPL_LOG_TAG.
132 */
133#ifndef MPL_LOGD
134#define MPL_LOGD(fmt, ...) MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__)
135#endif
136
137#ifndef MPL_LOGD_IF
138#define MPL_LOGD_IF(cond, fmt, ...) \
139 ((CONDITION(cond)) \
140 ? MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \
141 : (void)0)
142#endif
143
144/*
145 * Simplified macro to send an info log message using the current MPL_LOG_TAG.
146 */
147#ifndef MPL_LOGI
148#define MPL_LOGI(fmt, ...) MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__)
149#endif
150
151#ifndef MPL_LOGI_IF
152#define MPL_LOGI_IF(cond, fmt, ...) \
153 ((CONDITION(cond)) \
154 ? MPL_LOG(LOG_INFO, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \
155 : (void)0)
156#endif
157
158/*
159 * Simplified macro to send a warning log message using the current MPL_LOG_TAG.
160 */
161#ifndef MPL_LOGW
162#ifdef __KERNEL__
163#define MPL_LOGW(fmt, ...) printk(KERN_WARNING MPL_LOG_TAG fmt, ##__VA_ARGS__)
164#else
165#define MPL_LOGW(fmt, ...) MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__)
166#endif
167#endif
168
169#ifndef MPL_LOGW_IF
170#define MPL_LOGW_IF(cond, fmt, ...) \
171 ((CONDITION(cond)) \
172 ? MPL_LOG(LOG_WARN, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \
173 : (void)0)
174#endif
175
176/*
177 * Simplified macro to send an error log message using the current MPL_LOG_TAG.
178 */
179#ifndef MPL_LOGE
180#ifdef __KERNEL__
181#define MPL_LOGE(fmt, ...) printk(KERN_ERR MPL_LOG_TAG fmt, ##__VA_ARGS__)
182#else
183#define MPL_LOGE(fmt, ...) MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__VA_ARGS__)
184#endif
185#endif
186
187#ifndef MPL_LOGE_IF
188#define MPL_LOGE_IF(cond, fmt, ...) \
189 ((CONDITION(cond)) \
190 ? MPL_LOG(LOG_ERROR, MPL_LOG_TAG, fmt, ##__VA_ARGS__) \
191 : (void)0)
192#endif
193
194/* --------------------------------------------------------------------- */
195
196/*
197 * Log a fatal error. If the given condition fails, this stops program
198 * execution like a normal assertion, but also generating the given message.
199 * It is NOT stripped from release builds. Note that the condition test
200 * is -inverted- from the normal assert() semantics.
201 */
202#define MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ...) \
203 ((CONDITION(cond)) \
204 ? ((void)android_printAssert(#cond, MPL_LOG_TAG, \
205 fmt, ##__VA_ARGS__)) \
206 : (void)0)
207
208#define MPL_LOG_ALWAYS_FATAL(fmt, ...) \
209 (((void)android_printAssert(NULL, MPL_LOG_TAG, fmt, ##__VA_ARGS__)))
210
211/*
212 * Versions of MPL_LOG_ALWAYS_FATAL_IF and MPL_LOG_ALWAYS_FATAL that
213 * are stripped out of release builds.
214 */
215#if MPL_LOG_NDEBUG
216#define MPL_LOG_FATAL_IF(cond, fmt, ...) \
217 do { \
218 if (0) \
219 MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__); \
220 } while (0)
221#define MPL_LOG_FATAL(fmt, ...) \
222 do { \
223 if (0) \
224 MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__) \
225 } while (0)
226#else
227#define MPL_LOG_FATAL_IF(cond, fmt, ...) \
228 MPL_LOG_ALWAYS_FATAL_IF(cond, fmt, ##__VA_ARGS__)
229#define MPL_LOG_FATAL(fmt, ...) \
230 MPL_LOG_ALWAYS_FATAL(fmt, ##__VA_ARGS__)
231#endif
232
233/*
234 * Assertion that generates a log message when the assertion fails.
235 * Stripped out of release builds. Uses the current MPL_LOG_TAG.
236 */
237#define MPL_LOG_ASSERT(cond, fmt, ...) \
238 MPL_LOG_FATAL_IF(!(cond), fmt, ##__VA_ARGS__)
239
240/* --------------------------------------------------------------------- */
241
242/*
243 * Basic log message macro.
244 *
245 * Example:
246 * MPL_LOG(MPL_LOG_WARN, NULL, "Failed with error %d", errno);
247 *
248 * The second argument may be NULL or "" to indicate the "global" tag.
249 */
250#ifndef MPL_LOG
251#define MPL_LOG(priority, tag, fmt, ...) \
252 MPL_LOG_PRI(priority, tag, fmt, ##__VA_ARGS__)
253#endif
254
255/*
256 * Log macro that allows you to specify a number for the priority.
257 */
258#ifndef MPL_LOG_PRI
259#ifdef ANDROID
260#define MPL_LOG_PRI(priority, tag, fmt, ...) \
261 LOG(priority, tag, fmt, ##__VA_ARGS__)
262#elif defined __KERNEL__
263#define MPL_LOG_PRI(priority, tag, fmt, ...) \
264 pr_debug(MPL_##priority tag fmt, ##__VA_ARGS__)
265#else
266#define MPL_LOG_PRI(priority, tag, fmt, ...) \
267 _MLPrintLog(MPL_##priority, tag, fmt, ##__VA_ARGS__)
268#endif
269#endif
270
271/*
272 * Log macro that allows you to pass in a varargs ("args" is a va_list).
273 */
274#ifndef MPL_LOG_PRI_VA
275#ifdef ANDROID
276#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
277 android_vprintLog(priority, NULL, tag, fmt, args)
278#elif defined __KERNEL__
279/* not allowed in the Kernel because there is no dev_dbg that takes a va_list */
280#else
281#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
282 _MLPrintVaLog(priority, NULL, tag, fmt, args)
283#endif
284#endif
285
286/* --------------------------------------------------------------------- */
287
288/*
289 * ===========================================================================
290 *
291 * The stuff in the rest of this file should not be used directly.
292 */
293
294#ifndef ANDROID
295 int _MLPrintLog(int priority, const char *tag, const char *fmt,
296 ...);
297 int _MLPrintVaLog(int priority, const char *tag, const char *fmt,
298 va_list args);
299/* Final implementation of actual writing to a character device */
300 int _MLWriteLog(const char *buf, int buflen);
301#endif
302
303#ifdef __cplusplus
304}
305#endif
306#endif /* _LIBS_CUTILS_MPL_LOG_H */
diff --git a/drivers/misc/mpu3050/mldl_cfg.c b/drivers/misc/mpu3050/mldl_cfg.c
new file mode 100644
index 00000000000..9cc4cf69038
--- /dev/null
+++ b/drivers/misc/mpu3050/mldl_cfg.c
@@ -0,0 +1,1739 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup MLDL
22 *
23 * @{
24 * @file mldl_cfg.c
25 * @brief The Motion Library Driver Layer.
26 */
27
28/* ------------------ */
29/* - Include Files. - */
30/* ------------------ */
31
32#include <stddef.h>
33
34#include "mldl_cfg.h"
35#include "mpu.h"
36
37#include "mlsl.h"
38#include "mlos.h"
39
40#include "log.h"
41#undef MPL_LOG_TAG
42#define MPL_LOG_TAG "mldl_cfg:"
43
44/* --------------------- */
45/* - Variables. - */
46/* --------------------- */
47#ifdef M_HW
48#define SLEEP 0
49#define WAKE_UP 7
50#define RESET 1
51#define STANDBY 1
52#else
53/* licteral significance of all parameters used in MLDLPowerMgmtMPU */
54#define SLEEP 1
55#define WAKE_UP 0
56#define RESET 1
57#define STANDBY 1
58#endif
59
60/*---------------------*/
61/*- Prototypes. -*/
62/*---------------------*/
63
64/*----------------------*/
65/*- Static Functions. -*/
66/*----------------------*/
67
68static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle)
69{
70 unsigned char userCtrlReg;
71 int result;
72
73 if (!mldl_cfg->dmp_is_running)
74 return ML_SUCCESS;
75
76 result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
77 MPUREG_USER_CTRL, 1, &userCtrlReg);
78 ERROR_CHECK(result);
79 userCtrlReg = (userCtrlReg & (~BIT_FIFO_EN)) | BIT_FIFO_RST;
80 userCtrlReg = (userCtrlReg & (~BIT_DMP_EN)) | BIT_DMP_RST;
81
82 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
83 MPUREG_USER_CTRL, userCtrlReg);
84 ERROR_CHECK(result);
85 mldl_cfg->dmp_is_running = 0;
86
87 return result;
88
89}
90/**
91 * @brief Starts the DMP running
92 *
93 * @return ML_SUCCESS or non-zero error code
94 */
95static int dmp_start(struct mldl_cfg *pdata, void *mlsl_handle)
96{
97 unsigned char userCtrlReg;
98 int result;
99
100 if (pdata->dmp_is_running == pdata->dmp_enable)
101 return ML_SUCCESS;
102
103 result = MLSLSerialRead(mlsl_handle, pdata->addr,
104 MPUREG_USER_CTRL, 1, &userCtrlReg);
105 ERROR_CHECK(result);
106
107 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
108 MPUREG_USER_CTRL,
109 ((userCtrlReg & (~BIT_FIFO_EN))
110 | BIT_FIFO_RST));
111 ERROR_CHECK(result);
112
113 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
114 MPUREG_USER_CTRL, userCtrlReg);
115 ERROR_CHECK(result);
116
117 result = MLSLSerialRead(mlsl_handle, pdata->addr,
118 MPUREG_USER_CTRL, 1, &userCtrlReg);
119 ERROR_CHECK(result);
120
121 if (pdata->dmp_enable)
122 userCtrlReg |= BIT_DMP_EN;
123 else
124 userCtrlReg &= ~BIT_DMP_EN;
125
126 if (pdata->fifo_enable)
127 userCtrlReg |= BIT_FIFO_EN;
128 else
129 userCtrlReg &= ~BIT_FIFO_EN;
130
131 userCtrlReg |= BIT_DMP_RST;
132
133 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
134 MPUREG_USER_CTRL, userCtrlReg);
135 ERROR_CHECK(result);
136 pdata->dmp_is_running = pdata->dmp_enable;
137
138 return result;
139}
140
141/**
142 * @brief enables/disables the I2C bypass to an external device
143 * connected to MPU's secondary I2C bus.
144 * @param enable
145 * Non-zero to enable pass through.
146 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
147 */
148static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg,
149 void *mlsl_handle,
150 unsigned char enable)
151{
152 unsigned char b;
153 int result;
154
155 if ((mldl_cfg->gyro_is_bypassed && enable) ||
156 (!mldl_cfg->gyro_is_bypassed && !enable))
157 return ML_SUCCESS;
158
159 /*---- get current 'USER_CTRL' into b ----*/
160 result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
161 MPUREG_USER_CTRL, 1, &b);
162 ERROR_CHECK(result);
163
164 b &= ~BIT_AUX_IF_EN;
165
166 if (!enable) {
167 result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
168 MPUREG_USER_CTRL,
169 (b | BIT_AUX_IF_EN));
170 ERROR_CHECK(result);
171 } else {
172 /* Coming out of I2C is tricky due to several erratta. Do not
173 * modify this algorithm
174 */
175 /*
176 * 1) wait for the right time and send the command to change
177 * the aux i2c slave address to an invalid address that will
178 * get nack'ed
179 *
180 * 0x00 is broadcast. 0x7F is unlikely to be used by any aux.
181 */
182 result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
183 MPUREG_AUX_SLV_ADDR, 0x7F);
184 ERROR_CHECK(result);
185 /*
186 * 2) wait enough time for a nack to occur, then go into
187 * bypass mode:
188 */
189 MLOSSleep(2);
190 result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
191 MPUREG_USER_CTRL, (b));
192 ERROR_CHECK(result);
193 /*
194 * 3) wait for up to one MPU cycle then restore the slave
195 * address
196 */
197 MLOSSleep(SAMPLING_PERIOD_US(mldl_cfg) / 1000);
198 result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
199 MPUREG_AUX_SLV_ADDR,
200 mldl_cfg->pdata->
201 accel.address);
202 ERROR_CHECK(result);
203
204 /*
205 * 4) reset the ime interface
206 */
207#ifdef M_HW
208 result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
209 MPUREG_USER_CTRL,
210 (b | BIT_I2C_MST_RST));
211
212#else
213 result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
214 MPUREG_USER_CTRL,
215 (b | BIT_AUX_IF_RST));
216#endif
217 ERROR_CHECK(result);
218 MLOSSleep(2);
219 }
220 mldl_cfg->gyro_is_bypassed = enable;
221
222 return result;
223}
224
225struct tsProdRevMap {
226 unsigned char siliconRev;
227 unsigned short sensTrim;
228};
229
230#define NUM_OF_PROD_REVS (DIM(prodRevsMap))
231
232/* NOTE : 'npp' is a non production part */
233#ifdef M_HW
234#define OLDEST_PROD_REV_SUPPORTED 1
235static struct tsProdRevMap prodRevsMap[] = {
236 {0, 0},
237 {MPU_SILICON_REV_A1, 131}, /* 1 A1 (npp) */
238 {MPU_SILICON_REV_A1, 131}, /* 2 A1 (npp) */
239 {MPU_SILICON_REV_A1, 131}, /* 3 A1 (npp) */
240 {MPU_SILICON_REV_A1, 131}, /* 4 A1 (npp) */
241 {MPU_SILICON_REV_A1, 131}, /* 5 A1 (npp) */
242 {MPU_SILICON_REV_A1, 131}, /* 6 A1 (npp) */
243 {MPU_SILICON_REV_A1, 131}, /* 7 A1 (npp) */
244 {MPU_SILICON_REV_A1, 131}, /* 8 A1 (npp) */
245};
246
247#else /* !M_HW */
248#define OLDEST_PROD_REV_SUPPORTED 11
249
250static struct tsProdRevMap prodRevsMap[] = {
251 {0, 0},
252 {MPU_SILICON_REV_A4, 131}, /* 1 A? OBSOLETED */
253 {MPU_SILICON_REV_A4, 131}, /* 2 | */
254 {MPU_SILICON_REV_A4, 131}, /* 3 V */
255 {MPU_SILICON_REV_A4, 131}, /* 4 */
256 {MPU_SILICON_REV_A4, 131}, /* 5 */
257 {MPU_SILICON_REV_A4, 131}, /* 6 */
258 {MPU_SILICON_REV_A4, 131}, /* 7 */
259 {MPU_SILICON_REV_A4, 131}, /* 8 */
260 {MPU_SILICON_REV_A4, 131}, /* 9 */
261 {MPU_SILICON_REV_A4, 131}, /* 10 */
262 {MPU_SILICON_REV_B1, 131}, /* 11 B1 */
263 {MPU_SILICON_REV_B1, 131}, /* 12 | */
264 {MPU_SILICON_REV_B1, 131}, /* 13 V */
265 {MPU_SILICON_REV_B1, 131}, /* 14 B4 */
266 {MPU_SILICON_REV_B4, 131}, /* 15 | */
267 {MPU_SILICON_REV_B4, 131}, /* 16 V */
268 {MPU_SILICON_REV_B4, 131}, /* 17 */
269 {MPU_SILICON_REV_B4, 131}, /* 18 */
270 {MPU_SILICON_REV_B4, 115}, /* 19 */
271 {MPU_SILICON_REV_B4, 115}, /* 20 */
272 {MPU_SILICON_REV_B6, 131}, /* 21 B6 (B6/A9) */
273 {MPU_SILICON_REV_B4, 115}, /* 22 B4 (B7/A10) */
274 {MPU_SILICON_REV_B6, 0}, /* 23 B6 (npp) */
275 {MPU_SILICON_REV_B6, 0}, /* 24 | (npp) */
276 {MPU_SILICON_REV_B6, 0}, /* 25 V (npp) */
277 {MPU_SILICON_REV_B6, 131}, /* 26 (B6/A11) */
278};
279#endif /* !M_HW */
280
281/**
282 * @internal
283 * @brief Get the silicon revision ID from OTP.
284 * The silicon revision number is in read from OTP bank 0,
285 * ADDR6[7:2]. The corresponding ID is retrieved by lookup
286 * in a map.
287 * @return The silicon revision ID (0 on error).
288 */
289static int MLDLGetSiliconRev(struct mldl_cfg *pdata,
290 void *mlsl_handle)
291{
292 int result;
293 unsigned char index = 0x00;
294 unsigned char bank =
295 (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0);
296 unsigned short memAddr = ((bank << 8) | 0x06);
297
298 result = MLSLSerialReadMem(mlsl_handle, pdata->addr,
299 memAddr, 1, &index);
300 ERROR_CHECK(result);
301 if (result)
302 return result;
303 index >>= 2;
304
305 /* clean the prefetch and cfg user bank bits */
306 result =
307 MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
308 MPUREG_BANK_SEL, 0);
309 ERROR_CHECK(result);
310 if (result)
311 return result;
312
313 if (index < OLDEST_PROD_REV_SUPPORTED || NUM_OF_PROD_REVS <= index) {
314 pdata->silicon_revision = 0;
315 pdata->trim = 0;
316 MPL_LOGE("Unsupported Product Revision Detected : %d\n", index);
317 return ML_ERROR_INVALID_MODULE;
318 }
319
320 pdata->silicon_revision = prodRevsMap[index].siliconRev;
321 pdata->trim = prodRevsMap[index].sensTrim;
322
323 if (pdata->trim == 0) {
324 MPL_LOGE("sensitivity trim is 0"
325 " - unsupported non production part.\n");
326 return ML_ERROR_INVALID_MODULE;
327 }
328
329 return result;
330}
331
332/**
333 * @brief Enable / Disable the use MPU's secondary I2C interface level
334 * shifters.
335 * When enabled the secondary I2C interface to which the external
336 * device is connected runs at VDD voltage (main supply).
337 * When disabled the 2nd interface runs at VDDIO voltage.
338 * See the device specification for more details.
339 *
340 * @note using this API may produce unpredictable results, depending on how
341 * the MPU and slave device are setup on the target platform.
342 * Use of this API should entirely be restricted to system
343 * integrators. Once the correct value is found, there should be no
344 * need to change the level shifter at runtime.
345 *
346 * @pre Must be called after MLSerialOpen().
347 * @note Typically called before MLDmpOpen().
348 *
349 * @param[in] enable:
350 * 0 to run at VDDIO (default),
351 * 1 to run at VDD.
352 *
353 * @return ML_SUCCESS if successfull, a non-zero error code otherwise.
354 */
355static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata,
356 void *mlsl_handle,
357 unsigned char enable)
358{
359#ifndef M_HW
360 int result;
361 unsigned char reg;
362 unsigned char mask;
363 unsigned char regval;
364
365 if (0 == pdata->silicon_revision)
366 return ML_ERROR_INVALID_PARAMETER;
367
368 /*-- on parts before B6 the VDDIO bit is bit 7 of ACCEL_BURST_ADDR --
369 NOTE: this is incompatible with ST accelerometers where the VDDIO
370 bit MUST be set to enable ST's internal logic to autoincrement
371 the register address on burst reads --*/
372 if ((pdata->silicon_revision & 0xf) < MPU_SILICON_REV_B6) {
373 reg = MPUREG_ACCEL_BURST_ADDR;
374 mask = 0x80;
375 } else {
376 /*-- on B6 parts the VDDIO bit was moved to FIFO_EN2 =>
377 the mask is always 0x04 --*/
378 reg = MPUREG_FIFO_EN2;
379 mask = 0x04;
380 }
381
382 result = MLSLSerialRead(mlsl_handle, pdata->addr, reg, 1, &regval);
383 if (result)
384 return result;
385
386 if (enable)
387 regval |= mask;
388 else
389 regval &= ~mask;
390
391 result =
392 MLSLSerialWriteSingle(mlsl_handle, pdata->addr, reg, regval);
393
394 return result;
395#else
396 return ML_SUCCESS;
397#endif
398}
399
400
401#ifdef M_HW
402/**
403 * @internal
404 * @param reset 1 to reset hardware
405 */
406static tMLError mpu60xx_pwr_mgmt(struct mldl_cfg *pdata,
407 void *mlsl_handle,
408 unsigned char reset,
409 unsigned char powerselection)
410{
411 unsigned char b;
412 tMLError result;
413
414 if (powerselection < 0 || powerselection > 7)
415 return ML_ERROR_INVALID_PARAMETER;
416
417 result =
418 MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_1, 1,
419 &b);
420 ERROR_CHECK(result);
421
422 b &= ~(BITS_PWRSEL);
423
424 if (reset) {
425 /* Current sillicon has an errata where the reset will get
426 * nacked. Ignore the error code for now. */
427 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
428 MPUREG_PWR_MGM, b | BIT_H_RESET);
429#define M_HW_RESET_ERRATTA
430#ifndef M_HW_RESET_ERRATTA
431 ERROR_CHECK(result);
432#else
433 MLOSSleep(50);
434#endif
435 }
436
437 b |= (powerselection << 4);
438
439 if (b & BITS_PWRSEL)
440 pdata->gyro_is_suspended = FALSE;
441 else
442 pdata->gyro_is_suspended = TRUE;
443
444 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
445 MPUREG_PWR_MGM, b);
446 ERROR_CHECK(result);
447
448 return ML_SUCCESS;
449}
450
451/**
452 * @internal
453 */
454static tMLError MLDLStandByGyros(struct mldl_cfg *pdata,
455 void *mlsl_handle,
456 unsigned char disable_gx,
457 unsigned char disable_gy,
458 unsigned char disable_gz)
459{
460 unsigned char b;
461 tMLError result;
462
463 result =
464 MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1,
465 &b);
466 ERROR_CHECK(result);
467
468 b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
469 b |= (disable_gx << 2 | disable_gy << 1 | disable_gz);
470
471 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
472 MPUREG_PWR_MGMT_2, b);
473 ERROR_CHECK(result);
474
475 return ML_SUCCESS;
476}
477
478/**
479 * @internal
480 */
481static tMLError MLDLStandByAccels(struct mldl_cfg *pdata,
482 void *mlsl_handle,
483 unsigned char disable_ax,
484 unsigned char disable_ay,
485 unsigned char disable_az)
486{
487 unsigned char b;
488 tMLError result;
489
490 result =
491 MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1,
492 &b);
493 ERROR_CHECK(result);
494
495 b &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
496 b |= (disable_ax << 2 | disable_ay << 1 | disable_az);
497
498 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
499 MPUREG_PWR_MGMT_2, b);
500 ERROR_CHECK(result);
501
502 return ML_SUCCESS;
503}
504
505#else /* ! M_HW */
506
507/**
508 * @internal
509 * @brief This function controls the power management on the MPU device.
510 * The entire chip can be put to low power sleep mode, or individual
511 * gyros can be turned on/off.
512 *
513 * Putting the device into sleep mode depending upon the changing needs
514 * of the associated applications is a recommended method for reducing
515 * power consuption. It is a safe opearation in that sleep/wake up of
516 * gyros while running will not result in any interruption of data.
517 *
518 * Although it is entirely allowed to put the device into full sleep
519 * while running the DMP, it is not recomended because it will disrupt
520 * the ongoing calculations carried on inside the DMP and consequently
521 * the sensor fusion algorithm. Furthermore, while in sleep mode
522 * read & write operation from the app processor on both registers and
523 * memory are disabled and can only regained by restoring the MPU in
524 * normal power mode.
525 * Disabling any of the gyro axis will reduce the associated power
526 * consuption from the PLL but will not stop the DMP from running
527 * state.
528 *
529 * @param reset
530 * Non-zero to reset the device. Note that this setting
531 * is volatile and the corresponding register bit will
532 * clear itself right after being applied.
533 * @param sleep
534 * Non-zero to put device into full sleep.
535 * @param disable_gx
536 * Non-zero to disable gyro X.
537 * @param disable_gy
538 * Non-zero to disable gyro Y.
539 * @param disable_gz
540 * Non-zero to disable gyro Z.
541 *
542 * @return ML_SUCCESS if successfull; a non-zero error code otherwise.
543 */
544static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata,
545 void *mlsl_handle,
546 unsigned char reset,
547 unsigned char sleep,
548 unsigned char disable_gx,
549 unsigned char disable_gy,
550 unsigned char disable_gz)
551{
552 unsigned char b;
553 int result;
554
555 result =
556 MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1,
557 &b);
558 ERROR_CHECK(result);
559
560 /* If we are awake, we need to put it in bypass before resetting */
561 if ((!(b & BIT_SLEEP)) && reset)
562 result = MLDLSetI2CBypass(pdata, mlsl_handle, 1);
563
564 /* If we are awake, we need stop the dmp sleeping */
565 if ((!(b & BIT_SLEEP)) && sleep)
566 dmp_stop(pdata, mlsl_handle);
567
568 /* Reset if requested */
569 if (reset) {
570 MPL_LOGV("Reset MPU3050\n");
571 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
572 MPUREG_PWR_MGM, b | BIT_H_RESET);
573 ERROR_CHECK(result);
574 MLOSSleep(5);
575 pdata->gyro_needs_reset = FALSE;
576 /* Some chips are awake after reset and some are asleep,
577 * check the status */
578 result = MLSLSerialRead(mlsl_handle, pdata->addr,
579 MPUREG_PWR_MGM, 1, &b);
580 ERROR_CHECK(result);
581 }
582
583 /* Update the suspended state just in case we return early */
584 if (b & BIT_SLEEP)
585 pdata->gyro_is_suspended = TRUE;
586 else
587 pdata->gyro_is_suspended = FALSE;
588
589 /* if power status match requested, nothing else's left to do */
590 if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
591 (((sleep != 0) * BIT_SLEEP) |
592 ((disable_gx != 0) * BIT_STBY_XG) |
593 ((disable_gy != 0) * BIT_STBY_YG) |
594 ((disable_gz != 0) * BIT_STBY_ZG))) {
595 return ML_SUCCESS;
596 }
597
598 /*
599 * This specific transition between states needs to be reinterpreted:
600 * (1,1,1,1) -> (0,1,1,1) has to become
601 * (1,1,1,1) -> (1,0,0,0) -> (0,1,1,1)
602 * where
603 * (1,1,1,1) is (sleep=1,disable_gx=1,disable_gy=1,disable_gz=1)
604 */
605 if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
606 (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)
607 && ((!sleep) && disable_gx && disable_gy && disable_gz)) {
608 result = MLDLPowerMgmtMPU(pdata, mlsl_handle, 0, 1, 0, 0, 0);
609 if (result)
610 return result;
611 b |= BIT_SLEEP;
612 b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
613 }
614
615 if ((b & BIT_SLEEP) != ((sleep != 0) * BIT_SLEEP)) {
616 if (sleep) {
617 result = MLDLSetI2CBypass(pdata, mlsl_handle, 1);
618 ERROR_CHECK(result);
619 b |= BIT_SLEEP;
620 result =
621 MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
622 MPUREG_PWR_MGM, b);
623 ERROR_CHECK(result);
624 pdata->gyro_is_suspended = TRUE;
625 } else {
626 b &= ~BIT_SLEEP;
627 result =
628 MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
629 MPUREG_PWR_MGM, b);
630 ERROR_CHECK(result);
631 pdata->gyro_is_suspended = FALSE;
632 MLOSSleep(5);
633 }
634 }
635 /*---
636 WORKAROUND FOR PUTTING GYRO AXIS in STAND-BY MODE
637 1) put one axis at a time in stand-by
638 ---*/
639 if ((b & BIT_STBY_XG) != ((disable_gx != 0) * BIT_STBY_XG)) {
640 b ^= BIT_STBY_XG;
641 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
642 MPUREG_PWR_MGM, b);
643 ERROR_CHECK(result);
644 }
645 if ((b & BIT_STBY_YG) != ((disable_gy != 0) * BIT_STBY_YG)) {
646 b ^= BIT_STBY_YG;
647 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
648 MPUREG_PWR_MGM, b);
649 ERROR_CHECK(result);
650 }
651 if ((b & BIT_STBY_ZG) != ((disable_gz != 0) * BIT_STBY_ZG)) {
652 b ^= BIT_STBY_ZG;
653 result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
654 MPUREG_PWR_MGM, b);
655 ERROR_CHECK(result);
656 }
657
658 return ML_SUCCESS;
659}
660#endif /* M_HW */
661
662
663void mpu_print_cfg(struct mldl_cfg *mldl_cfg)
664{
665 struct mpu3050_platform_data *pdata = mldl_cfg->pdata;
666 struct ext_slave_platform_data *accel = &mldl_cfg->pdata->accel;
667 struct ext_slave_platform_data *compass =
668 &mldl_cfg->pdata->compass;
669 struct ext_slave_platform_data *pressure =
670 &mldl_cfg->pdata->pressure;
671
672 MPL_LOGD("mldl_cfg.addr = %02x\n", mldl_cfg->addr);
673 MPL_LOGD("mldl_cfg.int_config = %02x\n",
674 mldl_cfg->int_config);
675 MPL_LOGD("mldl_cfg.ext_sync = %02x\n", mldl_cfg->ext_sync);
676 MPL_LOGD("mldl_cfg.full_scale = %02x\n",
677 mldl_cfg->full_scale);
678 MPL_LOGD("mldl_cfg.lpf = %02x\n", mldl_cfg->lpf);
679 MPL_LOGD("mldl_cfg.clk_src = %02x\n", mldl_cfg->clk_src);
680 MPL_LOGD("mldl_cfg.divider = %02x\n", mldl_cfg->divider);
681 MPL_LOGD("mldl_cfg.dmp_enable = %02x\n",
682 mldl_cfg->dmp_enable);
683 MPL_LOGD("mldl_cfg.fifo_enable = %02x\n",
684 mldl_cfg->fifo_enable);
685 MPL_LOGD("mldl_cfg.dmp_cfg1 = %02x\n", mldl_cfg->dmp_cfg1);
686 MPL_LOGD("mldl_cfg.dmp_cfg2 = %02x\n", mldl_cfg->dmp_cfg2);
687 MPL_LOGD("mldl_cfg.offset_tc[0] = %02x\n",
688 mldl_cfg->offset_tc[0]);
689 MPL_LOGD("mldl_cfg.offset_tc[1] = %02x\n",
690 mldl_cfg->offset_tc[1]);
691 MPL_LOGD("mldl_cfg.offset_tc[2] = %02x\n",
692 mldl_cfg->offset_tc[2]);
693 MPL_LOGD("mldl_cfg.silicon_revision = %02x\n",
694 mldl_cfg->silicon_revision);
695 MPL_LOGD("mldl_cfg.product_id = %02x\n",
696 mldl_cfg->product_id);
697 MPL_LOGD("mldl_cfg.trim = %02x\n", mldl_cfg->trim);
698 MPL_LOGD("mldl_cfg.requested_sensors= %04lx\n",
699 mldl_cfg->requested_sensors);
700
701 if (mldl_cfg->accel) {
702 MPL_LOGD("slave_accel->suspend = %02x\n",
703 (int) mldl_cfg->accel->suspend);
704 MPL_LOGD("slave_accel->resume = %02x\n",
705 (int) mldl_cfg->accel->resume);
706 MPL_LOGD("slave_accel->read = %02x\n",
707 (int) mldl_cfg->accel->read);
708 MPL_LOGD("slave_accel->type = %02x\n",
709 mldl_cfg->accel->type);
710 MPL_LOGD("slave_accel->reg = %02x\n",
711 mldl_cfg->accel->reg);
712 MPL_LOGD("slave_accel->len = %02x\n",
713 mldl_cfg->accel->len);
714 MPL_LOGD("slave_accel->endian = %02x\n",
715 mldl_cfg->accel->endian);
716 MPL_LOGD("slave_accel->range.mantissa= %02lx\n",
717 mldl_cfg->accel->range.mantissa);
718 MPL_LOGD("slave_accel->range.fraction= %02lx\n",
719 mldl_cfg->accel->range.fraction);
720 } else {
721 MPL_LOGD("slave_accel = NULL\n");
722 }
723
724 if (mldl_cfg->compass) {
725 MPL_LOGD("slave_compass->suspend = %02x\n",
726 (int) mldl_cfg->compass->suspend);
727 MPL_LOGD("slave_compass->resume = %02x\n",
728 (int) mldl_cfg->compass->resume);
729 MPL_LOGD("slave_compass->read = %02x\n",
730 (int) mldl_cfg->compass->read);
731 MPL_LOGD("slave_compass->type = %02x\n",
732 mldl_cfg->compass->type);
733 MPL_LOGD("slave_compass->reg = %02x\n",
734 mldl_cfg->compass->reg);
735 MPL_LOGD("slave_compass->len = %02x\n",
736 mldl_cfg->compass->len);
737 MPL_LOGD("slave_compass->endian = %02x\n",
738 mldl_cfg->compass->endian);
739 MPL_LOGD("slave_compass->range.mantissa= %02lx\n",
740 mldl_cfg->compass->range.mantissa);
741 MPL_LOGD("slave_compass->range.fraction= %02lx\n",
742 mldl_cfg->compass->range.fraction);
743
744 } else {
745 MPL_LOGD("slave_compass = NULL\n");
746 }
747
748 if (mldl_cfg->pressure) {
749 MPL_LOGD("slave_pressure->suspend = %02x\n",
750 (int) mldl_cfg->pressure->suspend);
751 MPL_LOGD("slave_pressure->resume = %02x\n",
752 (int) mldl_cfg->pressure->resume);
753 MPL_LOGD("slave_pressure->read = %02x\n",
754 (int) mldl_cfg->pressure->read);
755 MPL_LOGD("slave_pressure->type = %02x\n",
756 mldl_cfg->pressure->type);
757 MPL_LOGD("slave_pressure->reg = %02x\n",
758 mldl_cfg->pressure->reg);
759 MPL_LOGD("slave_pressure->len = %02x\n",
760 mldl_cfg->pressure->len);
761 MPL_LOGD("slave_pressure->endian = %02x\n",
762 mldl_cfg->pressure->endian);
763 MPL_LOGD("slave_pressure->range.mantissa= %02lx\n",
764 mldl_cfg->pressure->range.mantissa);
765 MPL_LOGD("slave_pressure->range.fraction= %02lx\n",
766 mldl_cfg->pressure->range.fraction);
767
768 } else {
769 MPL_LOGD("slave_pressure = NULL\n");
770 }
771 MPL_LOGD("accel->get_slave_descr = %x\n",
772 (unsigned int) accel->get_slave_descr);
773 MPL_LOGD("accel->irq = %02x\n", accel->irq);
774 MPL_LOGD("accel->adapt_num = %02x\n", accel->adapt_num);
775 MPL_LOGD("accel->bus = %02x\n", accel->bus);
776 MPL_LOGD("accel->address = %02x\n", accel->address);
777 MPL_LOGD("accel->orientation =\n"
778 " %2d %2d %2d\n"
779 " %2d %2d %2d\n"
780 " %2d %2d %2d\n",
781 accel->orientation[0], accel->orientation[1],
782 accel->orientation[2], accel->orientation[3],
783 accel->orientation[4], accel->orientation[5],
784 accel->orientation[6], accel->orientation[7],
785 accel->orientation[8]);
786 MPL_LOGD("compass->get_slave_descr = %x\n",
787 (unsigned int) compass->get_slave_descr);
788 MPL_LOGD("compass->irq = %02x\n", compass->irq);
789 MPL_LOGD("compass->adapt_num = %02x\n", compass->adapt_num);
790 MPL_LOGD("compass->bus = %02x\n", compass->bus);
791 MPL_LOGD("compass->address = %02x\n", compass->address);
792 MPL_LOGD("compass->orientation =\n"
793 " %2d %2d %2d\n"
794 " %2d %2d %2d\n"
795 " %2d %2d %2d\n",
796 compass->orientation[0], compass->orientation[1],
797 compass->orientation[2], compass->orientation[3],
798 compass->orientation[4], compass->orientation[5],
799 compass->orientation[6], compass->orientation[7],
800 compass->orientation[8]);
801 MPL_LOGD("pressure->get_slave_descr = %x\n",
802 (unsigned int) pressure->get_slave_descr);
803 MPL_LOGD("pressure->irq = %02x\n", pressure->irq);
804 MPL_LOGD("pressure->adapt_num = %02x\n", pressure->adapt_num);
805 MPL_LOGD("pressure->bus = %02x\n", pressure->bus);
806 MPL_LOGD("pressure->address = %02x\n", pressure->address);
807 MPL_LOGD("pressure->orientation =\n"
808 " %2d %2d %2d\n"
809 " %2d %2d %2d\n"
810 " %2d %2d %2d\n",
811 pressure->orientation[0], pressure->orientation[1],
812 pressure->orientation[2], pressure->orientation[3],
813 pressure->orientation[4], pressure->orientation[5],
814 pressure->orientation[6], pressure->orientation[7],
815 pressure->orientation[8]);
816
817 MPL_LOGD("pdata->int_config = %02x\n", pdata->int_config);
818 MPL_LOGD("pdata->level_shifter = %02x\n",
819 pdata->level_shifter);
820 MPL_LOGD("pdata->orientation =\n"
821 " %2d %2d %2d\n"
822 " %2d %2d %2d\n"
823 " %2d %2d %2d\n",
824 pdata->orientation[0], pdata->orientation[1],
825 pdata->orientation[2], pdata->orientation[3],
826 pdata->orientation[4], pdata->orientation[5],
827 pdata->orientation[6], pdata->orientation[7],
828 pdata->orientation[8]);
829
830 MPL_LOGD("Struct sizes: mldl_cfg: %d, "
831 "ext_slave_descr:%d, "
832 "mpu3050_platform_data:%d: RamOffset: %d\n",
833 sizeof(struct mldl_cfg), sizeof(struct ext_slave_descr),
834 sizeof(struct mpu3050_platform_data),
835 offsetof(struct mldl_cfg, ram));
836}
837
838int mpu_set_slave(struct mldl_cfg *mldl_cfg,
839 void *gyro_handle,
840 struct ext_slave_descr *slave,
841 struct ext_slave_platform_data *slave_pdata)
842{
843 int result;
844 unsigned char reg;
845 unsigned char slave_reg;
846 unsigned char slave_len;
847 unsigned char slave_endian;
848 unsigned char slave_address;
849
850 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
851
852 if (NULL == slave || NULL == slave_pdata) {
853 slave_reg = 0;
854 slave_len = 0;
855 slave_endian = 0;
856 slave_address = 0;
857 } else {
858 slave_reg = slave->reg;
859 slave_len = slave->len;
860 slave_endian = slave->endian;
861 slave_address = slave_pdata->address;
862 }
863
864 /* Address */
865 result = MLSLSerialWriteSingle(gyro_handle,
866 mldl_cfg->addr,
867 MPUREG_AUX_SLV_ADDR,
868 slave_address);
869 ERROR_CHECK(result);
870 /* Register */
871 result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
872 MPUREG_ACCEL_BURST_ADDR, 1,
873 &reg);
874 ERROR_CHECK(result);
875 reg = ((reg & 0x80) | slave_reg);
876 result = MLSLSerialWriteSingle(gyro_handle,
877 mldl_cfg->addr,
878 MPUREG_ACCEL_BURST_ADDR,
879 reg);
880 ERROR_CHECK(result);
881
882#ifdef M_HW
883 /* Length, byte swapping, grouping & enable */
884 if (slave_len > BITS_SLV_LENG) {
885 MPL_LOGW("Limiting slave burst read length to "
886 "the allowed maximum (15B, req. %d)\n",
887 slave_len);
888 slave_len = BITS_SLV_LENG;
889 }
890 reg = slave_len;
891 if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN)
892 reg |= BIT_SLV_BYTE_SW;
893 reg |= BIT_SLV_GRP;
894 reg |= BIT_SLV_ENABLE;
895
896 result = MLSLSerialWriteSingle(gyro_handle,
897 mldl_cfg->addr,
898 MPUREG_I2C_SLV0_CTRL,
899 reg);
900#else
901 /* Length */
902 result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
903 MPUREG_USER_CTRL, 1, &reg);
904 ERROR_CHECK(result);
905 reg = (reg & ~BIT_AUX_RD_LENG);
906 result = MLSLSerialWriteSingle(gyro_handle,
907 mldl_cfg->addr,
908 MPUREG_USER_CTRL, reg);
909 ERROR_CHECK(result);
910#endif
911
912 if (slave_address) {
913 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, FALSE);
914 ERROR_CHECK(result);
915 }
916 return result;
917}
918
919/**
920 * Check to see if the gyro was reset by testing a couple of registers known
921 * to change on reset.
922 *
923 * @param mldl_cfg mldl configuration structure
924 * @param gyro_handle handle used to communicate with the gyro
925 *
926 * @return ML_SUCCESS or non-zero error code
927 */
928static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle)
929{
930 int result = ML_SUCCESS;
931 unsigned char reg;
932
933 result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
934 MPUREG_DMP_CFG_2, 1, &reg);
935 ERROR_CHECK(result);
936
937 if (mldl_cfg->dmp_cfg2 != reg)
938 return TRUE;
939
940 if (0 != mldl_cfg->dmp_cfg1)
941 return FALSE;
942
943 result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
944 MPUREG_SMPLRT_DIV, 1, &reg);
945 ERROR_CHECK(result);
946 if (reg != mldl_cfg->divider)
947 return TRUE;
948
949 if (0 != mldl_cfg->divider)
950 return FALSE;
951
952 /* Inconclusive assume it was reset */
953 return TRUE;
954}
955
956static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle)
957{
958 int result;
959 int ii;
960 int jj;
961 unsigned char reg;
962 unsigned char regs[7];
963
964 /* Wake up the part */
965#ifdef M_HW
966 result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, RESET,
967 WAKE_UP);
968 ERROR_CHECK(result);
969
970 /* Configure the MPU */
971 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1);
972 ERROR_CHECK(result);
973 /* setting int_config with the propert flag BIT_BYPASS_EN
974 should be done by the setup functions */
975 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
976 MPUREG_INT_PIN_CFG,
977 (mldl_cfg->pdata->int_config |
978 BIT_BYPASS_EN));
979 ERROR_CHECK(result);
980 /* temporary: masking out higher bits to avoid switching
981 intelligence */
982 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
983 MPUREG_INT_ENABLE,
984 (mldl_cfg->int_config));
985 ERROR_CHECK(result);
986#else
987 result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 0, 0,
988 mldl_cfg->gyro_power & BIT_STBY_XG,
989 mldl_cfg->gyro_power & BIT_STBY_YG,
990 mldl_cfg->gyro_power & BIT_STBY_ZG);
991
992 if (!mldl_cfg->gyro_needs_reset &&
993 !mpu_was_reset(mldl_cfg, gyro_handle)) {
994 return ML_SUCCESS;
995 }
996
997 result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 1, 0,
998 mldl_cfg->gyro_power & BIT_STBY_XG,
999 mldl_cfg->gyro_power & BIT_STBY_YG,
1000 mldl_cfg->gyro_power & BIT_STBY_ZG);
1001 ERROR_CHECK(result);
1002 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1003 MPUREG_INT_CFG,
1004 (mldl_cfg->int_config |
1005 mldl_cfg->pdata->int_config));
1006 ERROR_CHECK(result);
1007#endif
1008
1009 result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
1010 MPUREG_PWR_MGM, 1, &reg);
1011 ERROR_CHECK(result);
1012 reg &= ~BITS_CLKSEL;
1013 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1014 MPUREG_PWR_MGM,
1015 mldl_cfg->clk_src | reg);
1016 ERROR_CHECK(result);
1017 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1018 MPUREG_SMPLRT_DIV,
1019 mldl_cfg->divider);
1020 ERROR_CHECK(result);
1021
1022#ifdef M_HW
1023 reg = DLPF_FS_SYNC_VALUE(0, mldl_cfg->full_scale, 0);
1024 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1025 MPUREG_GYRO_CONFIG, reg);
1026 reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, 0, mldl_cfg->lpf);
1027 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1028 MPUREG_CONFIG, reg);
1029#else
1030 reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync,
1031 mldl_cfg->full_scale, mldl_cfg->lpf);
1032 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1033 MPUREG_DLPF_FS_SYNC, reg);
1034#endif
1035 ERROR_CHECK(result);
1036 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1037 MPUREG_DMP_CFG_1,
1038 mldl_cfg->dmp_cfg1);
1039 ERROR_CHECK(result);
1040 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1041 MPUREG_DMP_CFG_2,
1042 mldl_cfg->dmp_cfg2);
1043 ERROR_CHECK(result);
1044
1045 /* Write and verify memory */
1046 for (ii = 0; ii < MPU_MEM_NUM_RAM_BANKS; ii++) {
1047 unsigned char read[MPU_MEM_BANK_SIZE];
1048
1049 result = MLSLSerialWriteMem(gyro_handle,
1050 mldl_cfg->addr,
1051 ((ii << 8) | 0x00),
1052 MPU_MEM_BANK_SIZE,
1053 mldl_cfg->ram[ii]);
1054 ERROR_CHECK(result);
1055 result = MLSLSerialReadMem(gyro_handle, mldl_cfg->addr,
1056 ((ii << 8) | 0x00),
1057 MPU_MEM_BANK_SIZE, read);
1058 ERROR_CHECK(result);
1059
1060#ifdef M_HW
1061#define ML_SKIP_CHECK 38
1062#else
1063#define ML_SKIP_CHECK 20
1064#endif
1065 for (jj = 0; jj < MPU_MEM_BANK_SIZE; jj++) {
1066 /* skip the register memory locations */
1067 if (ii == 0 && jj < ML_SKIP_CHECK)
1068 continue;
1069 if (mldl_cfg->ram[ii][jj] != read[jj]) {
1070 result = ML_ERROR_SERIAL_WRITE;
1071 break;
1072 }
1073 }
1074 ERROR_CHECK(result);
1075 }
1076
1077 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1078 MPUREG_XG_OFFS_TC,
1079 mldl_cfg->offset_tc[0]);
1080 ERROR_CHECK(result);
1081 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1082 MPUREG_YG_OFFS_TC,
1083 mldl_cfg->offset_tc[1]);
1084 ERROR_CHECK(result);
1085 result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
1086 MPUREG_ZG_OFFS_TC,
1087 mldl_cfg->offset_tc[2]);
1088 ERROR_CHECK(result);
1089
1090 regs[0] = MPUREG_X_OFFS_USRH;
1091 for (ii = 0; ii < DIM(mldl_cfg->offset); ii++) {
1092 regs[1 + ii * 2] =
1093 (unsigned char)(mldl_cfg->offset[ii] >> 8)
1094 & 0xff;
1095 regs[1 + ii * 2 + 1] =
1096 (unsigned char)(mldl_cfg->offset[ii] & 0xff);
1097 }
1098 result = MLSLSerialWrite(gyro_handle, mldl_cfg->addr, 7, regs);
1099 ERROR_CHECK(result);
1100
1101 /* Configure slaves */
1102 result = MLDLSetLevelShifterBit(mldl_cfg, gyro_handle,
1103 mldl_cfg->pdata->level_shifter);
1104 ERROR_CHECK(result);
1105 return result;
1106}
1107/*******************************************************************************
1108 *******************************************************************************
1109 * Exported functions
1110 *******************************************************************************
1111 ******************************************************************************/
1112
1113/**
1114 * Initializes the pdata structure to defaults.
1115 *
1116 * Opens the device to read silicon revision, product id and whoami.
1117 *
1118 * @param mldl_cfg
1119 * The internal device configuration data structure.
1120 * @param mlsl_handle
1121 * The serial communication handle.
1122 *
1123 * @return ML_SUCCESS if silicon revision, product id and woami are supported
1124 * by this software.
1125 */
1126int mpu3050_open(struct mldl_cfg *mldl_cfg,
1127 void *mlsl_handle,
1128 void *accel_handle,
1129 void *compass_handle,
1130 void *pressure_handle)
1131{
1132 int result;
1133 /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */
1134 mldl_cfg->ignore_system_suspend = FALSE;
1135 mldl_cfg->int_config = BIT_INT_ANYRD_2CLEAR | BIT_DMP_INT_EN;
1136 mldl_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ;
1137 mldl_cfg->lpf = MPU_FILTER_42HZ;
1138 mldl_cfg->full_scale = MPU_FS_2000DPS;
1139 mldl_cfg->divider = 4;
1140 mldl_cfg->dmp_enable = 1;
1141 mldl_cfg->fifo_enable = 1;
1142 mldl_cfg->ext_sync = 0;
1143 mldl_cfg->dmp_cfg1 = 0;
1144 mldl_cfg->dmp_cfg2 = 0;
1145 mldl_cfg->gyro_power = 0;
1146 mldl_cfg->gyro_is_bypassed = TRUE;
1147 mldl_cfg->dmp_is_running = FALSE;
1148 mldl_cfg->gyro_is_suspended = TRUE;
1149 mldl_cfg->accel_is_suspended = TRUE;
1150 mldl_cfg->compass_is_suspended = TRUE;
1151 mldl_cfg->pressure_is_suspended = TRUE;
1152 mldl_cfg->gyro_needs_reset = FALSE;
1153 if (mldl_cfg->addr == 0) {
1154#ifdef __KERNEL__
1155 return ML_ERROR_INVALID_PARAMETER;
1156#else
1157 mldl_cfg->addr = 0x68;
1158#endif
1159 }
1160
1161 /*
1162 * Reset,
1163 * Take the DMP out of sleep, and
1164 * read the product_id, sillicon rev and whoami
1165 */
1166#ifdef M_HW
1167 result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle,
1168 RESET, WAKE_UP);
1169#else
1170 result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, RESET, 0, 0, 0, 0);
1171#endif
1172 ERROR_CHECK(result);
1173
1174 result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle);
1175 ERROR_CHECK(result);
1176#ifndef M_HW
1177 result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
1178 MPUREG_PRODUCT_ID, 1,
1179 &mldl_cfg->product_id);
1180 ERROR_CHECK(result);
1181#endif
1182
1183 /* Get the factory temperature compensation offsets */
1184 result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
1185 MPUREG_XG_OFFS_TC, 1,
1186 &mldl_cfg->offset_tc[0]);
1187 ERROR_CHECK(result);
1188 result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
1189 MPUREG_YG_OFFS_TC, 1,
1190 &mldl_cfg->offset_tc[1]);
1191 ERROR_CHECK(result);
1192 result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
1193 MPUREG_ZG_OFFS_TC, 1,
1194 &mldl_cfg->offset_tc[2]);
1195 ERROR_CHECK(result);
1196
1197 /* Configure the MPU */
1198#ifdef M_HW
1199 result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle,
1200 FALSE, SLEEP);
1201#else
1202 result =
1203 MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, SLEEP, 0, 0, 0);
1204#endif
1205 ERROR_CHECK(result);
1206
1207 if (mldl_cfg->accel && mldl_cfg->accel->init) {
1208 result = mldl_cfg->accel->init(accel_handle,
1209 mldl_cfg->accel,
1210 &mldl_cfg->pdata->accel);
1211 ERROR_CHECK(result);
1212 }
1213
1214 if (mldl_cfg->compass && mldl_cfg->compass->init) {
1215 result = mldl_cfg->compass->init(compass_handle,
1216 mldl_cfg->compass,
1217 &mldl_cfg->pdata->compass);
1218 if (ML_SUCCESS != result) {
1219 MPL_LOGE("mldl_cfg->compass->init returned %d\n",
1220 result);
1221 goto out_accel;
1222 }
1223 }
1224 if (mldl_cfg->pressure && mldl_cfg->pressure->init) {
1225 result = mldl_cfg->pressure->init(pressure_handle,
1226 mldl_cfg->pressure,
1227 &mldl_cfg->pdata->pressure);
1228 if (ML_SUCCESS != result) {
1229 MPL_LOGE("mldl_cfg->pressure->init returned %d\n",
1230 result);
1231 goto out_compass;
1232 }
1233 }
1234
1235 mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO;
1236 if (mldl_cfg->accel && mldl_cfg->accel->resume)
1237 mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL;
1238
1239 if (mldl_cfg->compass && mldl_cfg->compass->resume)
1240 mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS;
1241
1242 if (mldl_cfg->pressure && mldl_cfg->pressure->resume)
1243 mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE;
1244
1245 return result;
1246
1247out_compass:
1248 if (mldl_cfg->compass->init)
1249 mldl_cfg->compass->exit(compass_handle,
1250 mldl_cfg->compass,
1251 &mldl_cfg->pdata->compass);
1252out_accel:
1253 if (mldl_cfg->accel->init)
1254 mldl_cfg->accel->exit(accel_handle,
1255 mldl_cfg->accel,
1256 &mldl_cfg->pdata->accel);
1257 return result;
1258
1259}
1260
1261/**
1262 * Close the mpu3050 interface
1263 *
1264 * @param mldl_cfg pointer to the configuration structure
1265 * @param mlsl_handle pointer to the serial layer handle
1266 *
1267 * @return ML_SUCCESS or non-zero error code
1268 */
1269int mpu3050_close(struct mldl_cfg *mldl_cfg,
1270 void *mlsl_handle,
1271 void *accel_handle,
1272 void *compass_handle,
1273 void *pressure_handle)
1274{
1275 int result = ML_SUCCESS;
1276 int ret_result = ML_SUCCESS;
1277
1278 if (mldl_cfg->accel && mldl_cfg->accel->exit) {
1279 result = mldl_cfg->accel->exit(accel_handle,
1280 mldl_cfg->accel,
1281 &mldl_cfg->pdata->accel);
1282 if (ML_SUCCESS != result)
1283 MPL_LOGE("Accel exit failed %d\n", result);
1284 ret_result = result;
1285 }
1286 if (ML_SUCCESS == ret_result)
1287 ret_result = result;
1288
1289 if (mldl_cfg->compass && mldl_cfg->compass->exit) {
1290 result = mldl_cfg->compass->exit(compass_handle,
1291 mldl_cfg->compass,
1292 &mldl_cfg->pdata->compass);
1293 if (ML_SUCCESS != result)
1294 MPL_LOGE("Compass exit failed %d\n", result);
1295 }
1296 if (ML_SUCCESS == ret_result)
1297 ret_result = result;
1298
1299 if (mldl_cfg->pressure && mldl_cfg->pressure->exit) {
1300 result = mldl_cfg->pressure->exit(pressure_handle,
1301 mldl_cfg->pressure,
1302 &mldl_cfg->pdata->pressure);
1303 if (ML_SUCCESS != result)
1304 MPL_LOGE("Pressure exit failed %d\n", result);
1305 }
1306 if (ML_SUCCESS == ret_result)
1307 ret_result = result;
1308
1309 return ret_result;
1310}
1311
1312/**
1313 * @brief resume the MPU3050 device and all the other sensor
1314 * devices from their low power state.
1315 *
1316 * @param mldl_cfg
1317 * pointer to the configuration structure
1318 * @param gyro_handle
1319 * the main file handle to the MPU3050 device.
1320 * @param accel_handle
1321 * an handle to the accelerometer device, if sitting
1322 * onto a separate bus. Can match mlsl_handle if
1323 * the accelerometer device operates on the same
1324 * primary bus of MPU.
1325 * @param compass_handle
1326 * an handle to the compass device, if sitting
1327 * onto a separate bus. Can match mlsl_handle if
1328 * the compass device operates on the same
1329 * primary bus of MPU.
1330 * @param pressure_handle
1331 * an handle to the pressure sensor device, if sitting
1332 * onto a separate bus. Can match mlsl_handle if
1333 * the pressure sensor device operates on the same
1334 * primary bus of MPU.
1335 * @param resume_gyro
1336 * whether resuming the gyroscope device is
1337 * actually needed (if the device supports low power
1338 * mode of some sort).
1339 * @param resume_accel
1340 * whether resuming the accelerometer device is
1341 * actually needed (if the device supports low power
1342 * mode of some sort).
1343 * @param resume_compass
1344 * whether resuming the compass device is
1345 * actually needed (if the device supports low power
1346 * mode of some sort).
1347 * @param resume_pressure
1348 * whether resuming the pressure sensor device is
1349 * actually needed (if the device supports low power
1350 * mode of some sort).
1351 * @return ML_SUCCESS or a non-zero error code.
1352 */
1353int mpu3050_resume(struct mldl_cfg *mldl_cfg,
1354 void *gyro_handle,
1355 void *accel_handle,
1356 void *compass_handle,
1357 void *pressure_handle,
1358 bool resume_gyro,
1359 bool resume_accel,
1360 bool resume_compass,
1361 bool resume_pressure)
1362{
1363 int result = ML_SUCCESS;
1364
1365#ifdef CONFIG_MPU_SENSORS_DEBUG
1366 mpu_print_cfg(mldl_cfg);
1367#endif
1368
1369 if (resume_accel &&
1370 ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume)))
1371 return ML_ERROR_INVALID_PARAMETER;
1372 if (resume_compass &&
1373 ((!mldl_cfg->compass) || (!mldl_cfg->compass->resume)))
1374 return ML_ERROR_INVALID_PARAMETER;
1375 if (resume_pressure &&
1376 ((!mldl_cfg->pressure) || (!mldl_cfg->pressure->resume)))
1377 return ML_ERROR_INVALID_PARAMETER;
1378
1379 if (resume_gyro && mldl_cfg->gyro_is_suspended) {
1380 result = gyro_resume(mldl_cfg, gyro_handle);
1381 ERROR_CHECK(result);
1382 }
1383
1384 if (resume_accel && mldl_cfg->accel_is_suspended) {
1385 if (!mldl_cfg->gyro_is_suspended &&
1386 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
1387 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
1388 ERROR_CHECK(result);
1389 }
1390 result = mldl_cfg->accel->resume(accel_handle,
1391 mldl_cfg->accel,
1392 &mldl_cfg->pdata->accel);
1393 ERROR_CHECK(result);
1394 mldl_cfg->accel_is_suspended = FALSE;
1395 }
1396
1397 if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->accel_is_suspended &&
1398 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
1399 result = mpu_set_slave(mldl_cfg,
1400 gyro_handle,
1401 mldl_cfg->accel,
1402 &mldl_cfg->pdata->accel);
1403 ERROR_CHECK(result);
1404 }
1405
1406 if (resume_compass && mldl_cfg->compass_is_suspended) {
1407 if (!mldl_cfg->gyro_is_suspended &&
1408 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
1409 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
1410 ERROR_CHECK(result);
1411 }
1412 result = mldl_cfg->compass->resume(compass_handle,
1413 mldl_cfg->compass,
1414 &mldl_cfg->pdata->
1415 compass);
1416 ERROR_CHECK(result);
1417 mldl_cfg->compass_is_suspended = FALSE;
1418 }
1419
1420 if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->compass_is_suspended &&
1421 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
1422 result = mpu_set_slave(mldl_cfg,
1423 gyro_handle,
1424 mldl_cfg->compass,
1425 &mldl_cfg->pdata->compass);
1426 ERROR_CHECK(result);
1427 }
1428
1429 if (resume_pressure && mldl_cfg->pressure_is_suspended) {
1430 if (!mldl_cfg->gyro_is_suspended &&
1431 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
1432 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
1433 ERROR_CHECK(result);
1434 }
1435 result = mldl_cfg->pressure->resume(pressure_handle,
1436 mldl_cfg->pressure,
1437 &mldl_cfg->pdata->
1438 pressure);
1439 ERROR_CHECK(result);
1440 mldl_cfg->pressure_is_suspended = FALSE;
1441 }
1442
1443 if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->pressure_is_suspended &&
1444 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
1445 result = mpu_set_slave(mldl_cfg,
1446 gyro_handle,
1447 mldl_cfg->pressure,
1448 &mldl_cfg->pdata->pressure);
1449 ERROR_CHECK(result);
1450 }
1451
1452 /* Now start */
1453 if (resume_gyro) {
1454 result = dmp_start(mldl_cfg, gyro_handle);
1455 ERROR_CHECK(result);
1456 }
1457
1458 return result;
1459}
1460
1461/**
1462 * @brief suspend the MPU3050 device and all the other sensor
1463 * devices into their low power state.
1464 * @param gyro_handle
1465 * the main file handle to the MPU3050 device.
1466 * @param accel_handle
1467 * an handle to the accelerometer device, if sitting
1468 * onto a separate bus. Can match gyro_handle if
1469 * the accelerometer device operates on the same
1470 * primary bus of MPU.
1471 * @param compass_handle
1472 * an handle to the compass device, if sitting
1473 * onto a separate bus. Can match gyro_handle if
1474 * the compass device operates on the same
1475 * primary bus of MPU.
1476 * @param pressure_handle
1477 * an handle to the pressure sensor device, if sitting
1478 * onto a separate bus. Can match gyro_handle if
1479 * the pressure sensor device operates on the same
1480 * primary bus of MPU.
1481 * @param accel
1482 * whether suspending the accelerometer device is
1483 * actually needed (if the device supports low power
1484 * mode of some sort).
1485 * @param compass
1486 * whether suspending the compass device is
1487 * actually needed (if the device supports low power
1488 * mode of some sort).
1489 * @param pressure
1490 * whether suspending the pressure sensor device is
1491 * actually needed (if the device supports low power
1492 * mode of some sort).
1493 * @return ML_SUCCESS or a non-zero error code.
1494 */
1495int mpu3050_suspend(struct mldl_cfg *mldl_cfg,
1496 void *gyro_handle,
1497 void *accel_handle,
1498 void *compass_handle,
1499 void *pressure_handle,
1500 bool suspend_gyro,
1501 bool suspend_accel,
1502 bool suspend_compass,
1503 bool suspend_pressure)
1504{
1505 int result = ML_SUCCESS;
1506
1507 if (suspend_gyro && !mldl_cfg->gyro_is_suspended) {
1508#ifdef M_HW
1509 return ML_SUCCESS;
1510 /* This puts the bus into bypass mode */
1511 result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1);
1512 ERROR_CHECK(result);
1513 result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP);
1514#else
1515 result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle,
1516 0, SLEEP, 0, 0, 0);
1517#endif
1518 ERROR_CHECK(result);
1519 }
1520
1521 if (!mldl_cfg->accel_is_suspended && suspend_accel &&
1522 mldl_cfg->accel && mldl_cfg->accel->suspend) {
1523 if (!mldl_cfg->gyro_is_suspended &&
1524 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
1525 result = mpu_set_slave(mldl_cfg, gyro_handle,
1526 NULL, NULL);
1527 ERROR_CHECK(result);
1528 }
1529 result = mldl_cfg->accel->suspend(accel_handle,
1530 mldl_cfg->accel,
1531 &mldl_cfg->pdata->accel);
1532 ERROR_CHECK(result);
1533 mldl_cfg->accel_is_suspended = TRUE;
1534 }
1535
1536 if (!mldl_cfg->compass_is_suspended && suspend_compass &&
1537 mldl_cfg->compass && mldl_cfg->compass->suspend) {
1538 if (!mldl_cfg->gyro_is_suspended &&
1539 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
1540 result = mpu_set_slave(mldl_cfg, gyro_handle,
1541 NULL, NULL);
1542 ERROR_CHECK(result);
1543 }
1544 result = mldl_cfg->compass->suspend(compass_handle,
1545 mldl_cfg->compass,
1546 &mldl_cfg->
1547 pdata->compass);
1548 ERROR_CHECK(result);
1549 mldl_cfg->compass_is_suspended = TRUE;
1550 }
1551
1552 if (!mldl_cfg->pressure_is_suspended && suspend_pressure &&
1553 mldl_cfg->pressure && mldl_cfg->pressure->suspend) {
1554 if (!mldl_cfg->gyro_is_suspended &&
1555 EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
1556 result = mpu_set_slave(mldl_cfg, gyro_handle,
1557 NULL, NULL);
1558 ERROR_CHECK(result);
1559 }
1560 result = mldl_cfg->pressure->suspend(pressure_handle,
1561 mldl_cfg->pressure,
1562 &mldl_cfg->
1563 pdata->pressure);
1564 ERROR_CHECK(result);
1565 mldl_cfg->pressure_is_suspended = TRUE;
1566 }
1567 return result;
1568}
1569
1570
1571/**
1572 * @brief read raw sensor data from the accelerometer device
1573 * in use.
1574 * @param mldl_cfg
1575 * A pointer to the struct mldl_cfg data structure.
1576 * @param accel_handle
1577 * The handle to the device the accelerometer is connected to.
1578 * @param data
1579 * a buffer to store the raw sensor data.
1580 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
1581 */
1582int mpu3050_read_accel(struct mldl_cfg *mldl_cfg,
1583 void *accel_handle, unsigned char *data)
1584{
1585 if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read)
1586 if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus)
1587 && (!mldl_cfg->gyro_is_bypassed))
1588 return ML_ERROR_FEATURE_NOT_ENABLED;
1589 else
1590 return mldl_cfg->accel->read(accel_handle,
1591 mldl_cfg->accel,
1592 &mldl_cfg->pdata->accel,
1593 data);
1594 else
1595 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1596}
1597
1598/**
1599 * @brief read raw sensor data from the compass device
1600 * in use.
1601 * @param mldl_cfg
1602 * A pointer to the struct mldl_cfg data structure.
1603 * @param compass_handle
1604 * The handle to the device the compass is connected to.
1605 * @param data
1606 * a buffer to store the raw sensor data.
1607 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
1608 */
1609int mpu3050_read_compass(struct mldl_cfg *mldl_cfg,
1610 void *compass_handle, unsigned char *data)
1611{
1612 if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read)
1613 if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus)
1614 && (!mldl_cfg->gyro_is_bypassed))
1615 return ML_ERROR_FEATURE_NOT_ENABLED;
1616 else
1617 return mldl_cfg->compass->read(compass_handle,
1618 mldl_cfg->compass,
1619 &mldl_cfg->pdata->compass,
1620 data);
1621 else
1622 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1623}
1624
1625/**
1626 * @brief read raw sensor data from the pressure device
1627 * in use.
1628 * @param mldl_cfg
1629 * A pointer to the struct mldl_cfg data structure.
1630 * @param pressure_handle
1631 * The handle to the device the pressure sensor is connected to.
1632 * @param data
1633 * a buffer to store the raw sensor data.
1634 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
1635 */
1636int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg,
1637 void *pressure_handle, unsigned char *data)
1638{
1639 if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->read)
1640 if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus)
1641 && (!mldl_cfg->gyro_is_bypassed))
1642 return ML_ERROR_FEATURE_NOT_ENABLED;
1643 else
1644 return mldl_cfg->pressure->read(
1645 pressure_handle,
1646 mldl_cfg->pressure,
1647 &mldl_cfg->pdata->pressure,
1648 data);
1649 else
1650 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1651}
1652
1653int mpu3050_config_accel(struct mldl_cfg *mldl_cfg,
1654 void *accel_handle,
1655 struct ext_slave_config *data)
1656{
1657 if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->config)
1658 return mldl_cfg->accel->config(accel_handle,
1659 mldl_cfg->accel,
1660 &mldl_cfg->pdata->accel,
1661 data);
1662 else
1663 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1664
1665}
1666
1667int mpu3050_config_compass(struct mldl_cfg *mldl_cfg,
1668 void *compass_handle,
1669 struct ext_slave_config *data)
1670{
1671 if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->config)
1672 return mldl_cfg->compass->config(compass_handle,
1673 mldl_cfg->compass,
1674 &mldl_cfg->pdata->compass,
1675 data);
1676 else
1677 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1678
1679}
1680
1681int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg,
1682 void *pressure_handle,
1683 struct ext_slave_config *data)
1684{
1685 if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->config)
1686 return mldl_cfg->pressure->config(pressure_handle,
1687 mldl_cfg->pressure,
1688 &mldl_cfg->pdata->pressure,
1689 data);
1690 else
1691 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1692}
1693
1694int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg,
1695 void *accel_handle,
1696 struct ext_slave_config *data)
1697{
1698 if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->get_config)
1699 return mldl_cfg->accel->get_config(accel_handle,
1700 mldl_cfg->accel,
1701 &mldl_cfg->pdata->accel,
1702 data);
1703 else
1704 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1705
1706}
1707
1708int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg,
1709 void *compass_handle,
1710 struct ext_slave_config *data)
1711{
1712 if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->get_config)
1713 return mldl_cfg->compass->get_config(compass_handle,
1714 mldl_cfg->compass,
1715 &mldl_cfg->pdata->compass,
1716 data);
1717 else
1718 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1719
1720}
1721
1722int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg,
1723 void *pressure_handle,
1724 struct ext_slave_config *data)
1725{
1726 if (NULL != mldl_cfg->pressure &&
1727 NULL != mldl_cfg->pressure->get_config)
1728 return mldl_cfg->pressure->get_config(pressure_handle,
1729 mldl_cfg->pressure,
1730 &mldl_cfg->pdata->pressure,
1731 data);
1732 else
1733 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
1734}
1735
1736
1737/**
1738 *@}
1739 */
diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h
new file mode 100644
index 00000000000..ad6a211c5d8
--- /dev/null
+++ b/drivers/misc/mpu3050/mldl_cfg.h
@@ -0,0 +1,199 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @addtogroup MLDL
22 *
23 * @{
24 * @file mldl_cfg.h
25 * @brief The Motion Library Driver Layer Configuration header file.
26 */
27
28#ifndef __MLDL_CFG_H__
29#define __MLDL_CFG_H__
30
31/* ------------------ */
32/* - Include Files. - */
33/* ------------------ */
34
35#include "mlsl.h"
36#include "mpu.h"
37
38/* --------------------- */
39/* - Defines. - */
40/* --------------------- */
41
42 /*************************************************************************/
43 /* Sensors */
44 /*************************************************************************/
45
46#define ML_X_GYRO (0x0001)
47#define ML_Y_GYRO (0x0002)
48#define ML_Z_GYRO (0x0004)
49#define ML_DMP_PROCESSOR (0x0008)
50
51#define ML_X_ACCEL (0x0010)
52#define ML_Y_ACCEL (0x0020)
53#define ML_Z_ACCEL (0x0040)
54
55#define ML_X_COMPASS (0x0080)
56#define ML_Y_COMPASS (0x0100)
57#define ML_Z_COMPASS (0x0200)
58
59#define ML_X_PRESSURE (0x0300)
60#define ML_Y_PRESSURE (0x0800)
61#define ML_Z_PRESSURE (0x1000)
62
63#define ML_TEMPERATURE (0x2000)
64#define ML_TIME (0x4000)
65
66#define ML_THREE_AXIS_GYRO (0x000F)
67#define ML_THREE_AXIS_ACCEL (0x0070)
68#define ML_THREE_AXIS_COMPASS (0x0380)
69#define ML_THREE_AXIS_PRESSURE (0x1C00)
70
71#define ML_FIVE_AXIS (0x007B)
72#define ML_SIX_AXIS_GYRO_ACCEL (0x007F)
73#define ML_SIX_AXIS_ACCEL_COMPASS (0x03F0)
74#define ML_NINE_AXIS (0x03FF)
75#define ML_ALL_SENSORS (0x7FFF)
76
77#define SAMPLING_RATE_HZ(mldl_cfg) \
78 ((((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \
79 ? (8000) \
80 : (1000)) \
81 / ((mldl_cfg)->divider + 1))
82
83#define SAMPLING_PERIOD_US(mldl_cfg) \
84 ((1000000L * ((mldl_cfg)->divider + 1)) / \
85 (((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \
86 ? (8000) \
87 : (1000)))
88/* --------------------- */
89/* - Variables. - */
90/* --------------------- */
91
92/* Platform data for the MPU */
93struct mldl_cfg {
94 /* MPU related configuration */
95 unsigned long requested_sensors;
96 unsigned char ignore_system_suspend;
97 unsigned char addr;
98 unsigned char int_config;
99 unsigned char ext_sync;
100 unsigned char full_scale;
101 unsigned char lpf;
102 unsigned char clk_src;
103 unsigned char divider;
104 unsigned char dmp_enable;
105 unsigned char fifo_enable;
106 unsigned char dmp_cfg1;
107 unsigned char dmp_cfg2;
108 unsigned char gyro_power;
109 unsigned char offset_tc[MPU_NUM_AXES];
110 unsigned short offset[MPU_NUM_AXES];
111 unsigned char ram[MPU_MEM_NUM_RAM_BANKS][MPU_MEM_BANK_SIZE];
112
113 /* MPU Related stored status and info */
114 unsigned char silicon_revision;
115 unsigned char product_id;
116 unsigned short trim;
117
118 /* Driver/Kernel related state information */
119 int gyro_is_bypassed;
120 int dmp_is_running;
121 int gyro_is_suspended;
122 int accel_is_suspended;
123 int compass_is_suspended;
124 int pressure_is_suspended;
125 int gyro_needs_reset;
126
127 /* Slave related information */
128 struct ext_slave_descr *accel;
129 struct ext_slave_descr *compass;
130 struct ext_slave_descr *pressure;
131
132 /* Platform Data */
133 struct mpu3050_platform_data *pdata;
134};
135
136
137int mpu3050_open(struct mldl_cfg *mldl_cfg,
138 void *mlsl_handle,
139 void *accel_handle,
140 void *compass_handle,
141 void *pressure_handle);
142int mpu3050_close(struct mldl_cfg *mldl_cfg,
143 void *mlsl_handle,
144 void *accel_handle,
145 void *compass_handle,
146 void *pressure_handle);
147int mpu3050_resume(struct mldl_cfg *mldl_cfg,
148 void *gyro_handle,
149 void *accel_handle,
150 void *compass_handle,
151 void *pressure_handle,
152 bool resume_gyro,
153 bool resume_accel,
154 bool resume_compass,
155 bool resume_pressure);
156int mpu3050_suspend(struct mldl_cfg *mldl_cfg,
157 void *gyro_handle,
158 void *accel_handle,
159 void *compass_handle,
160 void *pressure_handle,
161 bool suspend_gyro,
162 bool suspend_accel,
163 bool suspend_compass,
164 bool suspend_pressure);
165int mpu3050_read_accel(struct mldl_cfg *mldl_cfg,
166 void *accel_handle,
167 unsigned char *data);
168int mpu3050_read_compass(struct mldl_cfg *mldl_cfg,
169 void *compass_handle,
170 unsigned char *data);
171int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
172 unsigned char *data);
173
174int mpu3050_config_accel(struct mldl_cfg *mldl_cfg,
175 void *accel_handle,
176 struct ext_slave_config *data);
177int mpu3050_config_compass(struct mldl_cfg *mldl_cfg,
178 void *compass_handle,
179 struct ext_slave_config *data);
180int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg,
181 void *pressure_handle,
182 struct ext_slave_config *data);
183
184int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg,
185 void *accel_handle,
186 struct ext_slave_config *data);
187int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg,
188 void *compass_handle,
189 struct ext_slave_config *data);
190int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg,
191 void *pressure_handle,
192 struct ext_slave_config *data);
193
194
195#endif /* __MLDL_CFG_H__ */
196
197/**
198 *@}
199 */
diff --git a/drivers/misc/mpu3050/mlos-kernel.c b/drivers/misc/mpu3050/mlos-kernel.c
new file mode 100644
index 00000000000..ced9ba4f6f3
--- /dev/null
+++ b/drivers/misc/mpu3050/mlos-kernel.c
@@ -0,0 +1,89 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19/**
20 * @defgroup
21 * @brief
22 *
23 * @{
24 * @file mlos-kernel.c
25 * @brief
26 *
27 *
28 */
29
30#include "mlos.h"
31#include <linux/delay.h>
32#include <linux/slab.h>
33
34void *MLOSMalloc(unsigned int numBytes)
35{
36 return kmalloc(numBytes, GFP_KERNEL);
37}
38
39tMLError MLOSFree(void *ptr)
40{
41 kfree(ptr);
42 return ML_SUCCESS;
43}
44
45tMLError MLOSCreateMutex(HANDLE *mutex)
46{
47 /* @todo implement if needed */
48 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
49}
50
51tMLError MLOSLockMutex(HANDLE mutex)
52{
53 /* @todo implement if needed */
54 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
55}
56
57tMLError MLOSUnlockMutex(HANDLE mutex)
58{
59 /* @todo implement if needed */
60 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
61}
62
63tMLError MLOSDestroyMutex(HANDLE handle)
64{
65 /* @todo implement if needed */
66 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
67}
68
69FILE *MLOSFOpen(char *filename)
70{
71 /* @todo implement if needed */
72 return NULL;
73}
74
75void MLOSFClose(FILE *fp)
76{
77 /* @todo implement if needed */
78}
79
80void MLOSSleep(int mSecs)
81{
82 msleep(mSecs);
83}
84
85unsigned long MLOSGetTickCount(void)
86{
87 /* @todo implement if needed */
88 return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
89}
diff --git a/drivers/misc/mpu3050/mlos.h b/drivers/misc/mpu3050/mlos.h
new file mode 100644
index 00000000000..4ebb86c9fa5
--- /dev/null
+++ b/drivers/misc/mpu3050/mlos.h
@@ -0,0 +1,73 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20#ifndef _MLOS_H
21#define _MLOS_H
22
23#ifndef __KERNEL__
24#include <stdio.h>
25#endif
26
27#include "mltypes.h"
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32
33 /* ------------ */
34 /* - Defines. - */
35 /* ------------ */
36
37 /* - MLOSCreateFile defines. - */
38
39#define MLOS_GENERIC_READ ((unsigned int)0x80000000)
40#define MLOS_GENERIC_WRITE ((unsigned int)0x40000000)
41#define MLOS_FILE_SHARE_READ ((unsigned int)0x00000001)
42#define MLOS_FILE_SHARE_WRITE ((unsigned int)0x00000002)
43#define MLOS_OPEN_EXISTING ((unsigned int)0x00000003)
44
45 /* ---------- */
46 /* - Enums. - */
47 /* ---------- */
48
49 /* --------------- */
50 /* - Structures. - */
51 /* --------------- */
52
53 /* --------------------- */
54 /* - Function p-types. - */
55 /* --------------------- */
56
57 void *MLOSMalloc(unsigned int numBytes);
58 tMLError MLOSFree(void *ptr);
59 tMLError MLOSCreateMutex(HANDLE *mutex);
60 tMLError MLOSLockMutex(HANDLE mutex);
61 tMLError MLOSUnlockMutex(HANDLE mutex);
62 FILE *MLOSFOpen(char *filename);
63 void MLOSFClose(FILE *fp);
64
65 tMLError MLOSDestroyMutex(HANDLE handle);
66
67 void MLOSSleep(int mSecs);
68 unsigned long MLOSGetTickCount(void);
69
70#ifdef __cplusplus
71}
72#endif
73#endif /* _MLOS_H */
diff --git a/drivers/misc/mpu3050/mlsl-kernel.c b/drivers/misc/mpu3050/mlsl-kernel.c
new file mode 100644
index 00000000000..cb1605131cb
--- /dev/null
+++ b/drivers/misc/mpu3050/mlsl-kernel.c
@@ -0,0 +1,331 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20#include "mlsl.h"
21#include "mpu-i2c.h"
22
23/* ------------ */
24/* - Defines. - */
25/* ------------ */
26
27/* ---------------------- */
28/* - Types definitions. - */
29/* ---------------------- */
30
31/* --------------------- */
32/* - Function p-types. - */
33/* --------------------- */
34
35/**
36 * @brief used to open the I2C or SPI serial port.
37 * This port is used to send and receive data to the MPU device.
38 * @param portNum
39 * The COM port number associated with the device in use.
40 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
41 */
42tMLError MLSLSerialOpen(char const *port, void **sl_handle)
43{
44 return ML_SUCCESS;
45}
46
47/**
48 * @brief used to reset any buffering the driver may be doing
49 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
50 */
51tMLError MLSLSerialReset(void *sl_handle)
52{
53 return ML_SUCCESS;
54}
55
56/**
57 * @brief used to close the I2C or SPI serial port.
58 * This port is used to send and receive data to the MPU device.
59 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
60 */
61tMLError MLSLSerialClose(void *sl_handle)
62{
63 return ML_SUCCESS;
64}
65
66/**
67 * @brief used to read a single byte of data.
68 * This should be sent by I2C or SPI.
69 *
70 * @param slaveAddr I2C slave address of device.
71 * @param registerAddr Register address to read.
72 * @param data Single byte of data to read.
73 *
74 * @return ML_SUCCESS if the command is successful, an error code otherwise.
75 */
76tMLError MLSLSerialWriteSingle(void *sl_handle,
77 unsigned char slaveAddr,
78 unsigned char registerAddr,
79 unsigned char data)
80{
81 return sensor_i2c_write_register((struct i2c_adapter *) sl_handle,
82 slaveAddr, registerAddr, data);
83}
84
85
86/**
87 * @brief used to write multiple bytes of data from registers.
88 * This should be sent by I2C.
89 *
90 * @param slaveAddr I2C slave address of device.
91 * @param registerAddr Register address to write.
92 * @param length Length of burst of data.
93 * @param data Pointer to block of data.
94 *
95 * @return ML_SUCCESS if successful, a non-zero error code otherwise.
96 */
97tMLError MLSLSerialWrite(void *sl_handle,
98 unsigned char slaveAddr,
99 unsigned short length,
100 unsigned char const *data)
101{
102 tMLError result;
103 const unsigned short dataLength = length - 1;
104 const unsigned char startRegAddr = data[0];
105 unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1];
106 unsigned short bytesWritten = 0;
107
108 while (bytesWritten < dataLength) {
109 unsigned short thisLen = min(SERIAL_MAX_TRANSFER_SIZE,
110 dataLength - bytesWritten);
111 if (bytesWritten == 0) {
112 result = sensor_i2c_write((struct i2c_adapter *)
113 sl_handle, slaveAddr,
114 1 + thisLen, data);
115 } else {
116 /* manually increment register addr between chunks */
117 i2cWrite[0] = startRegAddr + bytesWritten;
118 memcpy(&i2cWrite[1], &data[1 + bytesWritten],
119 thisLen);
120 result = sensor_i2c_write((struct i2c_adapter *)
121 sl_handle, slaveAddr,
122 1 + thisLen, i2cWrite);
123 }
124 if (ML_SUCCESS != result)
125 return result;
126 bytesWritten += thisLen;
127 }
128 return ML_SUCCESS;
129}
130
131
132/**
133 * @brief used to read multiple bytes of data from registers.
134 * This should be sent by I2C.
135 *
136 * @param slaveAddr I2C slave address of device.
137 * @param registerAddr Register address to read.
138 * @param length Length of burst of data.
139 * @param data Pointer to block of data.
140 *
141 * @return Zero if successful; an error code otherwise
142 */
143tMLError MLSLSerialRead(void *sl_handle,
144 unsigned char slaveAddr,
145 unsigned char registerAddr,
146 unsigned short length, unsigned char *data)
147{
148 tMLError result;
149 unsigned short bytesRead = 0;
150
151 if (registerAddr == MPUREG_FIFO_R_W
152 || registerAddr == MPUREG_MEM_R_W) {
153 return ML_ERROR_INVALID_PARAMETER;
154 }
155 while (bytesRead < length) {
156 unsigned short thisLen =
157 min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
158 result =
159 sensor_i2c_read((struct i2c_adapter *) sl_handle,
160 slaveAddr, registerAddr + bytesRead,
161 thisLen, &data[bytesRead]);
162 if (ML_SUCCESS != result)
163 return result;
164 bytesRead += thisLen;
165 }
166 return ML_SUCCESS;
167}
168
169
170/**
171 * @brief used to write multiple bytes of data to the memory.
172 * This should be sent by I2C.
173 *
174 * @param slaveAddr I2C slave address of device.
175 * @param memAddr The location in the memory to write to.
176 * @param length Length of burst data.
177 * @param data Pointer to block of data.
178 *
179 * @return Zero if successful; an error code otherwise
180 */
181tMLError MLSLSerialWriteMem(void *sl_handle,
182 unsigned char slaveAddr,
183 unsigned short memAddr,
184 unsigned short length,
185 unsigned char const *data)
186{
187 tMLError result;
188 unsigned short bytesWritten = 0;
189
190 if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) {
191 pr_err("memory read length (%d B) extends beyond its"
192 " limits (%d) if started at location %d\n", length,
193 MPU_MEM_BANK_SIZE, memAddr & 0xFF);
194 return ML_ERROR_INVALID_PARAMETER;
195 }
196 while (bytesWritten < length) {
197 unsigned short thisLen =
198 min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten);
199 result =
200 mpu_memory_write((struct i2c_adapter *) sl_handle,
201 slaveAddr, memAddr + bytesWritten,
202 thisLen, &data[bytesWritten]);
203 if (ML_SUCCESS != result)
204 return result;
205 bytesWritten += thisLen;
206 }
207 return ML_SUCCESS;
208}
209
210
211/**
212 * @brief used to read multiple bytes of data from the memory.
213 * This should be sent by I2C.
214 *
215 * @param slaveAddr I2C slave address of device.
216 * @param memAddr The location in the memory to read from.
217 * @param length Length of burst data.
218 * @param data Pointer to block of data.
219 *
220 * @return Zero if successful; an error code otherwise
221 */
222tMLError MLSLSerialReadMem(void *sl_handle,
223 unsigned char slaveAddr,
224 unsigned short memAddr,
225 unsigned short length, unsigned char *data)
226{
227 tMLError result;
228 unsigned short bytesRead = 0;
229
230 if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) {
231 printk
232 ("memory read length (%d B) extends beyond its limits (%d) "
233 "if started at location %d\n", length,
234 MPU_MEM_BANK_SIZE, memAddr & 0xFF);
235 return ML_ERROR_INVALID_PARAMETER;
236 }
237 while (bytesRead < length) {
238 unsigned short thisLen =
239 min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
240 result =
241 mpu_memory_read((struct i2c_adapter *) sl_handle,
242 slaveAddr, memAddr + bytesRead,
243 thisLen, &data[bytesRead]);
244 if (ML_SUCCESS != result)
245 return result;
246 bytesRead += thisLen;
247 }
248 return ML_SUCCESS;
249}
250
251
252/**
253 * @brief used to write multiple bytes of data to the fifo.
254 * This should be sent by I2C.
255 *
256 * @param slaveAddr I2C slave address of device.
257 * @param length Length of burst of data.
258 * @param data Pointer to block of data.
259 *
260 * @return Zero if successful; an error code otherwise
261 */
262tMLError MLSLSerialWriteFifo(void *sl_handle,
263 unsigned char slaveAddr,
264 unsigned short length,
265 unsigned char const *data)
266{
267 tMLError result;
268 unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1];
269 unsigned short bytesWritten = 0;
270
271 if (length > FIFO_HW_SIZE) {
272 printk(KERN_ERR
273 "maximum fifo write length is %d\n", FIFO_HW_SIZE);
274 return ML_ERROR_INVALID_PARAMETER;
275 }
276 while (bytesWritten < length) {
277 unsigned short thisLen =
278 min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten);
279 i2cWrite[0] = MPUREG_FIFO_R_W;
280 memcpy(&i2cWrite[1], &data[bytesWritten], thisLen);
281 result = sensor_i2c_write((struct i2c_adapter *) sl_handle,
282 slaveAddr, thisLen + 1,
283 i2cWrite);
284 if (ML_SUCCESS != result)
285 return result;
286 bytesWritten += thisLen;
287 }
288 return ML_SUCCESS;
289}
290
291
292/**
293 * @brief used to read multiple bytes of data from the fifo.
294 * This should be sent by I2C.
295 *
296 * @param slaveAddr I2C slave address of device.
297 * @param length Length of burst of data.
298 * @param data Pointer to block of data.
299 *
300 * @return Zero if successful; an error code otherwise
301 */
302tMLError MLSLSerialReadFifo(void *sl_handle,
303 unsigned char slaveAddr,
304 unsigned short length, unsigned char *data)
305{
306 tMLError result;
307 unsigned short bytesRead = 0;
308
309 if (length > FIFO_HW_SIZE) {
310 printk(KERN_ERR
311 "maximum fifo read length is %d\n", FIFO_HW_SIZE);
312 return ML_ERROR_INVALID_PARAMETER;
313 }
314 while (bytesRead < length) {
315 unsigned short thisLen =
316 min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
317 result =
318 sensor_i2c_read((struct i2c_adapter *) sl_handle,
319 slaveAddr, MPUREG_FIFO_R_W, thisLen,
320 &data[bytesRead]);
321 if (ML_SUCCESS != result)
322 return result;
323 bytesRead += thisLen;
324 }
325
326 return ML_SUCCESS;
327}
328
329/**
330 * @}
331 */
diff --git a/drivers/misc/mpu3050/mlsl.h b/drivers/misc/mpu3050/mlsl.h
new file mode 100644
index 00000000000..76f69c77ba9
--- /dev/null
+++ b/drivers/misc/mpu3050/mlsl.h
@@ -0,0 +1,103 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20#ifndef __MSSL_H__
21#define __MSSL_H__
22
23#include "mltypes.h"
24#include "mpu.h"
25
26#ifdef __cplusplus
27extern "C" {
28#endif
29
30/* ------------ */
31/* - Defines. - */
32/* ------------ */
33
34/*
35 * NOTE : to properly support Yamaha compass reads,
36 * the max transfer size should be at least 9 B.
37 * Length in bytes, typically a power of 2 >= 2
38 */
39#define SERIAL_MAX_TRANSFER_SIZE 128
40
41/* ---------------------- */
42/* - Types definitions. - */
43/* ---------------------- */
44
45/* --------------------- */
46/* - Function p-types. - */
47/* --------------------- */
48
49 tMLError MLSLSerialOpen(char const *port,
50 void **sl_handle);
51 tMLError MLSLSerialReset(void *sl_handle);
52 tMLError MLSLSerialClose(void *sl_handle);
53
54 tMLError MLSLSerialWriteSingle(void *sl_handle,
55 unsigned char slaveAddr,
56 unsigned char registerAddr,
57 unsigned char data);
58
59 tMLError MLSLSerialRead(void *sl_handle,
60 unsigned char slaveAddr,
61 unsigned char registerAddr,
62 unsigned short length,
63 unsigned char *data);
64
65 tMLError MLSLSerialWrite(void *sl_handle,
66 unsigned char slaveAddr,
67 unsigned short length,
68 unsigned char const *data);
69
70 tMLError MLSLSerialReadMem(void *sl_handle,
71 unsigned char slaveAddr,
72 unsigned short memAddr,
73 unsigned short length,
74 unsigned char *data);
75
76 tMLError MLSLSerialWriteMem(void *sl_handle,
77 unsigned char slaveAddr,
78 unsigned short memAddr,
79 unsigned short length,
80 unsigned char const *data);
81
82 tMLError MLSLSerialReadFifo(void *sl_handle,
83 unsigned char slaveAddr,
84 unsigned short length,
85 unsigned char *data);
86
87 tMLError MLSLSerialWriteFifo(void *sl_handle,
88 unsigned char slaveAddr,
89 unsigned short length,
90 unsigned char const *data);
91
92 tMLError MLSLWriteCal(unsigned char *cal, unsigned int len);
93 tMLError MLSLReadCal(unsigned char *cal, unsigned int len);
94 tMLError MLSLGetCalLength(unsigned int *len);
95
96#ifdef __cplusplus
97}
98#endif
99
100/**
101 * @}
102 */
103#endif /* MLSL_H */
diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h
new file mode 100644
index 00000000000..d0b27fa89e7
--- /dev/null
+++ b/drivers/misc/mpu3050/mltypes.h
@@ -0,0 +1,227 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @defgroup MLERROR
22 * @brief Motion Library - Error definitions.
23 * Definition of the error codes used within the MPL and returned
24 * to the user.
25 * Every function tries to return a meaningful error code basing
26 * on the occuring error condition. The error code is numeric.
27 *
28 * The available error codes and their associated values are:
29 * - (0) ML_SUCCESS
30 * - (1) ML_ERROR
31 * - (2) ML_ERROR_INVALID_PARAMETER
32 * - (3) ML_ERROR_FEATURE_NOT_ENABLED
33 * - (4) ML_ERROR_FEATURE_NOT_IMPLEMENTED
34 * - (6) ML_ERROR_DMP_NOT_STARTED
35 * - (7) ML_ERROR_DMP_STARTED
36 * - (8) ML_ERROR_NOT_OPENED
37 * - (9) ML_ERROR_OPENED
38 * - (10) ML_ERROR_INVALID_MODULE
39 * - (11) ML_ERROR_MEMORY_EXAUSTED
40 * - (12) ML_ERROR_DIVIDE_BY_ZERO
41 * - (13) ML_ERROR_ASSERTION_FAILURE
42 * - (14) ML_ERROR_FILE_OPEN
43 * - (15) ML_ERROR_FILE_READ
44 * - (16) ML_ERROR_FILE_WRITE
45 * - (20) ML_ERROR_SERIAL_CLOSED
46 * - (21) ML_ERROR_SERIAL_OPEN_ERROR
47 * - (22) ML_ERROR_SERIAL_READ
48 * - (23) ML_ERROR_SERIAL_WRITE
49 * - (24) ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED
50 * - (25) ML_ERROR_SM_TRANSITION
51 * - (26) ML_ERROR_SM_IMPROPER_STATE
52 * - (30) ML_ERROR_FIFO_OVERFLOW
53 * - (31) ML_ERROR_FIFO_FOOTER
54 * - (32) ML_ERROR_FIFO_READ_COUNT
55 * - (33) ML_ERROR_FIFO_READ_DATA
56 * - (40) ML_ERROR_MEMORY_SET
57 * - (50) ML_ERROR_LOG_MEMORY_ERROR
58 * - (51) ML_ERROR_LOG_OUTPUT_ERROR
59 * - (60) ML_ERROR_OS_BAD_PTR
60 * - (61) ML_ERROR_OS_BAD_HANDLE
61 * - (62) ML_ERROR_OS_CREATE_FAILED
62 * - (63) ML_ERROR_OS_LOCK_FAILED
63 * - (70) ML_ERROR_COMPASS_DATA_OVERFLOW
64 * - (71) ML_ERROR_COMPASS_DATA_UNDERFLOW
65 * - (72) ML_ERROR_COMPASS_DATA_NOT_READY
66 * - (73) ML_ERROR_COMPASS_DATA_ERROR
67 * - (75) ML_ERROR_CALIBRATION_LOAD
68 * - (76) ML_ERROR_CALIBRATION_STORE
69 * - (77) ML_ERROR_CALIBRATION_LEN
70 * - (78) ML_ERROR_CALIBRATION_CHECKSUM
71 *
72 * @{
73 * @file mltypes.h
74 * @}
75 */
76
77#ifndef MLTYPES_H
78#define MLTYPES_H
79
80#ifdef __KERNEL__
81#include <linux/types.h>
82#else
83#include "stdint_invensense.h"
84#endif
85#include "log.h"
86
87/*---------------------------
88 ML Types
89---------------------------*/
90
91/**
92 * @struct tMLError mltypes.h "mltypes"
93 * @brief The MPL Error Code return type.
94 *
95 * @code
96 * typedef unsigned char tMLError;
97 * @endcode
98 */
99typedef unsigned char tMLError;
100
101#if defined(LINUX) || defined(__KERNEL__)
102typedef unsigned int HANDLE;
103#endif
104
105#ifdef __KERNEL__
106typedef HANDLE FILE;
107#endif
108
109#ifndef __cplusplus
110#ifndef __KERNEL__
111typedef int_fast8_t bool;
112#endif
113#endif
114
115/*---------------------------
116 ML Defines
117---------------------------*/
118
119#ifndef NULL
120#define NULL 0
121#endif
122
123#ifndef TRUE
124#define TRUE 1
125#endif
126
127#ifndef FALSE
128#define FALSE 0
129#endif
130
131/* Dimension of an array */
132#ifndef DIM
133#define DIM(array) (sizeof(array)/sizeof((array)[0]))
134#endif
135
136/* - ML Errors. - */
137#define ERROR_NAME(x) (#x)
138#define ERROR_CHECK(x) \
139 do { \
140 if (ML_SUCCESS != x) { \
141 MPL_LOGE("%s|%s|%d returning %d\n", \
142 __FILE__, __func__, __LINE__, x); \
143 return x; \
144 } \
145 } while (0)
146
147#define ERROR_CHECK_FIRST(first, x) \
148 { if (ML_SUCCESS == first) first = x; }
149
150#define ML_SUCCESS (0)
151/* Generic Error code. Proprietary Error Codes only */
152#define ML_ERROR (1)
153
154/* Compatibility and other generic error codes */
155#define ML_ERROR_INVALID_PARAMETER (2)
156#define ML_ERROR_FEATURE_NOT_ENABLED (3)
157#define ML_ERROR_FEATURE_NOT_IMPLEMENTED (4)
158#define ML_ERROR_DMP_NOT_STARTED (6)
159#define ML_ERROR_DMP_STARTED (7)
160#define ML_ERROR_NOT_OPENED (8)
161#define ML_ERROR_OPENED (9)
162#define ML_ERROR_INVALID_MODULE (10)
163#define ML_ERROR_MEMORY_EXAUSTED (11)
164#define ML_ERROR_DIVIDE_BY_ZERO (12)
165#define ML_ERROR_ASSERTION_FAILURE (13)
166#define ML_ERROR_FILE_OPEN (14)
167#define ML_ERROR_FILE_READ (15)
168#define ML_ERROR_FILE_WRITE (16)
169#define ML_ERROR_INVALID_CONFIGURATION (17)
170
171/* Serial Communication */
172#define ML_ERROR_SERIAL_CLOSED (20)
173#define ML_ERROR_SERIAL_OPEN_ERROR (21)
174#define ML_ERROR_SERIAL_READ (22)
175#define ML_ERROR_SERIAL_WRITE (23)
176#define ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED (24)
177
178/* SM = State Machine */
179#define ML_ERROR_SM_TRANSITION (25)
180#define ML_ERROR_SM_IMPROPER_STATE (26)
181
182/* Fifo */
183#define ML_ERROR_FIFO_OVERFLOW (30)
184#define ML_ERROR_FIFO_FOOTER (31)
185#define ML_ERROR_FIFO_READ_COUNT (32)
186#define ML_ERROR_FIFO_READ_DATA (33)
187
188/* Memory & Registers, Set & Get */
189#define ML_ERROR_MEMORY_SET (40)
190
191#define ML_ERROR_LOG_MEMORY_ERROR (50)
192#define ML_ERROR_LOG_OUTPUT_ERROR (51)
193
194/* OS interface errors */
195#define ML_ERROR_OS_BAD_PTR (60)
196#define ML_ERROR_OS_BAD_HANDLE (61)
197#define ML_ERROR_OS_CREATE_FAILED (62)
198#define ML_ERROR_OS_LOCK_FAILED (63)
199
200/* Compass errors */
201#define ML_ERROR_COMPASS_DATA_OVERFLOW (70)
202#define ML_ERROR_COMPASS_DATA_UNDERFLOW (71)
203#define ML_ERROR_COMPASS_DATA_NOT_READY (72)
204#define ML_ERROR_COMPASS_DATA_ERROR (73)
205
206/* Load/Store calibration */
207#define ML_ERROR_CALIBRATION_LOAD (75)
208#define ML_ERROR_CALIBRATION_STORE (76)
209#define ML_ERROR_CALIBRATION_LEN (77)
210#define ML_ERROR_CALIBRATION_CHECKSUM (78)
211
212/* Accel errors */
213#define ML_ERROR_ACCEL_DATA_OVERFLOW (79)
214#define ML_ERROR_ACCEL_DATA_UNDERFLOW (80)
215#define ML_ERROR_ACCEL_DATA_NOT_READY (81)
216#define ML_ERROR_ACCEL_DATA_ERROR (82)
217
218/* For Linux coding compliance */
219#ifndef __KERNEL__
220#define EXPORT_SYMBOL(x)
221#endif
222
223/*---------------------------
224 p-Types
225---------------------------*/
226
227#endif /* MLTYPES_H */
diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c
new file mode 100644
index 00000000000..4dba44d4548
--- /dev/null
+++ b/drivers/misc/mpu3050/mpu-dev.c
@@ -0,0 +1,1310 @@
1/*
2 mpu-dev.c - mpu3050 char device interface 2 $License:
3
4 Copyright (C) 1995-97 Simon G. Vogl
5 Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
6 Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
7
8 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23#include <linux/i2c.h>
24#include <linux/i2c-dev.h>
25#include <linux/interrupt.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/kernel.h>
29#include <linux/init.h>
30#include <linux/stat.h>
31#include <linux/irq.h>
32#include <linux/gpio.h>
33#include <linux/signal.h>
34#include <linux/miscdevice.h>
35#include <linux/slab.h>
36#include <linux/version.h>
37#include <linux/pm.h>
38#include <linux/mutex.h>
39#include <linux/suspend.h>
40#include <linux/poll.h>
41#ifdef CONFIG_HAS_EARLYSUSPEND
42#include <linux/earlysuspend.h>
43#endif
44
45#include <linux/errno.h>
46#include <linux/fs.h>
47#include <linux/mm.h>
48#include <linux/sched.h>
49#include <linux/wait.h>
50#include <linux/uaccess.h>
51#include <linux/io.h>
52
53#include "mpuirq.h"
54#include "slaveirq.h"
55#include "mlsl.h"
56#include "mpu-i2c.h"
57#include "mldl_cfg.h"
58#include "mpu.h"
59
60#define MPU3050_EARLY_SUSPEND_IN_DRIVER 0
61
62/* Platform data for the MPU */
63struct mpu_private_data {
64 struct mldl_cfg mldl_cfg;
65
66#ifdef CONFIG_HAS_EARLYSUSPEND
67 struct early_suspend early_suspend;
68#endif
69 struct mutex mutex;
70 wait_queue_head_t mpu_event_wait;
71 struct completion completion;
72 struct timer_list timeout;
73 struct notifier_block nb;
74 struct mpuirq_data mpu_pm_event;
75 int response_timeout; /* In seconds */
76 unsigned long event;
77 int pid;
78};
79
80static struct i2c_client *this_client;
81
82
83static void
84mpu_pm_timeout(u_long data)
85{
86 struct mpu_private_data *mpu = (struct mpu_private_data *) data;
87 dev_dbg(&this_client->adapter->dev, "%s\n", __func__);
88 complete(&mpu->completion);
89}
90
91static int mpu_pm_notifier_callback(struct notifier_block *nb,
92 unsigned long event,
93 void *unused)
94{
95 struct mpu_private_data *mpu =
96 container_of(nb, struct mpu_private_data, nb);
97 struct timeval event_time;
98 dev_dbg(&this_client->adapter->dev, "%s: %ld\n", __func__, event);
99
100 /* Prevent the file handle from being closed before we initialize
101 the completion event */
102 mutex_lock(&mpu->mutex);
103 if (!(mpu->pid) ||
104 (event != PM_SUSPEND_PREPARE && event != PM_POST_SUSPEND)) {
105 mutex_unlock(&mpu->mutex);
106 return NOTIFY_OK;
107 }
108
109 do_gettimeofday(&event_time);
110 mpu->mpu_pm_event.interruptcount++;
111 mpu->mpu_pm_event.irqtime =
112 (((long long) event_time.tv_sec) << 32) +
113 event_time.tv_usec;
114 mpu->mpu_pm_event.data_type = MPUIRQ_DATA_TYPE_PM_EVENT;
115 mpu->mpu_pm_event.data_size = sizeof(unsigned long);
116 mpu->mpu_pm_event.data = &mpu->event;
117
118 if (event == PM_SUSPEND_PREPARE)
119 mpu->event = MPU_PM_EVENT_SUSPEND_PREPARE;
120 if (event == PM_POST_SUSPEND)
121 mpu->event = MPU_PM_EVENT_POST_SUSPEND;
122
123 if (mpu->response_timeout > 0) {
124 mpu->timeout.expires = jiffies + mpu->response_timeout * HZ;
125 add_timer(&mpu->timeout);
126 }
127 INIT_COMPLETION(mpu->completion);
128 mutex_unlock(&mpu->mutex);
129
130 wake_up_interruptible(&mpu->mpu_event_wait);
131 wait_for_completion(&mpu->completion);
132 del_timer_sync(&mpu->timeout);
133 dev_dbg(&this_client->adapter->dev, "%s: %ld DONE\n", __func__, event);
134 return NOTIFY_OK;
135}
136
137static int mpu_open(struct inode *inode, struct file *file)
138{
139 struct mpu_private_data *mpu =
140 (struct mpu_private_data *) i2c_get_clientdata(this_client);
141 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
142 int result;
143 dev_dbg(&this_client->adapter->dev, "mpu_open\n");
144 dev_dbg(&this_client->adapter->dev, "current->pid %d\n",
145 current->pid);
146 mpu->pid = current->pid;
147 file->private_data = this_client;
148 /* we could do some checking on the flags supplied by "open" */
149 /* i.e. O_NONBLOCK */
150 /* -> set some flag to disable interruptible_sleep_on in mpu_read */
151
152 /* Reset the sensors to the default */
153 result = mutex_lock_interruptible(&mpu->mutex);
154 if (result) {
155 dev_err(&this_client->adapter->dev,
156 "%s: mutex_lock_interruptible returned %d\n",
157 __func__, result);
158 return result;
159 }
160 mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO;
161 if (mldl_cfg->accel && mldl_cfg->accel->resume)
162 mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL;
163
164 if (mldl_cfg->compass && mldl_cfg->compass->resume)
165 mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS;
166
167 if (mldl_cfg->pressure && mldl_cfg->pressure->resume)
168 mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE;
169 mutex_unlock(&mpu->mutex);
170 return 0;
171}
172
173/* close function - called when the "file" /dev/mpu is closed in userspace */
174static int mpu_release(struct inode *inode, struct file *file)
175{
176 struct i2c_client *client =
177 (struct i2c_client *) file->private_data;
178 struct mpu_private_data *mpu =
179 (struct mpu_private_data *) i2c_get_clientdata(client);
180 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
181 struct i2c_adapter *accel_adapter;
182 struct i2c_adapter *compass_adapter;
183 struct i2c_adapter *pressure_adapter;
184 int result = 0;
185
186 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
187 compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
188 pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
189
190 mutex_lock(&mpu->mutex);
191 result = mpu3050_suspend(mldl_cfg, client->adapter,
192 accel_adapter, compass_adapter,
193 pressure_adapter,
194 TRUE, TRUE, TRUE, TRUE);
195 mpu->pid = 0;
196 mutex_unlock(&mpu->mutex);
197 complete(&mpu->completion);
198 dev_dbg(&this_client->adapter->dev, "mpu_release\n");
199 return result;
200}
201
202/* read function called when from /dev/mpu is read. Read from the FIFO */
203static ssize_t mpu_read(struct file *file,
204 char __user *buf, size_t count, loff_t *offset)
205{
206 struct mpuirq_data local_mpu_pm_event;
207 struct i2c_client *client =
208 (struct i2c_client *) file->private_data;
209 struct mpu_private_data *mpu =
210 (struct mpu_private_data *) i2c_get_clientdata(client);
211 size_t len = sizeof(mpu->mpu_pm_event) + sizeof(unsigned long);
212 int err;
213
214 if (!mpu->event && (!(file->f_flags & O_NONBLOCK)))
215 wait_event_interruptible(mpu->mpu_event_wait, mpu->event);
216
217 if (!mpu->event || NULL == buf
218 || count < sizeof(mpu->mpu_pm_event) + sizeof(unsigned long))
219 return 0;
220
221 err = copy_from_user(&local_mpu_pm_event, buf,
222 sizeof(mpu->mpu_pm_event));
223 if (err != 0) {
224 dev_err(&this_client->adapter->dev,
225 "Copy from user returned %d\n", err);
226 return -EFAULT;
227 }
228
229 mpu->mpu_pm_event.data = local_mpu_pm_event.data;
230 err = copy_to_user((unsigned long __user *)local_mpu_pm_event.data,
231 &mpu->event,
232 sizeof(mpu->event));
233 if (err != 0) {
234 dev_err(&this_client->adapter->dev,
235 "Copy to user returned %d\n", err);
236 return -EFAULT;
237 }
238 err = copy_to_user(buf, &mpu->mpu_pm_event, sizeof(mpu->mpu_pm_event));
239 if (err != 0) {
240 dev_err(&this_client->adapter->dev,
241 "Copy to user returned %d\n", err);
242 return -EFAULT;
243 }
244 mpu->event = 0;
245 return len;
246}
247
248static unsigned int mpu_poll(struct file *file, struct poll_table_struct *poll)
249{
250 struct i2c_client *client =
251 (struct i2c_client *) file->private_data;
252 struct mpu_private_data *mpu =
253 (struct mpu_private_data *) i2c_get_clientdata(client);
254 int mask = 0;
255
256 poll_wait(file, &mpu->mpu_event_wait, poll);
257 if (mpu->event)
258 mask |= POLLIN | POLLRDNORM;
259 return mask;
260}
261
262static int
263mpu_ioctl_set_mpu_pdata(struct i2c_client *client, unsigned long arg)
264{
265 int ii;
266 struct mpu_private_data *mpu =
267 (struct mpu_private_data *) i2c_get_clientdata(client);
268 struct mpu3050_platform_data *pdata = mpu->mldl_cfg.pdata;
269 struct mpu3050_platform_data local_pdata;
270
271 if (copy_from_user(&local_pdata, (unsigned char __user *) arg,
272 sizeof(local_pdata)))
273 return -EFAULT;
274
275 pdata->int_config = local_pdata.int_config;
276 for (ii = 0; ii < DIM(pdata->orientation); ii++)
277 pdata->orientation[ii] = local_pdata.orientation[ii];
278 pdata->level_shifter = local_pdata.level_shifter;
279
280 pdata->accel.address = local_pdata.accel.address;
281 for (ii = 0; ii < DIM(pdata->accel.orientation); ii++)
282 pdata->accel.orientation[ii] =
283 local_pdata.accel.orientation[ii];
284
285 pdata->compass.address = local_pdata.compass.address;
286 for (ii = 0; ii < DIM(pdata->compass.orientation); ii++)
287 pdata->compass.orientation[ii] =
288 local_pdata.compass.orientation[ii];
289
290 pdata->pressure.address = local_pdata.pressure.address;
291 for (ii = 0; ii < DIM(pdata->pressure.orientation); ii++)
292 pdata->pressure.orientation[ii] =
293 local_pdata.pressure.orientation[ii];
294
295 dev_dbg(&client->adapter->dev, "%s\n", __func__);
296
297 return ML_SUCCESS;
298}
299
300static int
301mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg)
302{
303 int ii;
304 int result = ML_SUCCESS;
305 struct mpu_private_data *mpu =
306 (struct mpu_private_data *) i2c_get_clientdata(client);
307 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
308 struct mldl_cfg *temp_mldl_cfg;
309
310 dev_dbg(&this_client->adapter->dev, "%s\n", __func__);
311
312 temp_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
313 if (NULL == temp_mldl_cfg)
314 return -ENOMEM;
315
316 /*
317 * User space is not allowed to modify accel compass pressure or
318 * pdata structs, as well as silicon_revision product_id or trim
319 */
320 if (copy_from_user(temp_mldl_cfg, (struct mldl_cfg __user *) arg,
321 offsetof(struct mldl_cfg, silicon_revision))) {
322 result = -EFAULT;
323 goto out;
324 }
325
326 if (mldl_cfg->gyro_is_suspended) {
327 if (mldl_cfg->addr != temp_mldl_cfg->addr)
328 mldl_cfg->gyro_needs_reset = TRUE;
329
330 if (mldl_cfg->int_config != temp_mldl_cfg->int_config)
331 mldl_cfg->gyro_needs_reset = TRUE;
332
333 if (mldl_cfg->ext_sync != temp_mldl_cfg->ext_sync)
334 mldl_cfg->gyro_needs_reset = TRUE;
335
336 if (mldl_cfg->full_scale != temp_mldl_cfg->full_scale)
337 mldl_cfg->gyro_needs_reset = TRUE;
338
339 if (mldl_cfg->lpf != temp_mldl_cfg->lpf)
340 mldl_cfg->gyro_needs_reset = TRUE;
341
342 if (mldl_cfg->clk_src != temp_mldl_cfg->clk_src)
343 mldl_cfg->gyro_needs_reset = TRUE;
344
345 if (mldl_cfg->divider != temp_mldl_cfg->divider)
346 mldl_cfg->gyro_needs_reset = TRUE;
347
348 if (mldl_cfg->dmp_enable != temp_mldl_cfg->dmp_enable)
349 mldl_cfg->gyro_needs_reset = TRUE;
350
351 if (mldl_cfg->fifo_enable != temp_mldl_cfg->fifo_enable)
352 mldl_cfg->gyro_needs_reset = TRUE;
353
354 if (mldl_cfg->dmp_cfg1 != temp_mldl_cfg->dmp_cfg1)
355 mldl_cfg->gyro_needs_reset = TRUE;
356
357 if (mldl_cfg->dmp_cfg2 != temp_mldl_cfg->dmp_cfg2)
358 mldl_cfg->gyro_needs_reset = TRUE;
359
360 if (mldl_cfg->gyro_power != temp_mldl_cfg->gyro_power)
361 mldl_cfg->gyro_needs_reset = TRUE;
362
363 for (ii = 0; ii < MPU_NUM_AXES; ii++)
364 if (mldl_cfg->offset_tc[ii] !=
365 temp_mldl_cfg->offset_tc[ii])
366 mldl_cfg->gyro_needs_reset = TRUE;
367
368 for (ii = 0; ii < MPU_NUM_AXES; ii++)
369 if (mldl_cfg->offset[ii] != temp_mldl_cfg->offset[ii])
370 mldl_cfg->gyro_needs_reset = TRUE;
371
372 if (memcmp(mldl_cfg->ram, temp_mldl_cfg->ram,
373 MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE *
374 sizeof(unsigned char)))
375 mldl_cfg->gyro_needs_reset = TRUE;
376 }
377
378 memcpy(mldl_cfg, temp_mldl_cfg,
379 offsetof(struct mldl_cfg, silicon_revision));
380
381out:
382 kfree(temp_mldl_cfg);
383 return result;
384}
385
386static int
387mpu_ioctl_get_mpu_config(struct i2c_client *client, unsigned long arg)
388{
389 /* Have to be careful as there are 3 pointers in the mldl_cfg
390 * structure */
391 struct mpu_private_data *mpu =
392 (struct mpu_private_data *) i2c_get_clientdata(client);
393 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
394 struct mldl_cfg *local_mldl_cfg;
395 int retval = 0;
396
397 local_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
398 if (NULL == local_mldl_cfg)
399 return -ENOMEM;
400
401 retval =
402 copy_from_user(local_mldl_cfg, (struct mldl_cfg __user *) arg,
403 sizeof(struct mldl_cfg));
404 if (retval) {
405 dev_err(&this_client->adapter->dev,
406 "%s|%s:%d: EFAULT on arg\n",
407 __FILE__, __func__, __LINE__);
408 retval = -EFAULT;
409 goto out;
410 }
411
412 /* Fill in the accel, compass, pressure and pdata pointers */
413 if (mldl_cfg->accel) {
414 retval = copy_to_user((void __user *)local_mldl_cfg->accel,
415 mldl_cfg->accel,
416 sizeof(*mldl_cfg->accel));
417 if (retval) {
418 dev_err(&this_client->adapter->dev,
419 "%s|%s:%d: EFAULT on accel\n",
420 __FILE__, __func__, __LINE__);
421 retval = -EFAULT;
422 goto out;
423 }
424 }
425
426 if (mldl_cfg->compass) {
427 retval = copy_to_user((void __user *)local_mldl_cfg->compass,
428 mldl_cfg->compass,
429 sizeof(*mldl_cfg->compass));
430 if (retval) {
431 dev_err(&this_client->adapter->dev,
432 "%s|%s:%d: EFAULT on compass\n",
433 __FILE__, __func__, __LINE__);
434 retval = -EFAULT;
435 goto out;
436 }
437 }
438
439 if (mldl_cfg->pressure) {
440 retval = copy_to_user((void __user *)local_mldl_cfg->pressure,
441 mldl_cfg->pressure,
442 sizeof(*mldl_cfg->pressure));
443 if (retval) {
444 dev_err(&this_client->adapter->dev,
445 "%s|%s:%d: EFAULT on pressure\n",
446 __FILE__, __func__, __LINE__);
447 retval = -EFAULT;
448 goto out;
449 }
450 }
451
452 if (mldl_cfg->pdata) {
453 retval = copy_to_user((void __user *)local_mldl_cfg->pdata,
454 mldl_cfg->pdata,
455 sizeof(*mldl_cfg->pdata));
456 if (retval) {
457 dev_err(&this_client->adapter->dev,
458 "%s|%s:%d: EFAULT on pdata\n",
459 __FILE__, __func__, __LINE__);
460 retval = -EFAULT;
461 goto out;
462 }
463 }
464
465 /* Do not modify the accel, compass, pressure and pdata pointers */
466 retval = copy_to_user((struct mldl_cfg __user *) arg,
467 mldl_cfg, offsetof(struct mldl_cfg, accel));
468
469 if (retval)
470 retval = -EFAULT;
471out:
472 kfree(local_mldl_cfg);
473 return retval;
474}
475
476/**
477 * Pass a requested slave configuration to the slave sensor
478 *
479 * @param adapter the adaptor to use to communicate with the slave
480 * @param mldl_cfg the mldl configuration structuer
481 * @param slave pointer to the slave descriptor
482 * @param usr_config The configuration to pass to the slave sensor
483 *
484 * @return 0 or non-zero error code
485 */
486static int slave_config(void *adapter,
487 struct mldl_cfg *mldl_cfg,
488 struct ext_slave_descr *slave,
489 struct ext_slave_platform_data *pdata,
490 struct ext_slave_config __user *usr_config)
491{
492 int retval = ML_SUCCESS;
493 struct ext_slave_config config;
494 if ((!slave) || (!slave->config))
495 return retval;
496
497 retval = copy_from_user(&config, usr_config, sizeof(config));
498 if (retval)
499 return -EFAULT;
500
501 if (config.len && config.data) {
502 int *data;
503 data = kzalloc(config.len, GFP_KERNEL);
504 if (!data)
505 return ML_ERROR_MEMORY_EXAUSTED;
506
507 retval = copy_from_user(data,
508 (void __user *)config.data,
509 config.len);
510 if (retval) {
511 retval = -EFAULT;
512 kfree(data);
513 return retval;
514 }
515 config.data = data;
516 }
517 retval = slave->config(adapter, slave, pdata, &config);
518 kfree(config.data);
519 return retval;
520}
521
522/**
523 * Get a requested slave configuration from the slave sensor
524 *
525 * @param adapter the adaptor to use to communicate with the slave
526 * @param mldl_cfg the mldl configuration structuer
527 * @param slave pointer to the slave descriptor
528 * @param usr_config The configuration for the slave to fill out
529 *
530 * @return 0 or non-zero error code
531 */
532static int slave_get_config(void *adapter,
533 struct mldl_cfg *mldl_cfg,
534 struct ext_slave_descr *slave,
535 struct ext_slave_platform_data *pdata,
536 struct ext_slave_config __user *usr_config)
537{
538 int retval = ML_SUCCESS;
539 struct ext_slave_config config;
540 void *user_data;
541 if (!(slave) || !(slave->get_config))
542 return ML_SUCCESS;
543
544 retval = copy_from_user(&config, usr_config, sizeof(config));
545 if (retval)
546 return -EFAULT;
547
548 user_data = config.data;
549 if (config.len && config.data) {
550 int *data;
551 data = kzalloc(config.len, GFP_KERNEL);
552 if (!data)
553 return ML_ERROR_MEMORY_EXAUSTED;
554
555 retval = copy_from_user(data,
556 (void __user *)config.data,
557 config.len);
558 if (retval) {
559 retval = -EFAULT;
560 kfree(data);
561 return retval;
562 }
563 config.data = data;
564 }
565 retval = slave->get_config(adapter, slave, pdata, &config);
566 if (retval) {
567 kfree(config.data);
568 return retval;
569 }
570 retval = copy_to_user((unsigned char __user *) user_data,
571 config.data,
572 config.len);
573 kfree(config.data);
574 return retval;
575}
576
577static int mpu_handle_mlsl(void *sl_handle,
578 unsigned char addr,
579 unsigned int cmd,
580 struct mpu_read_write __user *usr_msg)
581{
582 int retval = ML_SUCCESS;
583 struct mpu_read_write msg;
584 unsigned char *user_data;
585 retval = copy_from_user(&msg, usr_msg, sizeof(msg));
586 if (retval)
587 return -EFAULT;
588
589 user_data = msg.data;
590 if (msg.length && msg.data) {
591 unsigned char *data;
592 data = kzalloc(msg.length, GFP_KERNEL);
593 if (!data)
594 return ML_ERROR_MEMORY_EXAUSTED;
595
596 retval = copy_from_user(data,
597 (void __user *)msg.data,
598 msg.length);
599 if (retval) {
600 retval = -EFAULT;
601 kfree(data);
602 return retval;
603 }
604 msg.data = data;
605 } else {
606 return ML_ERROR_INVALID_PARAMETER;
607 }
608
609 switch (cmd) {
610 case MPU_READ:
611 retval = MLSLSerialRead(sl_handle, addr,
612 msg.address, msg.length, msg.data);
613 break;
614 case MPU_WRITE:
615 retval = MLSLSerialWrite(sl_handle, addr,
616 msg.length, msg.data);
617 break;
618 case MPU_READ_MEM:
619 retval = MLSLSerialReadMem(sl_handle, addr,
620 msg.address, msg.length, msg.data);
621 break;
622 case MPU_WRITE_MEM:
623 retval = MLSLSerialWriteMem(sl_handle, addr,
624 msg.address, msg.length, msg.data);
625 break;
626 case MPU_READ_FIFO:
627 retval = MLSLSerialReadFifo(sl_handle, addr,
628 msg.length, msg.data);
629 break;
630 case MPU_WRITE_FIFO:
631 retval = MLSLSerialWriteFifo(sl_handle, addr,
632 msg.length, msg.data);
633 break;
634
635 };
636 retval = copy_to_user((unsigned char __user *) user_data,
637 msg.data,
638 msg.length);
639 kfree(msg.data);
640 return retval;
641}
642
643/* ioctl - I/O control */
644static long mpu_ioctl(struct file *file,
645 unsigned int cmd, unsigned long arg)
646{
647 struct i2c_client *client =
648 (struct i2c_client *) file->private_data;
649 struct mpu_private_data *mpu =
650 (struct mpu_private_data *) i2c_get_clientdata(client);
651 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
652 int retval = 0;
653 struct i2c_adapter *accel_adapter;
654 struct i2c_adapter *compass_adapter;
655 struct i2c_adapter *pressure_adapter;
656
657 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
658 compass_adapter =
659 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
660 pressure_adapter =
661 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
662
663 retval = mutex_lock_interruptible(&mpu->mutex);
664 if (retval) {
665 dev_err(&this_client->adapter->dev,
666 "%s: mutex_lock_interruptible returned %d\n",
667 __func__, retval);
668 return retval;
669 }
670
671 switch (cmd) {
672 case MPU_SET_MPU_CONFIG:
673 retval = mpu_ioctl_set_mpu_config(client, arg);
674 break;
675 case MPU_SET_PLATFORM_DATA:
676 retval = mpu_ioctl_set_mpu_pdata(client, arg);
677 break;
678 case MPU_GET_MPU_CONFIG:
679 retval = mpu_ioctl_get_mpu_config(client, arg);
680 break;
681 case MPU_READ:
682 case MPU_WRITE:
683 case MPU_READ_MEM:
684 case MPU_WRITE_MEM:
685 case MPU_READ_FIFO:
686 case MPU_WRITE_FIFO:
687 retval = mpu_handle_mlsl(client->adapter, mldl_cfg->addr, cmd,
688 (struct mpu_read_write __user *) arg);
689 break;
690 case MPU_CONFIG_ACCEL:
691 retval = slave_config(accel_adapter, mldl_cfg,
692 mldl_cfg->accel,
693 &mldl_cfg->pdata->accel,
694 (struct ext_slave_config __user *) arg);
695 break;
696 case MPU_CONFIG_COMPASS:
697 retval = slave_config(compass_adapter, mldl_cfg,
698 mldl_cfg->compass,
699 &mldl_cfg->pdata->compass,
700 (struct ext_slave_config __user *) arg);
701 break;
702 case MPU_CONFIG_PRESSURE:
703 retval = slave_config(pressure_adapter, mldl_cfg,
704 mldl_cfg->pressure,
705 &mldl_cfg->pdata->pressure,
706 (struct ext_slave_config __user *) arg);
707 break;
708 case MPU_GET_CONFIG_ACCEL:
709 retval = slave_get_config(accel_adapter, mldl_cfg,
710 mldl_cfg->accel,
711 &mldl_cfg->pdata->accel,
712 (struct ext_slave_config __user *) arg);
713 break;
714 case MPU_GET_CONFIG_COMPASS:
715 retval = slave_get_config(compass_adapter, mldl_cfg,
716 mldl_cfg->compass,
717 &mldl_cfg->pdata->compass,
718 (struct ext_slave_config __user *) arg);
719 break;
720 case MPU_GET_CONFIG_PRESSURE:
721 retval = slave_get_config(pressure_adapter, mldl_cfg,
722 mldl_cfg->pressure,
723 &mldl_cfg->pdata->pressure,
724 (struct ext_slave_config __user *) arg);
725 break;
726 case MPU_SUSPEND:
727 {
728 unsigned long sensors;
729 sensors = ~(mldl_cfg->requested_sensors);
730 retval = mpu3050_suspend(mldl_cfg,
731 client->adapter,
732 accel_adapter,
733 compass_adapter,
734 pressure_adapter,
735 ((sensors & ML_THREE_AXIS_GYRO)
736 == ML_THREE_AXIS_GYRO),
737 ((sensors & ML_THREE_AXIS_ACCEL)
738 == ML_THREE_AXIS_ACCEL),
739 ((sensors & ML_THREE_AXIS_COMPASS)
740 == ML_THREE_AXIS_COMPASS),
741 ((sensors & ML_THREE_AXIS_PRESSURE)
742 == ML_THREE_AXIS_PRESSURE));
743 }
744 break;
745 case MPU_RESUME:
746 {
747 unsigned long sensors;
748 sensors = mldl_cfg->requested_sensors;
749 retval = mpu3050_resume(mldl_cfg,
750 client->adapter,
751 accel_adapter,
752 compass_adapter,
753 pressure_adapter,
754 sensors & ML_THREE_AXIS_GYRO,
755 sensors & ML_THREE_AXIS_ACCEL,
756 sensors & ML_THREE_AXIS_COMPASS,
757 sensors & ML_THREE_AXIS_PRESSURE);
758 }
759 break;
760 case MPU_PM_EVENT_HANDLED:
761 dev_dbg(&this_client->adapter->dev,
762 "%s: %d\n", __func__, cmd);
763 complete(&mpu->completion);
764 break;
765 case MPU_READ_ACCEL:
766 {
767 unsigned char data[6];
768 retval = mpu3050_read_accel(mldl_cfg, client->adapter,
769 data);
770 if ((ML_SUCCESS == retval) &&
771 (copy_to_user((unsigned char __user *) arg,
772 data, sizeof(data))))
773 retval = -EFAULT;
774 }
775 break;
776 case MPU_READ_COMPASS:
777 {
778 unsigned char data[6];
779 struct i2c_adapter *compass_adapt =
780 i2c_get_adapter(mldl_cfg->pdata->compass.
781 adapt_num);
782 retval = mpu3050_read_compass(mldl_cfg, compass_adapt,
783 data);
784 if ((ML_SUCCESS == retval) &&
785 (copy_to_user((unsigned char *) arg,
786 data, sizeof(data))))
787 retval = -EFAULT;
788 }
789 break;
790 case MPU_READ_PRESSURE:
791 {
792 unsigned char data[3];
793 struct i2c_adapter *pressure_adapt =
794 i2c_get_adapter(mldl_cfg->pdata->pressure.
795 adapt_num);
796 retval =
797 mpu3050_read_pressure(mldl_cfg, pressure_adapt,
798 data);
799 if ((ML_SUCCESS == retval) &&
800 (copy_to_user((unsigned char __user *) arg,
801 data, sizeof(data))))
802 retval = -EFAULT;
803 }
804 break;
805 default:
806 dev_err(&this_client->adapter->dev,
807 "%s: Unknown cmd %x, arg %lu\n", __func__, cmd,
808 arg);
809 retval = -EINVAL;
810 }
811
812 mutex_unlock(&mpu->mutex);
813 return retval;
814}
815
816#ifdef CONFIG_HAS_EARLYSUSPEND
817void mpu3050_early_suspend(struct early_suspend *h)
818{
819 struct mpu_private_data *mpu = container_of(h,
820 struct
821 mpu_private_data,
822 early_suspend);
823 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
824 struct i2c_adapter *accel_adapter;
825 struct i2c_adapter *compass_adapter;
826 struct i2c_adapter *pressure_adapter;
827
828 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
829 compass_adapter =
830 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
831 pressure_adapter =
832 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
833
834 dev_dbg(&this_client->adapter->dev, "%s: %d, %d\n", __func__,
835 h->level, mpu->mldl_cfg.gyro_is_suspended);
836 if (MPU3050_EARLY_SUSPEND_IN_DRIVER) {
837 mutex_lock(&mpu->mutex);
838 (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
839 accel_adapter, compass_adapter,
840 pressure_adapter, TRUE, TRUE, TRUE, TRUE);
841 mutex_unlock(&mpu->mutex);
842 }
843}
844
845void mpu3050_early_resume(struct early_suspend *h)
846{
847 struct mpu_private_data *mpu = container_of(h,
848 struct
849 mpu_private_data,
850 early_suspend);
851 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
852 struct i2c_adapter *accel_adapter;
853 struct i2c_adapter *compass_adapter;
854 struct i2c_adapter *pressure_adapter;
855
856 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
857 compass_adapter =
858 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
859 pressure_adapter =
860 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
861
862 if (MPU3050_EARLY_SUSPEND_IN_DRIVER) {
863 if (mpu->pid) {
864 unsigned long sensors = mldl_cfg->requested_sensors;
865 mutex_lock(&mpu->mutex);
866 (void) mpu3050_resume(mldl_cfg,
867 this_client->adapter,
868 accel_adapter,
869 compass_adapter,
870 pressure_adapter,
871 sensors & ML_THREE_AXIS_GYRO,
872 sensors & ML_THREE_AXIS_ACCEL,
873 sensors & ML_THREE_AXIS_COMPASS,
874 sensors & ML_THREE_AXIS_PRESSURE);
875 mutex_unlock(&mpu->mutex);
876 dev_dbg(&this_client->adapter->dev,
877 "%s for pid %d\n", __func__, mpu->pid);
878 }
879 }
880 dev_dbg(&this_client->adapter->dev, "%s: %d\n", __func__, h->level);
881}
882#endif
883
884void mpu_shutdown(struct i2c_client *client)
885{
886 struct mpu_private_data *mpu =
887 (struct mpu_private_data *) i2c_get_clientdata(client);
888 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
889 struct i2c_adapter *accel_adapter;
890 struct i2c_adapter *compass_adapter;
891 struct i2c_adapter *pressure_adapter;
892
893 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
894 compass_adapter =
895 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
896 pressure_adapter =
897 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
898
899 mutex_lock(&mpu->mutex);
900 (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
901 accel_adapter, compass_adapter, pressure_adapter,
902 TRUE, TRUE, TRUE, TRUE);
903 mutex_unlock(&mpu->mutex);
904 dev_dbg(&this_client->adapter->dev, "%s\n", __func__);
905}
906
907int mpu_suspend(struct i2c_client *client, pm_message_t mesg)
908{
909 struct mpu_private_data *mpu =
910 (struct mpu_private_data *) i2c_get_clientdata(client);
911 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
912 struct i2c_adapter *accel_adapter;
913 struct i2c_adapter *compass_adapter;
914 struct i2c_adapter *pressure_adapter;
915
916 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
917 compass_adapter =
918 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
919 pressure_adapter =
920 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
921
922 mutex_lock(&mpu->mutex);
923 if (!mldl_cfg->ignore_system_suspend) {
924 dev_dbg(&this_client->adapter->dev,
925 "%s: suspending on event %d\n", __func__,
926 mesg.event);
927 (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
928 accel_adapter, compass_adapter,
929 pressure_adapter,
930 TRUE, TRUE, TRUE, TRUE);
931 } else {
932 dev_dbg(&this_client->adapter->dev,
933 "%s: Already suspended %d\n", __func__,
934 mesg.event);
935 }
936 mutex_unlock(&mpu->mutex);
937 return 0;
938}
939
940int mpu_resume(struct i2c_client *client)
941{
942 struct mpu_private_data *mpu =
943 (struct mpu_private_data *) i2c_get_clientdata(client);
944 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
945 struct i2c_adapter *accel_adapter;
946 struct i2c_adapter *compass_adapter;
947 struct i2c_adapter *pressure_adapter;
948
949 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
950 compass_adapter =
951 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
952 pressure_adapter =
953 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
954
955 mutex_lock(&mpu->mutex);
956 if (mpu->pid && !mldl_cfg->ignore_system_suspend) {
957 unsigned long sensors = mldl_cfg->requested_sensors;
958 (void) mpu3050_resume(mldl_cfg, this_client->adapter,
959 accel_adapter,
960 compass_adapter,
961 pressure_adapter,
962 sensors & ML_THREE_AXIS_GYRO,
963 sensors & ML_THREE_AXIS_ACCEL,
964 sensors & ML_THREE_AXIS_COMPASS,
965 sensors & ML_THREE_AXIS_PRESSURE);
966 dev_dbg(&this_client->adapter->dev,
967 "%s for pid %d\n", __func__, mpu->pid);
968 }
969 mutex_unlock(&mpu->mutex);
970 return 0;
971}
972
973/* define which file operations are supported */
974static const struct file_operations mpu_fops = {
975 .owner = THIS_MODULE,
976 .read = mpu_read,
977 .poll = mpu_poll,
978
979#if HAVE_COMPAT_IOCTL
980 .compat_ioctl = mpu_ioctl,
981#endif
982#if HAVE_UNLOCKED_IOCTL
983 .unlocked_ioctl = mpu_ioctl,
984#endif
985 .open = mpu_open,
986 .release = mpu_release,
987};
988
989static unsigned short normal_i2c[] = { I2C_CLIENT_END };
990
991#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
992I2C_CLIENT_INSMOD;
993#endif
994
995static struct miscdevice i2c_mpu_device = {
996 .minor = MISC_DYNAMIC_MINOR,
997 .name = "mpu", /* Same for both 3050 and 6000 */
998 .fops = &mpu_fops,
999};
1000
1001
1002int mpu3050_probe(struct i2c_client *client,
1003 const struct i2c_device_id *devid)
1004{
1005 struct mpu3050_platform_data *pdata;
1006 struct mpu_private_data *mpu;
1007 struct mldl_cfg *mldl_cfg;
1008 int res = 0;
1009 struct i2c_adapter *accel_adapter = NULL;
1010 struct i2c_adapter *compass_adapter = NULL;
1011 struct i2c_adapter *pressure_adapter = NULL;
1012 dev_dbg(&client->adapter->dev, "%s\n", __func__);
1013
1014 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
1015 res = -ENODEV;
1016 goto out_check_functionality_failed;
1017 }
1018
1019 mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL);
1020 if (!mpu) {
1021 res = -ENOMEM;
1022 goto out_alloc_data_failed;
1023 }
1024
1025 i2c_set_clientdata(client, mpu);
1026 this_client = client;
1027 mldl_cfg = &mpu->mldl_cfg;
1028
1029 init_waitqueue_head(&mpu->mpu_event_wait);
1030
1031 mutex_init(&mpu->mutex);
1032 init_completion(&mpu->completion);
1033
1034 mpu->response_timeout = 60; /* Seconds */
1035 mpu->timeout.function = mpu_pm_timeout;
1036 mpu->timeout.data = (u_long) mpu;
1037 init_timer(&mpu->timeout);
1038
1039 /* FIXME:
1040 * Do not register the pm_notifier as it causes
1041 * issues with resume sequence as there is no response
1042 * from user-space for power notifications for approx
1043 * 60 sec. Refer NV bug 858630 for more details.
1044 */
1045#if 0
1046 mpu->nb.notifier_call = mpu_pm_notifier_callback;
1047 mpu->nb.priority = 0;
1048 register_pm_notifier(&mpu->nb);
1049#endif
1050
1051 pdata = (struct mpu3050_platform_data *) client->dev.platform_data;
1052 if (!pdata) {
1053 dev_warn(&this_client->adapter->dev,
1054 "Missing platform data for mpu3050\n");
1055 } else {
1056 mldl_cfg->pdata = pdata;
1057
1058#if defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) || \
1059 defined(CONFIG_MPU_SENSORS_MPU6000_MODULE)
1060 pdata->accel.get_slave_descr = get_accel_slave_descr;
1061 pdata->compass.get_slave_descr = get_compass_slave_descr;
1062 pdata->pressure.get_slave_descr = get_pressure_slave_descr;
1063#endif
1064
1065 if (pdata->accel.get_slave_descr) {
1066 mldl_cfg->accel =
1067 pdata->accel.get_slave_descr();
1068 dev_info(&this_client->adapter->dev,
1069 "%s: +%s\n", MPU_NAME,
1070 mldl_cfg->accel->name);
1071 accel_adapter =
1072 i2c_get_adapter(pdata->accel.adapt_num);
1073 if (pdata->accel.irq > 0) {
1074 dev_info(&this_client->adapter->dev,
1075 "Installing Accel irq using %d\n",
1076 pdata->accel.irq);
1077 res = slaveirq_init(accel_adapter,
1078 &pdata->accel,
1079 "accelirq");
1080 if (res)
1081 goto out_accelirq_failed;
1082 } else {
1083 dev_warn(&this_client->adapter->dev,
1084 "WARNING: Accel irq not assigned\n");
1085 }
1086 } else {
1087 dev_warn(&this_client->adapter->dev,
1088 "%s: No Accel Present\n", MPU_NAME);
1089 }
1090
1091 if (pdata->compass.get_slave_descr) {
1092 mldl_cfg->compass =
1093 pdata->compass.get_slave_descr();
1094 dev_info(&this_client->adapter->dev,
1095 "%s: +%s\n", MPU_NAME,
1096 mldl_cfg->compass->name);
1097 compass_adapter =
1098 i2c_get_adapter(pdata->compass.adapt_num);
1099 if (pdata->compass.irq > 0) {
1100 dev_info(&this_client->adapter->dev,
1101 "Installing Compass irq using %d\n",
1102 pdata->compass.irq);
1103 res = slaveirq_init(compass_adapter,
1104 &pdata->compass,
1105 "compassirq");
1106 if (res)
1107 goto out_compassirq_failed;
1108 } else {
1109 dev_warn(&this_client->adapter->dev,
1110 "WARNING: Compass irq not assigned\n");
1111 }
1112 } else {
1113 dev_warn(&this_client->adapter->dev,
1114 "%s: No Compass Present\n", MPU_NAME);
1115 }
1116
1117 if (pdata->pressure.get_slave_descr) {
1118 mldl_cfg->pressure =
1119 pdata->pressure.get_slave_descr();
1120 dev_info(&this_client->adapter->dev,
1121 "%s: +%s\n", MPU_NAME,
1122 mldl_cfg->pressure->name);
1123 pressure_adapter =
1124 i2c_get_adapter(pdata->pressure.adapt_num);
1125
1126 if (pdata->pressure.irq > 0) {
1127 dev_info(&this_client->adapter->dev,
1128 "Installing Pressure irq using %d\n",
1129 pdata->pressure.irq);
1130 res = slaveirq_init(pressure_adapter,
1131 &pdata->pressure,
1132 "pressureirq");
1133 if (res)
1134 goto out_pressureirq_failed;
1135 } else {
1136 dev_warn(&this_client->adapter->dev,
1137 "WARNING: Pressure irq not assigned\n");
1138 }
1139 } else {
1140 dev_warn(&this_client->adapter->dev,
1141 "%s: No Pressure Present\n", MPU_NAME);
1142 }
1143 }
1144
1145 mldl_cfg->addr = client->addr;
1146 res = mpu3050_open(&mpu->mldl_cfg, client->adapter,
1147 accel_adapter, compass_adapter, pressure_adapter);
1148
1149 if (res) {
1150 dev_err(&this_client->adapter->dev,
1151 "Unable to open %s %d\n", MPU_NAME, res);
1152 res = -ENODEV;
1153 goto out_whoami_failed;
1154 }
1155
1156 res = misc_register(&i2c_mpu_device);
1157 if (res < 0) {
1158 dev_err(&this_client->adapter->dev,
1159 "ERROR: misc_register returned %d\n", res);
1160 goto out_misc_register_failed;
1161 }
1162
1163 if (this_client->irq > 0) {
1164 dev_info(&this_client->adapter->dev,
1165 "Installing irq using %d\n", this_client->irq);
1166 res = mpuirq_init(this_client);
1167 if (res)
1168 goto out_mpuirq_failed;
1169 } else {
1170 dev_warn(&this_client->adapter->dev,
1171 "Missing %s IRQ\n", MPU_NAME);
1172 }
1173
1174
1175#ifdef CONFIG_HAS_EARLYSUSPEND
1176 mpu->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
1177 mpu->early_suspend.suspend = mpu3050_early_suspend;
1178 mpu->early_suspend.resume = mpu3050_early_resume;
1179 register_early_suspend(&mpu->early_suspend);
1180#endif
1181 return res;
1182
1183out_mpuirq_failed:
1184 misc_deregister(&i2c_mpu_device);
1185out_misc_register_failed:
1186 mpu3050_close(&mpu->mldl_cfg, client->adapter,
1187 accel_adapter, compass_adapter, pressure_adapter);
1188out_whoami_failed:
1189 if (pdata &&
1190 pdata->pressure.get_slave_descr &&
1191 pdata->pressure.irq)
1192 slaveirq_exit(&pdata->pressure);
1193out_pressureirq_failed:
1194 if (pdata &&
1195 pdata->compass.get_slave_descr &&
1196 pdata->compass.irq)
1197 slaveirq_exit(&pdata->compass);
1198out_compassirq_failed:
1199 if (pdata &&
1200 pdata->accel.get_slave_descr &&
1201 pdata->accel.irq)
1202 slaveirq_exit(&pdata->accel);
1203out_accelirq_failed:
1204 kfree(mpu);
1205out_alloc_data_failed:
1206out_check_functionality_failed:
1207 dev_err(&this_client->adapter->dev, "%s failed %d\n", __func__,
1208 res);
1209 return res;
1210
1211}
1212
1213static int mpu3050_remove(struct i2c_client *client)
1214{
1215 struct mpu_private_data *mpu = i2c_get_clientdata(client);
1216 struct i2c_adapter *accel_adapter;
1217 struct i2c_adapter *compass_adapter;
1218 struct i2c_adapter *pressure_adapter;
1219 struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
1220 struct mpu3050_platform_data *pdata = mldl_cfg->pdata;
1221
1222 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
1223 compass_adapter =
1224 i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
1225 pressure_adapter =
1226 i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
1227
1228 dev_dbg(&client->adapter->dev, "%s\n", __func__);
1229
1230#ifdef CONFIG_HAS_EARLYSUSPEND
1231 unregister_early_suspend(&mpu->early_suspend);
1232#endif
1233 mpu3050_close(mldl_cfg, client->adapter,
1234 accel_adapter, compass_adapter, pressure_adapter);
1235
1236 if (client->irq)
1237 mpuirq_exit();
1238
1239 if (pdata &&
1240 pdata->pressure.get_slave_descr &&
1241 pdata->pressure.irq)
1242 slaveirq_exit(&pdata->pressure);
1243
1244 if (pdata &&
1245 pdata->compass.get_slave_descr &&
1246 pdata->compass.irq)
1247 slaveirq_exit(&pdata->compass);
1248
1249 if (pdata &&
1250 pdata->accel.get_slave_descr &&
1251 pdata->accel.irq)
1252 slaveirq_exit(&pdata->accel);
1253
1254 misc_deregister(&i2c_mpu_device);
1255 kfree(mpu);
1256
1257 return 0;
1258}
1259
1260static const struct i2c_device_id mpu3050_id[] = {
1261 {MPU_NAME, 0},
1262 {}
1263};
1264
1265MODULE_DEVICE_TABLE(i2c, mpu3050_id);
1266
1267static struct i2c_driver mpu3050_driver = {
1268 .class = I2C_CLASS_HWMON,
1269 .probe = mpu3050_probe,
1270 .remove = mpu3050_remove,
1271 .id_table = mpu3050_id,
1272 .driver = {
1273 .owner = THIS_MODULE,
1274 .name = MPU_NAME,
1275 },
1276#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
1277 .address_data = &addr_data,
1278#else
1279 .address_list = normal_i2c,
1280#endif
1281
1282 .shutdown = mpu_shutdown, /* optional */
1283 .suspend = mpu_suspend, /* optional */
1284 .resume = mpu_resume, /* optional */
1285
1286};
1287
1288static int __init mpu_init(void)
1289{
1290 int res = i2c_add_driver(&mpu3050_driver);
1291 pr_debug("%s\n", __func__);
1292 if (res)
1293 pr_err("%s failed\n",
1294 __func__);
1295 return res;
1296}
1297
1298static void __exit mpu_exit(void)
1299{
1300 pr_debug("%s\n", __func__);
1301 i2c_del_driver(&mpu3050_driver);
1302}
1303
1304module_init(mpu_init);
1305module_exit(mpu_exit);
1306
1307MODULE_AUTHOR("Invensense Corporation");
1308MODULE_DESCRIPTION("User space character device interface for MPU3050");
1309MODULE_LICENSE("GPL");
1310MODULE_ALIAS(MPU_NAME);
diff --git a/drivers/misc/mpu3050/mpu-i2c.c b/drivers/misc/mpu3050/mpu-i2c.c
new file mode 100644
index 00000000000..b1298d313ab
--- /dev/null
+++ b/drivers/misc/mpu3050/mpu-i2c.c
@@ -0,0 +1,196 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20/**
21 * @defgroup
22 * @brief
23 *
24 * @{
25 * @file mpu-i2c.c
26 * @brief
27 *
28 */
29
30#include <linux/i2c.h>
31#include "mpu.h"
32
33int sensor_i2c_write(struct i2c_adapter *i2c_adap,
34 unsigned char address,
35 unsigned int len, unsigned char const *data)
36{
37 struct i2c_msg msgs[1];
38 int res;
39
40 if (NULL == data || NULL == i2c_adap)
41 return -EINVAL;
42
43 msgs[0].addr = address;
44 msgs[0].flags = 0; /* write */
45 msgs[0].buf = (unsigned char *) data;
46 msgs[0].len = len;
47
48 res = i2c_transfer(i2c_adap, msgs, 1);
49 if (res < 1)
50 return res;
51 else
52 return 0;
53}
54
55int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
56 unsigned char address,
57 unsigned char reg, unsigned char value)
58{
59 unsigned char data[2];
60
61 data[0] = reg;
62 data[1] = value;
63 return sensor_i2c_write(i2c_adap, address, 2, data);
64}
65
66int sensor_i2c_read(struct i2c_adapter *i2c_adap,
67 unsigned char address,
68 unsigned char reg,
69 unsigned int len, unsigned char *data)
70{
71 struct i2c_msg msgs[2];
72 int res;
73
74 if (NULL == data || NULL == i2c_adap)
75 return -EINVAL;
76
77 msgs[0].addr = address;
78 msgs[0].flags = 0; /* write */
79 msgs[0].buf = &reg;
80 msgs[0].len = 1;
81
82 msgs[1].addr = address;
83 msgs[1].flags = I2C_M_RD;
84 msgs[1].buf = data;
85 msgs[1].len = len;
86
87 res = i2c_transfer(i2c_adap, msgs, 2);
88 if (res < 2)
89 return res;
90 else
91 return 0;
92}
93
94int mpu_memory_read(struct i2c_adapter *i2c_adap,
95 unsigned char mpu_addr,
96 unsigned short mem_addr,
97 unsigned int len, unsigned char *data)
98{
99 unsigned char bank[2];
100 unsigned char addr[2];
101 unsigned char buf;
102
103 struct i2c_msg msgs[4];
104 int ret;
105
106 if (NULL == data || NULL == i2c_adap)
107 return -EINVAL;
108
109 bank[0] = MPUREG_BANK_SEL;
110 bank[1] = mem_addr >> 8;
111
112 addr[0] = MPUREG_MEM_START_ADDR;
113 addr[1] = mem_addr & 0xFF;
114
115 buf = MPUREG_MEM_R_W;
116
117 /* Write Message */
118 msgs[0].addr = mpu_addr;
119 msgs[0].flags = 0;
120 msgs[0].buf = bank;
121 msgs[0].len = sizeof(bank);
122
123 msgs[1].addr = mpu_addr;
124 msgs[1].flags = 0;
125 msgs[1].buf = addr;
126 msgs[1].len = sizeof(addr);
127
128 msgs[2].addr = mpu_addr;
129 msgs[2].flags = 0;
130 msgs[2].buf = &buf;
131 msgs[2].len = 1;
132
133 msgs[3].addr = mpu_addr;
134 msgs[3].flags = I2C_M_RD;
135 msgs[3].buf = data;
136 msgs[3].len = len;
137
138 ret = i2c_transfer(i2c_adap, msgs, 4);
139 if (ret != 4)
140 return ret;
141 else
142 return 0;
143}
144
145int mpu_memory_write(struct i2c_adapter *i2c_adap,
146 unsigned char mpu_addr,
147 unsigned short mem_addr,
148 unsigned int len, unsigned char const *data)
149{
150 unsigned char bank[2];
151 unsigned char addr[2];
152 unsigned char buf[513];
153
154 struct i2c_msg msgs[3];
155 int ret;
156
157 if (NULL == data || NULL == i2c_adap)
158 return -EINVAL;
159 if (len >= (sizeof(buf) - 1))
160 return -ENOMEM;
161
162 bank[0] = MPUREG_BANK_SEL;
163 bank[1] = mem_addr >> 8;
164
165 addr[0] = MPUREG_MEM_START_ADDR;
166 addr[1] = mem_addr & 0xFF;
167
168 buf[0] = MPUREG_MEM_R_W;
169 memcpy(buf + 1, data, len);
170
171 /* Write Message */
172 msgs[0].addr = mpu_addr;
173 msgs[0].flags = 0;
174 msgs[0].buf = bank;
175 msgs[0].len = sizeof(bank);
176
177 msgs[1].addr = mpu_addr;
178 msgs[1].flags = 0;
179 msgs[1].buf = addr;
180 msgs[1].len = sizeof(addr);
181
182 msgs[2].addr = mpu_addr;
183 msgs[2].flags = 0;
184 msgs[2].buf = (unsigned char *) buf;
185 msgs[2].len = len + 1;
186
187 ret = i2c_transfer(i2c_adap, msgs, 3);
188 if (ret != 3)
189 return ret;
190 else
191 return 0;
192}
193
194/**
195 * @}
196 */
diff --git a/drivers/misc/mpu3050/mpu-i2c.h b/drivers/misc/mpu3050/mpu-i2c.h
new file mode 100644
index 00000000000..0bbc8c64594
--- /dev/null
+++ b/drivers/misc/mpu3050/mpu-i2c.h
@@ -0,0 +1,58 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19/**
20 * @defgroup
21 * @brief
22 *
23 * @{
24 * @file mpu-i2c.c
25 * @brief
26 *
27 *
28 */
29
30#ifndef __MPU_I2C_H__
31#define __MPU_I2C_H__
32
33#include <linux/i2c.h>
34
35int sensor_i2c_write(struct i2c_adapter *i2c_adap,
36 unsigned char address,
37 unsigned int len, unsigned char const *data);
38
39int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
40 unsigned char address,
41 unsigned char reg, unsigned char value);
42
43int sensor_i2c_read(struct i2c_adapter *i2c_adap,
44 unsigned char address,
45 unsigned char reg,
46 unsigned int len, unsigned char *data);
47
48int mpu_memory_read(struct i2c_adapter *i2c_adap,
49 unsigned char mpu_addr,
50 unsigned short mem_addr,
51 unsigned int len, unsigned char *data);
52
53int mpu_memory_write(struct i2c_adapter *i2c_adap,
54 unsigned char mpu_addr,
55 unsigned short mem_addr,
56 unsigned int len, unsigned char const *data);
57
58#endif /* __MPU_I2C_H__ */
diff --git a/drivers/misc/mpu3050/mpuirq.c b/drivers/misc/mpu3050/mpuirq.c
new file mode 100644
index 00000000000..ce1ad409cbf
--- /dev/null
+++ b/drivers/misc/mpu3050/mpuirq.c
@@ -0,0 +1,319 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/stat.h>
25#include <linux/irq.h>
26#include <linux/signal.h>
27#include <linux/miscdevice.h>
28#include <linux/i2c.h>
29#include <linux/i2c-dev.h>
30#include <linux/workqueue.h>
31#include <linux/poll.h>
32
33#include <linux/errno.h>
34#include <linux/fs.h>
35#include <linux/mm.h>
36#include <linux/sched.h>
37#include <linux/wait.h>
38#include <linux/uaccess.h>
39#include <linux/io.h>
40
41#include "mpu.h"
42#include "mpuirq.h"
43#include "mldl_cfg.h"
44#include "mpu-i2c.h"
45
46#define MPUIRQ_NAME "mpuirq"
47
48/* function which gets accel data and sends it to MPU */
49
50DECLARE_WAIT_QUEUE_HEAD(mpuirq_wait);
51
52struct mpuirq_dev_data {
53 struct work_struct work;
54 struct i2c_client *mpu_client;
55 struct miscdevice *dev;
56 int irq;
57 int pid;
58 int accel_divider;
59 int data_ready;
60 int timeout;
61};
62
63static struct mpuirq_dev_data mpuirq_dev_data;
64static struct mpuirq_data mpuirq_data;
65static char *interface = MPUIRQ_NAME;
66
67static void mpu_accel_data_work_fcn(struct work_struct *work);
68
69static int mpuirq_open(struct inode *inode, struct file *file)
70{
71 dev_dbg(mpuirq_dev_data.dev->this_device,
72 "%s current->pid %d\n", __func__, current->pid);
73 mpuirq_dev_data.pid = current->pid;
74 file->private_data = &mpuirq_dev_data;
75 return 0;
76}
77
78/* close function - called when the "file" /dev/mpuirq is closed in userspace */
79static int mpuirq_release(struct inode *inode, struct file *file)
80{
81 dev_dbg(mpuirq_dev_data.dev->this_device, "mpuirq_release\n");
82 return 0;
83}
84
85/* read function called when from /dev/mpuirq is read */
86static ssize_t mpuirq_read(struct file *file,
87 char *buf, size_t count, loff_t *ppos)
88{
89 int len, err;
90 struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data;
91
92 if (!mpuirq_dev_data.data_ready &&
93 mpuirq_dev_data.timeout &&
94 (!(file->f_flags & O_NONBLOCK))) {
95 wait_event_interruptible_timeout(mpuirq_wait,
96 mpuirq_dev_data.
97 data_ready,
98 mpuirq_dev_data.timeout);
99 }
100
101 if (mpuirq_dev_data.data_ready && NULL != buf
102 && count >= sizeof(mpuirq_data)) {
103 err = copy_to_user(buf, &mpuirq_data, sizeof(mpuirq_data));
104 mpuirq_data.data_type = 0;
105 } else {
106 return 0;
107 }
108 if (err != 0) {
109 dev_err(p_mpuirq_dev_data->dev->this_device,
110 "Copy to user returned %d\n", err);
111 return -EFAULT;
112 }
113 mpuirq_dev_data.data_ready = 0;
114 len = sizeof(mpuirq_data);
115 return len;
116}
117
118unsigned int mpuirq_poll(struct file *file, struct poll_table_struct *poll)
119{
120 int mask = 0;
121
122 poll_wait(file, &mpuirq_wait, poll);
123 if (mpuirq_dev_data.data_ready)
124 mask |= POLLIN | POLLRDNORM;
125 return mask;
126}
127
128/* ioctl - I/O control */
129static long mpuirq_ioctl(struct file *file,
130 unsigned int cmd, unsigned long arg)
131{
132 int retval = 0;
133 int data;
134
135 switch (cmd) {
136 case MPUIRQ_SET_TIMEOUT:
137 mpuirq_dev_data.timeout = arg;
138 break;
139
140 case MPUIRQ_GET_INTERRUPT_CNT:
141 data = mpuirq_data.interruptcount - 1;
142 if (mpuirq_data.interruptcount > 1)
143 mpuirq_data.interruptcount = 1;
144
145 if (copy_to_user((int *) arg, &data, sizeof(int)))
146 return -EFAULT;
147 break;
148 case MPUIRQ_GET_IRQ_TIME:
149 if (copy_to_user((int *) arg, &mpuirq_data.irqtime,
150 sizeof(mpuirq_data.irqtime)))
151 return -EFAULT;
152 mpuirq_data.irqtime = 0;
153 break;
154 case MPUIRQ_SET_FREQUENCY_DIVIDER:
155 mpuirq_dev_data.accel_divider = arg;
156 break;
157 default:
158 retval = -EINVAL;
159 }
160 return retval;
161}
162
163static void mpu_accel_data_work_fcn(struct work_struct *work)
164{
165 struct mpuirq_dev_data *mpuirq_dev_data =
166 (struct mpuirq_dev_data *) work;
167 struct mldl_cfg *mldl_cfg =
168 (struct mldl_cfg *)
169 i2c_get_clientdata(mpuirq_dev_data->mpu_client);
170 struct i2c_adapter *accel_adapter;
171 unsigned char wbuff[16];
172 unsigned char rbuff[16];
173 int ii;
174
175 accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
176 mldl_cfg->accel->read(accel_adapter,
177 mldl_cfg->accel,
178 &mldl_cfg->pdata->accel, rbuff);
179
180
181 /* @todo add other data formats here as well */
182 if (EXT_SLAVE_BIG_ENDIAN == mldl_cfg->accel->endian) {
183 for (ii = 0; ii < 3; ii++) {
184 wbuff[2 * ii + 1] = rbuff[2 * ii + 1];
185 wbuff[2 * ii + 2] = rbuff[2 * ii + 0];
186 }
187 } else {
188 memcpy(wbuff + 1, rbuff, mldl_cfg->accel->len);
189 }
190
191 wbuff[7] = 0;
192 wbuff[8] = 1; /*set semaphore */
193
194 mpu_memory_write(mpuirq_dev_data->mpu_client->adapter,
195 mldl_cfg->addr, 0x0108, 8, wbuff);
196}
197
198static irqreturn_t mpuirq_handler(int irq, void *dev_id)
199{
200 static int mycount;
201 struct timeval irqtime;
202 mycount++;
203
204 mpuirq_data.interruptcount++;
205
206 /* wake up (unblock) for reading data from userspace */
207 /* and ignore first interrupt generated in module init */
208 mpuirq_dev_data.data_ready = 1;
209
210 do_gettimeofday(&irqtime);
211 mpuirq_data.irqtime = (((long long) irqtime.tv_sec) << 32);
212 mpuirq_data.irqtime += irqtime.tv_usec;
213
214 if ((mpuirq_dev_data.accel_divider >= 0) &&
215 (0 == (mycount % (mpuirq_dev_data.accel_divider + 1)))) {
216 schedule_work((struct work_struct
217 *) (&mpuirq_dev_data));
218 }
219
220 wake_up_interruptible(&mpuirq_wait);
221
222 return IRQ_HANDLED;
223
224}
225
226/* define which file operations are supported */
227const struct file_operations mpuirq_fops = {
228 .owner = THIS_MODULE,
229 .read = mpuirq_read,
230 .poll = mpuirq_poll,
231
232#if HAVE_COMPAT_IOCTL
233 .compat_ioctl = mpuirq_ioctl,
234#endif
235#if HAVE_UNLOCKED_IOCTL
236 .unlocked_ioctl = mpuirq_ioctl,
237#endif
238 .open = mpuirq_open,
239 .release = mpuirq_release,
240};
241
242static struct miscdevice mpuirq_device = {
243 .minor = MISC_DYNAMIC_MINOR,
244 .name = MPUIRQ_NAME,
245 .fops = &mpuirq_fops,
246};
247
248int mpuirq_init(struct i2c_client *mpu_client)
249{
250
251 int res;
252 struct mldl_cfg *mldl_cfg =
253 (struct mldl_cfg *) i2c_get_clientdata(mpu_client);
254
255 /* work_struct initialization */
256 INIT_WORK((struct work_struct *) &mpuirq_dev_data,
257 mpu_accel_data_work_fcn);
258 mpuirq_dev_data.mpu_client = mpu_client;
259
260 dev_info(&mpu_client->adapter->dev,
261 "Module Param interface = %s\n", interface);
262
263 mpuirq_dev_data.irq = mpu_client->irq;
264 mpuirq_dev_data.pid = 0;
265 mpuirq_dev_data.accel_divider = -1;
266 mpuirq_dev_data.data_ready = 0;
267 mpuirq_dev_data.timeout = 0;
268 mpuirq_dev_data.dev = &mpuirq_device;
269
270 if (mpuirq_dev_data.irq) {
271 unsigned long flags;
272 if (BIT_ACTL_LOW ==
273 ((mldl_cfg->pdata->int_config) & BIT_ACTL))
274 flags = IRQF_TRIGGER_FALLING;
275 else
276 flags = IRQF_TRIGGER_RISING;
277
278 res =
279 request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags,
280 interface, &mpuirq_dev_data.irq);
281 if (res) {
282 dev_err(&mpu_client->adapter->dev,
283 "myirqtest: cannot register IRQ %d\n",
284 mpuirq_dev_data.irq);
285 } else {
286 res = misc_register(&mpuirq_device);
287 if (res < 0) {
288 dev_err(&mpu_client->adapter->dev,
289 "misc_register returned %d\n",
290 res);
291 free_irq(mpuirq_dev_data.irq,
292 &mpuirq_dev_data.irq);
293 }
294 }
295
296 } else {
297 res = 0;
298 }
299
300 return res;
301}
302
303void mpuirq_exit(void)
304{
305 /* Free the IRQ first before flushing the work */
306 if (mpuirq_dev_data.irq > 0)
307 free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq);
308
309 flush_scheduled_work();
310
311 dev_info(mpuirq_device.this_device, "Unregistering %s\n",
312 MPUIRQ_NAME);
313 misc_deregister(&mpuirq_device);
314
315 return;
316}
317
318module_param(interface, charp, S_IRUGO | S_IWUSR);
319MODULE_PARM_DESC(interface, "The Interface name");
diff --git a/drivers/misc/mpu3050/mpuirq.h b/drivers/misc/mpu3050/mpuirq.h
new file mode 100644
index 00000000000..a71c79c75e8
--- /dev/null
+++ b/drivers/misc/mpu3050/mpuirq.h
@@ -0,0 +1,42 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20#ifndef __MPUIRQ__
21#define __MPUIRQ__
22
23#ifdef __KERNEL__
24#include <linux/i2c-dev.h>
25#include <linux/time.h>
26#else
27#include <sys/time.h>
28#endif
29
30#define MPUIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x40, unsigned long)
31#define MPUIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x41, unsigned long)
32#define MPUIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x42, struct timeval)
33#define MPUIRQ_SET_FREQUENCY_DIVIDER _IOW(MPU_IOCTL, 0x43, unsigned long)
34
35#ifdef __KERNEL__
36
37void mpuirq_exit(void);
38int mpuirq_init(struct i2c_client *mpu_client);
39
40#endif
41
42#endif
diff --git a/drivers/misc/mpu3050/slaveirq.c b/drivers/misc/mpu3050/slaveirq.c
new file mode 100644
index 00000000000..a3c7bfec4b4
--- /dev/null
+++ b/drivers/misc/mpu3050/slaveirq.c
@@ -0,0 +1,273 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/stat.h>
25#include <linux/irq.h>
26#include <linux/signal.h>
27#include <linux/miscdevice.h>
28#include <linux/i2c.h>
29#include <linux/i2c-dev.h>
30#include <linux/poll.h>
31
32#include <linux/errno.h>
33#include <linux/fs.h>
34#include <linux/mm.h>
35#include <linux/sched.h>
36#include <linux/wait.h>
37#include <linux/uaccess.h>
38#include <linux/io.h>
39#include <linux/wait.h>
40#include <linux/slab.h>
41
42#include "mpu.h"
43#include "slaveirq.h"
44#include "mldl_cfg.h"
45#include "mpu-i2c.h"
46
47/* function which gets slave data and sends it to SLAVE */
48
49struct slaveirq_dev_data {
50 struct miscdevice dev;
51 struct i2c_client *slave_client;
52 struct mpuirq_data data;
53 wait_queue_head_t slaveirq_wait;
54 int irq;
55 int pid;
56 int data_ready;
57 int timeout;
58};
59
60/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28
61 * drivers: misc: pass miscdevice pointer via file private data
62 */
63static int slaveirq_open(struct inode *inode, struct file *file)
64{
65 /* Device node is availabe in the file->private_data, this is
66 * exactly what we want so we leave it there */
67 struct slaveirq_dev_data *data =
68 container_of(file->private_data, struct slaveirq_dev_data, dev);
69
70 dev_dbg(data->dev.this_device,
71 "%s current->pid %d\n", __func__, current->pid);
72 data->pid = current->pid;
73 return 0;
74}
75
76static int slaveirq_release(struct inode *inode, struct file *file)
77{
78 struct slaveirq_dev_data *data =
79 container_of(file->private_data, struct slaveirq_dev_data, dev);
80 dev_dbg(data->dev.this_device, "slaveirq_release\n");
81 return 0;
82}
83
84/* read function called when from /dev/slaveirq is read */
85static ssize_t slaveirq_read(struct file *file,
86 char *buf, size_t count, loff_t *ppos)
87{
88 int len, err;
89 struct slaveirq_dev_data *data =
90 container_of(file->private_data, struct slaveirq_dev_data, dev);
91
92 if (!data->data_ready &&
93 data->timeout &&
94 !(file->f_flags & O_NONBLOCK)) {
95 wait_event_interruptible_timeout(data->slaveirq_wait,
96 data->data_ready,
97 data->timeout);
98 }
99
100 if (data->data_ready && NULL != buf
101 && count >= sizeof(data->data)) {
102 err = copy_to_user(buf, &data->data, sizeof(data->data));
103 data->data.data_type = 0;
104 } else {
105 return 0;
106 }
107 if (err != 0) {
108 dev_err(data->dev.this_device,
109 "Copy to user returned %d\n", err);
110 return -EFAULT;
111 }
112 data->data_ready = 0;
113 len = sizeof(data->data);
114 return len;
115}
116
117static unsigned int slaveirq_poll(struct file *file,
118 struct poll_table_struct *poll)
119{
120 int mask = 0;
121 struct slaveirq_dev_data *data =
122 container_of(file->private_data, struct slaveirq_dev_data, dev);
123
124 poll_wait(file, &data->slaveirq_wait, poll);
125 if (data->data_ready)
126 mask |= POLLIN | POLLRDNORM;
127 return mask;
128}
129
130/* ioctl - I/O control */
131static long slaveirq_ioctl(struct file *file,
132 unsigned int cmd, unsigned long arg)
133{
134 int retval = 0;
135 int tmp;
136 struct slaveirq_dev_data *data =
137 container_of(file->private_data, struct slaveirq_dev_data, dev);
138
139 switch (cmd) {
140 case SLAVEIRQ_SET_TIMEOUT:
141 data->timeout = arg;
142 break;
143
144 case SLAVEIRQ_GET_INTERRUPT_CNT:
145 tmp = data->data.interruptcount - 1;
146 if (data->data.interruptcount > 1)
147 data->data.interruptcount = 1;
148
149 if (copy_to_user((int *) arg, &tmp, sizeof(int)))
150 return -EFAULT;
151 break;
152 case SLAVEIRQ_GET_IRQ_TIME:
153 if (copy_to_user((int *) arg, &data->data.irqtime,
154 sizeof(data->data.irqtime)))
155 return -EFAULT;
156 data->data.irqtime = 0;
157 break;
158 default:
159 retval = -EINVAL;
160 }
161 return retval;
162}
163
164static irqreturn_t slaveirq_handler(int irq, void *dev_id)
165{
166 struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id;
167 static int mycount;
168 struct timeval irqtime;
169 mycount++;
170
171 data->data.interruptcount++;
172
173 /* wake up (unblock) for reading data from userspace */
174 data->data_ready = 1;
175
176 do_gettimeofday(&irqtime);
177 data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
178 data->data.irqtime += irqtime.tv_usec;
179 data->data.data_type |= 1;
180
181 wake_up_interruptible(&data->slaveirq_wait);
182
183 return IRQ_HANDLED;
184
185}
186
187/* define which file operations are supported */
188static const struct file_operations slaveirq_fops = {
189 .owner = THIS_MODULE,
190 .read = slaveirq_read,
191 .poll = slaveirq_poll,
192
193#if HAVE_COMPAT_IOCTL
194 .compat_ioctl = slaveirq_ioctl,
195#endif
196#if HAVE_UNLOCKED_IOCTL
197 .unlocked_ioctl = slaveirq_ioctl,
198#endif
199 .open = slaveirq_open,
200 .release = slaveirq_release,
201};
202
203int slaveirq_init(struct i2c_adapter *slave_adapter,
204 struct ext_slave_platform_data *pdata,
205 char *name)
206{
207
208 int res;
209 struct slaveirq_dev_data *data;
210
211 if (!pdata->irq)
212 return -EINVAL;
213
214 pdata->irq_data = kzalloc(sizeof(*data),
215 GFP_KERNEL);
216 data = (struct slaveirq_dev_data *) pdata->irq_data;
217 if (!data)
218 return -ENOMEM;
219
220 data->dev.minor = MISC_DYNAMIC_MINOR;
221 data->dev.name = name;
222 data->dev.fops = &slaveirq_fops;
223 data->irq = pdata->irq;
224 data->pid = 0;
225 data->data_ready = 0;
226 data->timeout = 0;
227
228 init_waitqueue_head(&data->slaveirq_wait);
229
230 res = request_irq(data->irq, slaveirq_handler, IRQF_TRIGGER_RISING,
231 data->dev.name, data);
232
233 if (res) {
234 dev_err(&slave_adapter->dev,
235 "myirqtest: cannot register IRQ %d\n",
236 data->irq);
237 goto out_request_irq;
238 }
239
240 res = misc_register(&data->dev);
241 if (res < 0) {
242 dev_err(&slave_adapter->dev,
243 "misc_register returned %d\n",
244 res);
245 goto out_misc_register;
246 }
247
248 return res;
249
250out_misc_register:
251 free_irq(data->irq, data);
252out_request_irq:
253 kfree(pdata->irq_data);
254 pdata->irq_data = NULL;
255
256 return res;
257}
258
259void slaveirq_exit(struct ext_slave_platform_data *pdata)
260{
261 struct slaveirq_dev_data *data = pdata->irq_data;
262
263 if (!pdata->irq_data || data->irq <= 0)
264 return;
265
266 dev_info(data->dev.this_device, "Unregistering %s\n",
267 data->dev.name);
268
269 free_irq(data->irq, data);
270 misc_deregister(&data->dev);
271 kfree(pdata->irq_data);
272 pdata->irq_data = NULL;
273}
diff --git a/drivers/misc/mpu3050/slaveirq.h b/drivers/misc/mpu3050/slaveirq.h
new file mode 100644
index 00000000000..b4e1115f1b0
--- /dev/null
+++ b/drivers/misc/mpu3050/slaveirq.h
@@ -0,0 +1,43 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20#ifndef __SLAVEIRQ__
21#define __SLAVEIRQ__
22
23#ifdef __KERNEL__
24#include <linux/i2c-dev.h>
25#endif
26
27#include "mpu.h"
28#include "mpuirq.h"
29
30#define SLAVEIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x50, unsigned long)
31#define SLAVEIRQ_GET_INTERRUPT_CNT _IOR(MPU_IOCTL, 0x51, unsigned long)
32#define SLAVEIRQ_GET_IRQ_TIME _IOR(MPU_IOCTL, 0x52, unsigned long)
33
34#ifdef __KERNEL__
35
36void slaveirq_exit(struct ext_slave_platform_data *pdata);
37int slaveirq_init(struct i2c_adapter *slave_adapter,
38 struct ext_slave_platform_data *pdata,
39 char *name);
40
41#endif
42
43#endif
diff --git a/drivers/misc/mpu3050/timerirq.c b/drivers/misc/mpu3050/timerirq.c
new file mode 100644
index 00000000000..41c3ac98101
--- /dev/null
+++ b/drivers/misc/mpu3050/timerirq.c
@@ -0,0 +1,299 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/kernel.h>
23#include <linux/init.h>
24#include <linux/stat.h>
25#include <linux/signal.h>
26#include <linux/miscdevice.h>
27#include <linux/i2c.h>
28#include <linux/i2c-dev.h>
29#include <linux/poll.h>
30
31#include <linux/errno.h>
32#include <linux/fs.h>
33#include <linux/mm.h>
34#include <linux/sched.h>
35#include <linux/wait.h>
36#include <linux/uaccess.h>
37#include <linux/io.h>
38#include <linux/timer.h>
39#include <linux/slab.h>
40
41#include "mpu.h"
42#include "mltypes.h"
43#include "timerirq.h"
44
45/* function which gets timer data and sends it to TIMER */
46struct timerirq_data {
47 int pid;
48 int data_ready;
49 int run;
50 int timeout;
51 unsigned long period;
52 struct mpuirq_data data;
53 struct completion timer_done;
54 wait_queue_head_t timerirq_wait;
55 struct timer_list timer;
56 struct miscdevice *dev;
57};
58
59static struct miscdevice *timerirq_dev_data;
60
61static void timerirq_handler(unsigned long arg)
62{
63 struct timerirq_data *data = (struct timerirq_data *)arg;
64 struct timeval irqtime;
65
66 data->data.interruptcount++;
67
68 data->data_ready = 1;
69
70 do_gettimeofday(&irqtime);
71 data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
72 data->data.irqtime += irqtime.tv_usec;
73 data->data.data_type |= 1;
74
75 dev_dbg(data->dev->this_device,
76 "%s, %lld, %ld\n", __func__, data->data.irqtime,
77 (unsigned long)data);
78
79 wake_up_interruptible(&data->timerirq_wait);
80
81 if (data->run)
82 mod_timer(&data->timer,
83 jiffies + msecs_to_jiffies(data->period));
84 else
85 complete(&data->timer_done);
86}
87
88static int start_timerirq(struct timerirq_data *data)
89{
90 dev_dbg(data->dev->this_device,
91 "%s current->pid %d\n", __func__, current->pid);
92
93 /* Timer already running... success */
94 if (data->run)
95 return 0;
96
97 /* Don't allow a period of 0 since this would fire constantly */
98 if (!data->period)
99 return -EINVAL;
100
101 data->run = TRUE;
102 data->data_ready = FALSE;
103
104 init_completion(&data->timer_done);
105 setup_timer(&data->timer, timerirq_handler, (unsigned long)data);
106
107 return mod_timer(&data->timer,
108 jiffies + msecs_to_jiffies(data->period));
109}
110
111static int stop_timerirq(struct timerirq_data *data)
112{
113 dev_dbg(data->dev->this_device,
114 "%s current->pid %lx\n", __func__, (unsigned long)data);
115
116 if (data->run) {
117 data->run = FALSE;
118 mod_timer(&data->timer, jiffies + 1);
119 wait_for_completion(&data->timer_done);
120 }
121 return 0;
122}
123
124/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28
125 * drivers: misc: pass miscdevice pointer via file private data
126 */
127static int timerirq_open(struct inode *inode, struct file *file)
128{
129 /* Device node is availabe in the file->private_data, this is
130 * exactly what we want so we leave it there */
131 struct miscdevice *dev_data = file->private_data;
132 struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
133 if (!data)
134 return -ENOMEM;
135
136 data->dev = dev_data;
137 file->private_data = data;
138 data->pid = current->pid;
139 init_waitqueue_head(&data->timerirq_wait);
140
141 dev_dbg(data->dev->this_device,
142 "%s current->pid %d\n", __func__, current->pid);
143 return 0;
144}
145
146static int timerirq_release(struct inode *inode, struct file *file)
147{
148 struct timerirq_data *data = file->private_data;
149 dev_dbg(data->dev->this_device, "timerirq_release\n");
150 if (data->run)
151 stop_timerirq(data);
152 kfree(data);
153 return 0;
154}
155
156/* read function called when from /dev/timerirq is read */
157static ssize_t timerirq_read(struct file *file,
158 char *buf, size_t count, loff_t *ppos)
159{
160 int len, err;
161 struct timerirq_data *data = file->private_data;
162
163 if (!data->data_ready &&
164 data->timeout &&
165 !(file->f_flags & O_NONBLOCK)) {
166 wait_event_interruptible_timeout(data->timerirq_wait,
167 data->data_ready,
168 data->timeout);
169 }
170
171 if (data->data_ready && NULL != buf
172 && count >= sizeof(data->data)) {
173 err = copy_to_user(buf, &data->data, sizeof(data->data));
174 data->data.data_type = 0;
175 } else {
176 return 0;
177 }
178 if (err != 0) {
179 dev_err(data->dev->this_device,
180 "Copy to user returned %d\n", err);
181 return -EFAULT;
182 }
183 data->data_ready = 0;
184 len = sizeof(data->data);
185 return len;
186}
187
188static unsigned int timerirq_poll(struct file *file,
189 struct poll_table_struct *poll)
190{
191 int mask = 0;
192 struct timerirq_data *data = file->private_data;
193
194 poll_wait(file, &data->timerirq_wait, poll);
195 if (data->data_ready)
196 mask |= POLLIN | POLLRDNORM;
197 return mask;
198}
199
200/* ioctl - I/O control */
201static long timerirq_ioctl(struct file *file,
202 unsigned int cmd, unsigned long arg)
203{
204 int retval = 0;
205 int tmp;
206 struct timerirq_data *data = file->private_data;
207
208 dev_dbg(data->dev->this_device,
209 "%s current->pid %d, %d, %ld\n",
210 __func__, current->pid, cmd, arg);
211
212 if (!data)
213 return -EFAULT;
214
215 switch (cmd) {
216 case TIMERIRQ_SET_TIMEOUT:
217 data->timeout = arg;
218 break;
219 case TIMERIRQ_GET_INTERRUPT_CNT:
220 tmp = data->data.interruptcount - 1;
221 if (data->data.interruptcount > 1)
222 data->data.interruptcount = 1;
223
224 if (copy_to_user((int *) arg, &tmp, sizeof(int)))
225 return -EFAULT;
226 break;
227 case TIMERIRQ_START:
228 data->period = arg;
229 retval = start_timerirq(data);
230 break;
231 case TIMERIRQ_STOP:
232 retval = stop_timerirq(data);
233 break;
234 default:
235 retval = -EINVAL;
236 }
237 return retval;
238}
239
240/* define which file operations are supported */
241static const struct file_operations timerirq_fops = {
242 .owner = THIS_MODULE,
243 .read = timerirq_read,
244 .poll = timerirq_poll,
245
246#if HAVE_COMPAT_IOCTL
247 .compat_ioctl = timerirq_ioctl,
248#endif
249#if HAVE_UNLOCKED_IOCTL
250 .unlocked_ioctl = timerirq_ioctl,
251#endif
252 .open = timerirq_open,
253 .release = timerirq_release,
254};
255
256static int __init timerirq_init(void)
257{
258
259 int res;
260 static struct miscdevice *data;
261
262 data = kzalloc(sizeof(*data), GFP_KERNEL);
263 if (!data)
264 return -ENOMEM;
265 timerirq_dev_data = data;
266 data->minor = MISC_DYNAMIC_MINOR;
267 data->name = "timerirq";
268 data->fops = &timerirq_fops;
269
270 res = misc_register(data);
271 if (res < 0) {
272 dev_err(data->this_device,
273 "misc_register returned %d\n",
274 res);
275 return res;
276 }
277
278 return res;
279}
280module_init(timerirq_init);
281
282static void __exit timerirq_exit(void)
283{
284 struct miscdevice *data = timerirq_dev_data;
285
286 dev_info(data->this_device, "Unregistering %s\n",
287 data->name);
288
289 misc_deregister(data);
290 kfree(data);
291
292 timerirq_dev_data = NULL;
293}
294module_exit(timerirq_exit);
295
296MODULE_AUTHOR("Invensense Corporation");
297MODULE_DESCRIPTION("Timer IRQ device driver.");
298MODULE_LICENSE("GPL");
299MODULE_ALIAS("timerirq");
diff --git a/drivers/misc/mpu3050/timerirq.h b/drivers/misc/mpu3050/timerirq.h
new file mode 100644
index 00000000000..ec2c1e29f08
--- /dev/null
+++ b/drivers/misc/mpu3050/timerirq.h
@@ -0,0 +1,30 @@
1/*
2 $License:
3 Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 $
18 */
19
20#ifndef __TIMERIRQ__
21#define __TIMERIRQ__
22
23#include "mpu.h"
24
25#define TIMERIRQ_SET_TIMEOUT _IOW(MPU_IOCTL, 0x60, unsigned long)
26#define TIMERIRQ_GET_INTERRUPT_CNT _IOW(MPU_IOCTL, 0x61, unsigned long)
27#define TIMERIRQ_START _IOW(MPU_IOCTL, 0x62, unsigned long)
28#define TIMERIRQ_STOP _IO(MPU_IOCTL, 0x63)
29
30#endif