[ARM/tegra] Integrate Accelerometer source code files.
Robert Collins [Tue, 23 Nov 2010 21:54:32 +0000 (13:54 -0800)]
Inegrate MPL libraries and the following sensors:
Accelerometers:
kxtf9

Compi:
ak8975

Original-Change-Id: I450b5b7ff018249a19bb23b78e722e9a355b7bd8
Reviewed-on: http://git-master/r/11803
Tested-by: Robert R Collins <rcollins@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>

Rebase-Id: R76e2da39a90190d176552fdb11aab2009964023f

21 files changed:
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/mpu3050/Kconfig [new file with mode: 0755]
drivers/misc/mpu3050/Makefile [new file with mode: 0755]
drivers/misc/mpu3050/README [new file with mode: 0755]
drivers/misc/mpu3050/accel/kxtf9.c [new file with mode: 0755]
drivers/misc/mpu3050/compass/ak8975.c [new file with mode: 0755]
drivers/misc/mpu3050/log.h [new file with mode: 0755]
drivers/misc/mpu3050/mldl_cfg.c [new file with mode: 0755]
drivers/misc/mpu3050/mldl_cfg.h [new file with mode: 0755]
drivers/misc/mpu3050/mlos-kernel.c [new file with mode: 0755]
drivers/misc/mpu3050/mlos.h [new file with mode: 0755]
drivers/misc/mpu3050/mlsl-kernel.c [new file with mode: 0755]
drivers/misc/mpu3050/mlsl.h [new file with mode: 0755]
drivers/misc/mpu3050/mltypes.h [new file with mode: 0755]
drivers/misc/mpu3050/mpu-dev.c [new file with mode: 0755]
drivers/misc/mpu3050/mpu-i2c.c [new file with mode: 0755]
drivers/misc/mpu3050/mpu-i2c.h [new file with mode: 0755]
drivers/misc/mpu3050/mpuirq.c [new file with mode: 0755]
drivers/misc/mpu3050/mpuirq.h [new file with mode: 0755]
include/linux/mpu3050.h [new file with mode: 0755]

index 540b8d7..f0459ce 100644 (file)
@@ -534,5 +534,6 @@ source "drivers/misc/iwmc3200top/Kconfig"
 source "drivers/misc/ti-st/Kconfig"
 source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
+source "drivers/misc/mpu3050/Kconfig"
 
 endif # MISC_DEVICES
index 7f8788e..7a13ef8 100644 (file)
@@ -13,8 +13,8 @@ obj-$(CONFIG_ATMEL_TCLIB)     += atmel_tclib.o
 obj-$(CONFIG_BMP085)           += bmp085.o
 obj-$(CONFIG_ICS932S401)       += ics932s401.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
-obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
-obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
+obj-$(CONFIG_TIFM_CORE)                += tifm_core.o
+obj-$(CONFIG_TIFM_7XX1)                += tifm_7xx1.o
 obj-$(CONFIG_PHANTOM)          += phantom.o
 obj-$(CONFIG_SENSORS_BH1780)   += bh1780gli.o
 obj-$(CONFIG_SENSORS_BH1770)   += bh1770glc.o
@@ -49,5 +49,6 @@ obj-y                         += carma/
 obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
 obj-$(CONFIG_SENSORS_NCT1008)  += nct1008.o
 obj-$(CONFIG_BCM4329_RFKILL)   += bcm4329_rfkill.o
+obj-$(CONFIG_SENSORS_MPU3050)  += mpu3050/
 obj-$(CONFIG_TEGRA_CRYPTO_DEV) += tegra-cryptodev.o
 obj-$(CONFIG_MAX1749_VIBRATOR) += max1749.o
diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig
new file mode 100755 (executable)
index 0000000..99ea1c6
--- /dev/null
@@ -0,0 +1,54 @@
+\r
+menu "Motion Sensors Support"\r
+\r
+config SENSORS_MPU3050\r
+    tristate "MPU3050 Gyroscope Driver"\r
+    depends on I2C\r
+    help\r
+      If you say yes here you get support for the MPU3050 Gyroscope driver\r
+      This driver can also be built as a module.  If so, the module\r
+      will be called mpu3050.\r
+\r
+config SENSORS_MPU3050_DEBUG\r
+    bool "MPU3050 debug"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      If you say yes here you get extra debug messages from the MPU3050\r
+      and other slave sensors.\r
+\r
+choice\r
+    prompt "Accelerometer Type"\r
+    depends on SENSORS_MPU3050\r
+    default SENSORS_KXTF9_MPU\r
+\r
+config SENSORS_ACCELEROMETER_NONE\r
+    bool "NONE"\r
+    help\r
+      This disables accelerometer support for the MPU3050\r
+\r
+config SENSORS_KXTF9_MPU\r
+    bool "Kionix KXTF9"\r
+    help\r
+      This enables support for the Kionix KXFT9 accelerometer\r
+\r
+endchoice\r
+\r
+choice\r
+    prompt "Compass Type"\r
+    depends on SENSORS_MPU3050\r
+    default SENSORS_AK8975_MPU\r
+\r
+config SENSORS_COMPASS_NONE\r
+    bool "NONE"\r
+    help\r
+      This disables compass support for the MPU3050\r
+\r
+config SENSORS_AK8975_MPU\r
+    bool "AKM ak8975"\r
+    help\r
+      This enables support for the AKM ak8975 compass\r
+\r
+endchoice\r
+\r
+endmenu\r
+\r
diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile
new file mode 100755 (executable)
index 0000000..99955ad
--- /dev/null
@@ -0,0 +1,37 @@
+\r
+# Kernel makefile for motions sensors\r
+#\r
+# \r
+\r
+# MPU\r
+obj-$(CONFIG_SENSORS_MPU3050)  += mpu3050.o\r
+mpu3050-objs += mpuirq.o \\r
+       mpu-dev.o \\r
+       mpu-i2c.o \\r
+       mlsl-kernel.o \\r
+       mlos-kernel.o \\r
+       $(MLLITE_DIR)mldl_cfg.o\r
+\r
+#\r
+# Accel options\r
+#\r
+ifdef CONFIG_SENSORS_KXTF9_MPU\r
+mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o\r
+endif\r
+\r
+#\r
+# Compass options\r
+#\r
+ifdef CONFIG_SENSORS_AK8975_MPU\r
+mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o\r
+endif\r
+\r
+EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \\r
+                -I$(M)/../../include \\r
+                               -Idrivers/misc/mpu3050 \\r
+                -Iinclude/linux\r
+\r
+ifdef CONFIG_SENSORS_MPU3050_DEBUG\r
+EXTRA_CFLAGS += -DDEBUG\r
+endif\r
+\r
diff --git a/drivers/misc/mpu3050/README b/drivers/misc/mpu3050/README
new file mode 100755 (executable)
index 0000000..8ff0c30
--- /dev/null
@@ -0,0 +1,138 @@
+Kernel driver mpu3050
+=====================
+
+Supported chips:
+  * Invensense IMU3050
+    Prefix: 'mpu3050'
+    Datasheet:
+        PS-MPU-3000A-00.2.4b.pdf
+
+Author: Invensense <http://invensense.com>
+
+Description
+-----------
+The mpu3050 is a motion processor that controls the mpu3050 gyroscope, a slave
+accelerometer and compass.  This document describes how to install the driver
+into a linux kernel and a small note about how to set up the file permissions
+in an android file system.
+
+Sysfs entries
+-------------
+/dev/mpu
+/dev/mpuirq
+
+General Remarks
+---------------
+
+Valid addresses for the MPU3050 is 0x68.
+Accelerometer must be on the secondary I2C bus.
+
+Programming the chip using /dev/mpu
+----------------------------------
+Programming of the MPU3050 is done by first opening the /dev/mpu file and
+then performing a series of IOCTLS on the handle returned.  The IOCTL codes can
+be found in mpu3050.h.  Typically this is done by the mllite library in user
+space.
+
+Adding to a Kernel
+==================
+
+The mpu3050 driver is designed to be inserted in the drivers/misc part of the 
+kernel.  Copy the mpu3050 directory and the mpu3050 include file to:
+
+    <kernel root dir>/drivers/misc/mpu3050
+    <kernel root dir>/include/linux/mpu3050.h
+
+respectively.
+
+After this is done the drivers/misc/Kconfig must be edited to add the line:
+
+    source "drivers/misc/mpu3050/Kconfig"
+
+Similarly drivers/misc/Makefile must be edited to add the line:
+
+    obj-y += mpu3050/
+
+Configuration can then be done as normal.
+
+Board and Platform Data
+-----------------------
+
+In order for the driver to work, board and platform data specific to the device
+needs to be added to the board file.  A mpu3050_platform_data structure must
+be created and populatd and set in the i2c_board_info_structure.  For details of
+each structure member see mpu3050.h.  All values below are modified for the ventana
+platform. You should add these lines into the
+kernel/arch/arm/mach-tegra/board-generic.c file.
+
+#include <linux/mpu3050.h>
+
+static struct mpu3050_platform_data mpu3050_data = {
+    .int_config  = 0x10,
+    .orientation = { 0, -1, 0,
+                    -1, 0, 0,
+                    0, 0, -1 },  //Orientation matrix for MPU on ventana
+    .level_shifter = 0,
+    .accel = {
+        .get_slave_descr = kxtf9_get_slave_descr,
+        .adapt_num   = 0,
+        .bus         = EXT_SLAVE_BUS_SECONDARY,
+        .address     = 0x0F,
+    .orientation = { 0, -1, 0,
+                    -1, 0, 0,
+                    0, 0, -1 },  //Orientation matrix for Kionix on ventana
+    },
+
+    .compass = {
+        .get_slave_descr = ak8975_get_slave_descr,
+        .adapt_num   = 3,            //bus number 3 on ventana
+        .bus         = EXT_SLAVE_BUS_PRIMARY,
+        .address     = 0x0C,
+       .orientation = { 1, 0, 0,
+                       0, -1, 0,  
+                       0, 0, -1 },  //Orientation matrix for AKM on ventana
+    },
+
+};
+
+static struct i2c_board_info __initdata mpu3050_i2c0_boardinfo[] = {
+    {
+        I2C_BOARD_INFO("mpu3050", 0x68),
+        /*.irq = 299,*/
+        .platform_data = &mpu3050_data,
+    },
+};
+
+Note: If you are unsure where to add this code, look for other instances of "i2c_board_info"
+and copy paste this code after one of them.
+
+After this is done, we must register the board upon initialization. This is done in the
+i2c_device_setup function in the board-generic.c file. Look for this function and add these
+lines of code:
+
+if (ARRAY_SIZE(mpu3050_i2c0_boardinfo)) 
+       i2c_register_board_info(0, mpu3050_i2c0_boardinfo, 
+               ARRAY_SIZE(mpu3050_i2c0_boardinfo));
+
+Before you can build the kernel, you will need to remove the existing NVidia AK8975 driver for the compass.
+In the board-generic.c file, rename the instance of CONFIG_SENSORS_AK8975 to NVIDIA_CONFIG_SENSORS_AK8975.
+In kernel/drivers/hwmon/Makefile, rename that instance of CONFIG_SENSORS_AK8975 to NVIDIA_CONFIG_SENSORS_AK8975 as well.
+This will prevent NVidia's driver for the compass from building.
+
+Now you can build the new kernel. First, we must configure the kernel. Take the tegra_ventana_android_defconfig
+file from this package and replace the existing one in the kernel/arch/arm/configs directory. In the root kernel
+directory, you can then run:
+
+export CCOMPILER=/<path to android environment>/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-
+make ARCH=arm CROSS_COMPILE=$CCOMPILER mrproper
+make ARCH=arm CROSS_COMPILE=$CCOMPILER tegra_ventana_android_defconfig
+make ARCH=arm CROSS_COMPILE=$CCOMPILER
+
+This should build your zImage, which you will find in kernel/arch/arm/boot/zImage. You can use the mkbootimg utility to then
+make a boot.img:
+
+ ./mkbootimg --kernel <path to android system>/kernel/arch/arm/boot/zImage --ramdisk <path to android system>/out/target/product/ventana/ramdisk.img --output boot.img
+
+You can then flash this boot.img using the nvflash utility. 
+
diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c
new file mode 100755 (executable)
index 0000000..ecf9e7d
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: kxtf9.c 3867 2010-10-09 01:06:18Z prao $
+ *
+ *******************************************************************************/
+
+/**
+ *  @defgroup   ACCELDL (Motion Library - Accelerometer Driver Layer)
+ *  @brief      Provides the interface to setup and handle an accelerometers
+ *              connected to the secondary I2C interface of the gyroscope.
+ *
+ *  @{
+ *      @file   kxtf9.c
+ *      @brief  Accelerometer setup and handling methods.
+**/
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu3050.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+static int kxtf9_suspend(mlsl_handle_t mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata)
+{
+       int result;
+       /* RAM reset */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1d, 0xcd);
+       return result;
+}
+
+/* full scale setting - register and mask */
+#define ACCEL_KIONIX_CTRL_REG      (0x1b)
+#define ACCEL_KIONIX_CTRL_MASK     (0x18)
+
+static int kxtf9_resume(mlsl_handle_t mlsl_handle,
+                       struct ext_slave_descr *slave,
+                       struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       /* RAM reset */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1d, 0xcd);
+       MLOSSleep(10);
+       /* Wake up */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0x42);
+       /* INT_CTRL_REG1: */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1e, 0x14);
+       /* WUF_THRESH: */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x5a, 0x00);
+       /* DATA_CTRL_REG */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x04);
+       /* WUF_TIMER */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x29, 0x02);
+
+       /* Full Scale */
+       reg = 0xc2;
+       reg &= ~ACCEL_KIONIX_CTRL_MASK;
+       reg |= 0x00;            /* TODO FIXME michelle */
+       if (slave->range.mantissa == 2) {
+               reg |= 0x00;
+       } else if (slave->range.mantissa == 4) {
+               reg |= 0x08;
+       } else if (slave->range.mantissa == 8) {
+               reg |= 0x10;
+       }
+       /* Normal operation */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, reg);
+       MLOSSleep(50);
+
+       return ML_SUCCESS;
+}
+
+static int kxtf9_read(mlsl_handle_t mlsl_handle,
+                     struct ext_slave_descr *slave,
+                     struct ext_slave_platform_data *pdata,
+                     unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+static struct ext_slave_descr kxtf9_descr = {
+       /*.suspend          = */ kxtf9_suspend,
+       /*.resume           = */ kxtf9_resume,
+       /*.read             = */ kxtf9_read,
+       /*.name             = */ "kxtf9",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_KXTF9,
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *kxtf9_get_slave_descr(void)
+{
+       return &kxtf9_descr;
+}
+
+#ifdef __KERNEL__
+EXPORT_SYMBOL(kxtf9_get_slave_descr);
+#endif
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c
new file mode 100755 (executable)
index 0000000..fb4c033
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: ak8975.c 3879 2010-10-12 03:12:37Z mcaramello $
+ *
+ *******************************************************************************/
+
+/**
+ *  @defgroup   COMPASSDL (Motion Library - Accelerometer Driver Layer)
+ *  @brief      Provides the interface to setup and handle an accelerometers
+ *              connected to the secondary I2C interface of the gyroscope.
+ *
+ *  @{
+ *      @file   AK8975.c
+ *      @brief  Magnetometer setup and handling methods for AKM 8975 compass.
+**/
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu3050.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+#define AK8975_REG_ST1  (0x02)
+#define AK8975_REG_HXL  (0x03)
+#define AK8975_REG_ST2  (0x09)
+
+#define AK8975_REG_CNTL (0x0A)
+
+#define AK8975_CNTL_MODE_POWER_DOWN         (0x00)
+#define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x01)
+
+int ak8975_suspend(mlsl_handle_t mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      AK8975_REG_CNTL,
+                                      AK8975_CNTL_MODE_POWER_DOWN);
+       return result;
+}
+
+int ak8975_resume(mlsl_handle_t mlsl_handle,
+                 struct ext_slave_descr *slave,
+                 struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      AK8975_REG_CNTL,
+                                      AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
+       return result;
+}
+
+int ak8975_read(mlsl_handle_t mlsl_handle,
+               struct ext_slave_descr *slave,
+               struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+       unsigned char stat;
+       unsigned char stat2;
+       int result = ML_SUCCESS;
+
+       result = MLSLSerialRead(mlsl_handle, pdata->address,
+                               AK8975_REG_ST1, 1, &stat);
+       ERROR_CHECK(result);
+       if (stat & 0x01) {
+               result = MLSLSerialRead(mlsl_handle, pdata->address,
+                                       AK8975_REG_HXL, 6,
+                                       (unsigned char *)data);
+               ERROR_CHECK(result);
+               result = MLSLSerialRead(mlsl_handle, pdata->address,
+                                       AK8975_REG_ST2, 1, &stat2);
+               ERROR_CHECK(result);
+               if (stat2 & 0x04) {     /*data error */
+                       return ML_ERROR_COMPASS_DATA_NOT_READY;
+               }
+               if (stat2 & 0x08) {
+                       return ML_ERROR_COMPASS_DATA_OVERFLOW;
+               }
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                              AK8975_REG_CNTL,
+                                              AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
+               return ML_SUCCESS;
+       } else if (stat & 0x02) {
+               result = MLSLSerialRead(mlsl_handle, pdata->address,
+                                       AK8975_REG_ST2, 1, &stat2);
+               ERROR_CHECK(result);
+               return ML_ERROR_COMPASS_DATA_OVERFLOW;
+       } else {
+               return ML_ERROR_COMPASS_DATA_NOT_READY;
+       }
+
+}
+
+struct ext_slave_descr ak8975_descr = {
+       /*.suspend          = */ ak8975_suspend,
+       /*.resume           = */ ak8975_resume,
+       /*.read             = */ ak8975_read,
+       /*.name             = */ "ak8975",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_AKM,
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {9830, 4000}
+};
+
+struct ext_slave_descr *ak8975_get_slave_descr(void)
+{
+       return &ak8975_descr;
+}
+
+#ifdef __KERNEL__
+EXPORT_SYMBOL(ak8975_get_slave_descr);
+#endif
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/log.h b/drivers/misc/mpu3050/log.h
new file mode 100755 (executable)
index 0000000..6cb7eae
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2010 InvenSense Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+// C/C++ logging functions.  See the logging documentation for API details.
+//
+// We'd like these to be available from C code (in case we import some from
+// somewhere), so this has a C interface.
+//
+// The output will be correct when the log file is shared between multiple
+// threads and/or multiple processes so long as the operating system
+// supports O_APPEND.  These calls have mutex-protected data structures
+// and so are NOT reentrant.  Do not use MPL_LOG in a signal handler.
+*/
+#ifndef _LIBS_CUTILS_MPL_LOG_H
+#define _LIBS_CUTILS_MPL_LOG_H
+
+#include <stdarg.h>
+
+#ifdef ANDROID
+#include <utils/Log.h>         /* For the LOG macro */
+#endif
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Normally we strip MPL_LOGV (VERBOSE messages) from release builds.
+ * You can modify this (for example with "#define MPL_LOG_NDEBUG 0"
+ * at the top of your source file) to change that behavior.
+ */
+#define MPL_LOGV               /* comment this out to enable VERBOSE level logging */
+#ifndef MPL_LOG_NDEBUG
+#ifdef NDEBUG
+#define MPL_LOG_NDEBUG 1
+#else
+#define MPL_LOG_NDEBUG 0
+#endif
+#endif
+
+#ifdef __KERNEL__
+#define MPL_LOG_UNKNOWN MPL_LOG_VERBOSE
+#define MPL_LOG_DEFAULT KERN_DEFAULT
+#define MPL_LOG_VERBOSE KERN_CONT
+#define MPL_LOG_DEBUG   KERN_NOTICE
+#define MPL_LOG_INFO    KERN_INFO
+#define MPL_LOG_WARN    KERN_WARNING
+#define MPL_LOG_ERROR   KERN_ERR
+#define MPL_LOG_SILENT  MPL_LOG_VERBOSE
+
+#else
+       /* Based off the log priorities in android
+          /system/core/include/android/log.h */
+#define MPL_LOG_UNKNOWN (0)
+#define MPL_LOG_DEFAULT (1)
+#define MPL_LOG_VERBOSE (2)
+#define MPL_LOG_DEBUG (3)
+#define MPL_LOG_INFO (4)
+#define MPL_LOG_WARN (5)
+#define MPL_LOG_ERROR (6)
+#define MPL_LOG_SILENT (8)
+#endif
+
+/*
+ * This is the local tag used for the following simplified
+ * logging macros.  You can change this preprocessor definition
+ * before using the other macros to change the tag.
+ */
+#ifndef MPL_LOG_TAG
+#ifdef __KERNEL__
+#define MPL_LOG_TAG
+#else
+#define MPL_LOG_TAG NULL
+#endif
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Simplified macro to send a verbose log message using the current MPL_LOG_TAG.
+ */
+#define MPL_LOGV
+#ifndef MPL_LOGV
+#if MPL_LOG_NDEBUG
+#define MPL_LOGV(...) ((void)0)
+#else
+#define MPL_LOGV(...) ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#ifndef CONDITION
+#define CONDITION(cond)     ((cond) != 0)
+#endif
+
+#ifndef MPL_LOGV_IF
+#if MPL_LOG_NDEBUG
+#define MPL_LOGV_IF(cond, ...)   ((void)0)
+#else
+#define MPL_LOGV_IF(cond, ...) \
+    ((CONDITION(cond)) \
+    ? ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__)) \
+    : (void)0)
+#endif
+#endif
+
+/*
+ * Simplified macro to send a debug log message using the current MPL_LOG_TAG.
+ */
+#ifndef MPL_LOGD
+#define MPL_LOGD(...) ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGD_IF
+#define MPL_LOGD_IF(cond, ...) \
+    ((CONDITION(cond)) \
+    ? ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__)) \
+    : (void)0)
+#endif
+
+/*
+ * Simplified macro to send an info log message using the current MPL_LOG_TAG.
+ */
+#ifndef MPL_LOGI
+#define MPL_LOGI(...) ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGI_IF
+#define MPL_LOGI_IF(cond, ...) \
+    ((CONDITION(cond)) \
+    ? ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__)) \
+    : (void)0)
+#endif
+
+/*
+ * Simplified macro to send a warning log message using the current MPL_LOG_TAG.
+ */
+#ifndef MPL_LOGW
+#define MPL_LOGW(...) ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGW_IF
+#define MPL_LOGW_IF(cond, ...) \
+    ((CONDITION(cond)) \
+    ? ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__)) \
+    : (void)0)
+#endif
+
+/*
+ * Simplified macro to send an error log message using the current MPL_LOG_TAG.
+ */
+#ifndef MPL_LOGE
+#define MPL_LOGE(...) ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGE_IF
+#define MPL_LOGE_IF(cond, ...) \
+    ((CONDITION(cond)) \
+    ? ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__)) \
+    : (void)0)
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Log a fatal error.  If the given condition fails, this stops program
+ * execution like a normal assertion, but also generating the given message.
+ * It is NOT stripped from release builds.  Note that the condition test
+ * is -inverted- from the normal assert() semantics.
+ */
+#define MPL_LOG_ALWAYS_FATAL_IF(cond, ...) \
+    ((CONDITION(cond)) \
+    ? ((void)android_printAssert(#cond, MPL_LOG_TAG, __VA_ARGS__)) \
+    : (void)0)
+
+#define MPL_LOG_ALWAYS_FATAL(...) \
+    (((void)android_printAssert(NULL, MPL_LOG_TAG, __VA_ARGS__)))
+
+/*
+ * Versions of MPL_LOG_ALWAYS_FATAL_IF and MPL_LOG_ALWAYS_FATAL that
+ * are stripped out of release builds.
+ */
+#if MPL_LOG_NDEBUG
+
+#define MPL_LOG_FATAL_IF(cond, ...) ((void)0)
+#define MPL_LOG_FATAL(...)          ((void)0)
+
+#else
+
+#define MPL_LOG_FATAL_IF(cond, ...) MPL_LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__)
+#define MPL_LOG_FATAL(...)          MPL_LOG_ALWAYS_FATAL(__VA_ARGS__)
+
+#endif
+
+/*
+ * Assertion that generates a log message when the assertion fails.
+ * Stripped out of release builds.  Uses the current MPL_LOG_TAG.
+ */
+#define MPL_LOG_ASSERT(cond, ...) MPL_LOG_FATAL_IF(!(cond), __VA_ARGS__)
+/*#define MPL_LOG_ASSERT(cond) MPL_LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) */
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Basic log message macro.
+ *
+ * Example:
+ *  MPL_LOG(MPL_LOG_WARN, NULL, "Failed with error %d", errno);
+ *
+ * The second argument may be NULL or "" to indicate the "global" tag.
+ */
+#ifndef MPL_LOG
+#define MPL_LOG(priority, tag, ...) \
+    MPL_LOG_PRI(priority, tag, __VA_ARGS__)
+#endif
+
+/*
+ * Log macro that allows you to specify a number for the priority.
+ */
+#ifndef MPL_LOG_PRI
+#ifdef ANDROID
+#define MPL_LOG_PRI(priority, tag, ...) \
+    LOG(priority, tag, __VA_ARGS__)
+#elif defined __KERNEL__
+#define MPL_LOG_PRI(priority, tag, ...) \
+    printk(MPL_##priority tag __VA_ARGS__)
+#else
+#define MPL_LOG_PRI(priority, tag, ...) \
+    _MLPrintLog(MPL_##priority, tag, __VA_ARGS__)
+#endif
+#endif
+
+/*
+ * Log macro that allows you to pass in a varargs ("args" is a va_list).
+ */
+#ifndef MPL_LOG_PRI_VA
+#ifdef ANDROID
+#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
+    android_vprintLog(priority, NULL, tag, fmt, args)
+#elif defined __KERNEL__
+#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
+    vprintk(MPL_##priority tag fmt, args)
+#else
+#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
+    _MLPrintVaLog(priority, NULL, tag, fmt, args)
+#endif
+#endif
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * ===========================================================================
+ *
+ * The stuff in the rest of this file should not be used directly.
+ */
+
+#ifndef ANDROID
+       int _MLPrintLog(int priority, const char *tag, const char *fmt, ...);
+       int _MLPrintVaLog(int priority, const char *tag, const char *fmt,
+                         va_list args);
+/* Final implementation of actual writing to a character device */
+       int _MLWriteLog(const char *buf, int buflen);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#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 100755 (executable)
index 0000000..d96b0a7
--- /dev/null
@@ -0,0 +1,872 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: mldl_cfg.c 3881 2010-10-12 18:58:45Z prao $
+ *
+ ******************************************************************************/
+
+/**
+ *  @addtogroup MLDL
+ *
+ *  @{
+ *      @file   mldl_cfg.c
+ *      @brief  The Motion Library Driver Layer.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#include <stddef.h>
+
+#include "mldl_cfg.h"
+#include "mpu3050.h"
+
+#include "mlsl.h"
+#include "mlos.h"
+
+#include "log.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "mldl_cfg:"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/* ---------------------- */
+/* -  Static Functions. - */
+/* ---------------------- */
+
+/**
+ *  @internal
+ * @brief   MLDLCfgDMP configures the Digital Motion Processor internal to
+ *          the MPU. The DMP can be enabled or disabled and the start address
+ *          can be set.
+ *
+ * @param   enableRun   Enables the DMP processing if set to TRUE.
+ * @param   enableFIFO  Enables DMP output to the FIFO if set to TRUE.
+ *
+ * @return  Zero if the command is successful, an error code otherwise.
+ */
+static int MLDLCtrlDmp(struct mldl_cfg *pdata, mlsl_handle_t mlsl_handle,
+                      bool enableRun, bool enableFIFO)
+{
+       unsigned char b;
+
+       MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, 1, &b);
+       if (enableRun) {
+               b |= BIT_DMP_EN;
+       } else {
+               b &= ~BIT_DMP_EN;
+       }
+
+       if (enableFIFO) {
+               b |= BIT_FIFO_EN;
+       }
+
+       b |= BIT_DMP_RST;
+
+       MLSLSerialWriteSingle(mlsl_handle, pdata->addr, MPUREG_USER_CTRL, b);
+
+       return ML_SUCCESS;
+}
+
+/**
+ * @brief Starts the DMP running
+ *
+ * @return ML_SUCCESS or non-zero error code
+ */
+static int MLDLDmpStart(struct mldl_cfg *pdata, mlsl_handle_t mlsl_handle)
+{
+       unsigned char fifoBuf[2];
+       unsigned char tries = 0;
+       unsigned char userCtrlReg;
+       int result;
+       unsigned short len = !0;
+
+       result = MLSLSerialRead(mlsl_handle, pdata->addr,
+                               MPUREG_USER_CTRL, 1, &userCtrlReg);
+
+       while (len != 0 && tries < 6) {
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                              MPUREG_USER_CTRL,
+                                              ((userCtrlReg & (~BIT_FIFO_EN))
+                                               | BIT_FIFO_RST));
+               MLSLSerialRead(mlsl_handle, pdata->addr,
+                              MPUREG_FIFO_COUNTH, 2, fifoBuf);
+               len = (((unsigned short)fifoBuf[0] << 8)
+                      | (unsigned short)fifoBuf[1]);
+               tries++;
+       }
+
+       MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                             MPUREG_USER_CTRL, userCtrlReg);
+
+       return MLDLCtrlDmp(pdata, mlsl_handle,
+                          pdata->dmp_enable, pdata->fifo_enable);
+}
+
+/**
+ *  @brief  enables/disables the I2C pass through to the accelerometer device.
+ *  @param  enable Non-zero to enable pass through.
+ *  @return ML_SUCCESS if the command is successful, an error code otherwise.
+ */
+static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg,
+                           mlsl_handle_t mlsl_handle, unsigned char enable)
+{
+       unsigned char b;
+       int result;
+
+#ifdef ML_USE_DMP_SIM
+       if (!MLGetGyroPresent())        /*  done this way so that pc demo */
+               return ML_SUCCESS;      /*  w/arm board works with universal api */
+#endif
+
+    /*---- get current 'USER_CTRL' into b ----*/
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_USER_CTRL, 1, &b);
+       ERROR_CHECK(result);
+
+       /* No change */
+       if ((b & BIT_AUX_IF_EN) != (enable * BIT_AUX_IF_EN))
+               return ML_SUCCESS;
+
+       b &= ~BIT_AUX_IF_EN;
+
+       if (!enable) {
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_USER_CTRL,
+                                              (b | BIT_AUX_IF_EN));
+               ERROR_CHECK(result);
+       } else {
+               /* Coming out of I2C is tricky due to severla erratta.  Do not modify
+                * this algorithm */
+               /*
+                * 1) wait for the right time and send the command to change the ime
+                * i2c slave address to an invalid address that will get naked
+                *
+                * 0x00 is broadcast.  0x7F is ulikely to be used by any accels.
+                */
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_AUX_SLV_ADDR, 0x7F);
+               ERROR_CHECK(result);
+               /*
+                * 2) wait enough time for a nack to occur, then go into bypass mode:
+                */
+               MLOSSleep(2);
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_USER_CTRL, (b));
+               ERROR_CHECK(result);
+               /*
+                * 3) wait for up to one MPU cycle then restore the slave address
+                */
+               MLOSSleep(5);
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_AUX_SLV_ADDR,
+                                              mldl_cfg->pdata->accel.address);
+               ERROR_CHECK(result);
+
+               /*
+                * 4) reset the ime interface
+                */
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_USER_CTRL,
+                                              (b | BIT_AUX_IF_RST));
+               ERROR_CHECK(result);
+               MLOSSleep(2);
+       }
+
+       return result;
+}
+
+struct tsProdRevMap {
+       /*unsigned char prodRev; */
+       unsigned char siliconRev;
+       unsigned short sensTrim;
+};
+
+#define NUM_OF_PROD_REVS (DIM(prodRevsMap))
+
+#define OLDEST_PROD_REV_SUPPORTED 11
+static struct tsProdRevMap prodRevsMap[] = {
+       {0, 0},
+       {MPU_SILICON_REV_A4, 131},      /* 1 A? OBSOLETED */
+       {MPU_SILICON_REV_A4, 131},      /* 2 | */
+       {MPU_SILICON_REV_A4, 131},      /* 3 V */
+       {MPU_SILICON_REV_A4, 131},      /* 4 */
+       {MPU_SILICON_REV_A4, 131},      /* 5 */
+       {MPU_SILICON_REV_A4, 131},      /* 6 */
+       {MPU_SILICON_REV_A4, 131},      /* 7 */
+       {MPU_SILICON_REV_A4, 131},      /* 8 */
+       {MPU_SILICON_REV_A4, 131},      /* 9 */
+       {MPU_SILICON_REV_A4, 131},      /* 10 */
+       {MPU_SILICON_REV_B1, 131},      /* 11 B1 */
+       {MPU_SILICON_REV_B1, 131},      /* 12 | */
+       {MPU_SILICON_REV_B1, 131},      /* 13 V */
+       {MPU_SILICON_REV_B1, 131},      /* 14 B4 */
+       {MPU_SILICON_REV_B4, 131},      /* 15 | {MPU_SILICON_REV_B4, 131},      // 16 V */
+       {MPU_SILICON_REV_B4, 131},      /* 17 */
+       {MPU_SILICON_REV_B4, 131},      /* 18 */
+       {MPU_SILICON_REV_B4, 115},      /* 19 */
+       {MPU_SILICON_REV_B4, 115},      /* 20 */
+       {MPU_SILICON_REV_B6, 131},      /* 21 B6 */
+       {MPU_SILICON_REV_B4, 115},      /* 22 B4 */
+};
+
+/**
+ *  @internal
+ *  @brief  Get the silicon revision ID from OTP.
+ *          The silicon revision number is in read from OTP bank 0,
+ *          ADDR6[7:2].  The corresponding ID is retrieved by lookup
+ *          in a map.
+ *  @return The silicon revision ID (0 on error).
+ */
+static int MLDLGetSiliconRev(struct mldl_cfg *pdata, mlsl_handle_t mlsl_handle)
+{
+       int result;
+       unsigned char index = 0x00;
+       unsigned char bank =
+           (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0);
+       unsigned short memAddr = ((bank << 8) | 0x06);
+
+       result = MLSLSerialReadMem(mlsl_handle, pdata->addr,
+                                  memAddr, 1, &index);
+       if (result)
+               return result;
+       index >>= 2;
+
+       if (index < OLDEST_PROD_REV_SUPPORTED || NUM_OF_PROD_REVS < index) {
+               pdata->silicon_revision = 0;
+               return ML_ERROR_INVALID_MODULE;
+       } else {
+               pdata->silicon_revision = prodRevsMap[index].siliconRev;
+               pdata->trim = prodRevsMap[index].sensTrim;
+       }
+       return result;
+}
+
+/**
+ *  @brief      Enable/Disable the use MPU's VDDIO level shifters.
+ *              When enabled the voltage interface with AUX or other external
+ *              accelerometer is using Vlogic instead of VDD (supply).
+ *
+ *  @note       Must be called after MLSerialOpen().
+ *  @note       Typically be called before MLDmpOpen().
+ *              If called after MLDmpOpen(), must be followed by a call to
+ *              MLDLApplyLevelShifterBit() to write the setting on the hw.
+ *
+ *  @param[in]  enable
+ *                  1 to enable, 0 to disable
+ *
+ *  @return     ML_SUCCESS if successfull, a non-zero error code otherwise.
+**/
+static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata,
+                                 mlsl_handle_t mlsl_handle,
+                                 unsigned char enable)
+{
+       int result;
+       unsigned char reg;
+       unsigned char mask;
+       unsigned char regval;
+
+       if (0 == pdata->silicon_revision) {
+               return ML_ERROR_INVALID_PARAMETER;
+       }
+
+    /*-- on parts before B6 the VDDIO bit is bit 7 of ACCEL_BURST_ADDR --
+       NOTE: this is incompatible with ST accelerometers where the VDDIO
+       bit MUST be set to enable ST's internal logic to autoincrement
+       the register address on burst reads --*/
+       if ((pdata->silicon_revision & 0xf) < MPU_SILICON_REV_B6) {
+               reg = MPUREG_ACCEL_BURST_ADDR;
+               mask = 0x80;
+       } else {
+       /*-- on B6 parts the VDDIO bit was moved to FIFO_EN2 =>
+               the mask is always 0x04 --*/
+               reg = MPUREG_FIFO_EN2;
+               mask = 0x04;
+       }
+
+       result = MLSLSerialRead(mlsl_handle, pdata->addr, reg, 1, &regval);
+       if (result)
+               return result;
+
+       if (enable)
+               regval |= mask;
+       else
+               regval &= ~mask;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr, reg, regval);
+
+       return result;
+}
+
+/**
+ * @internal
+ * @brief   This function controls the power management on the MPU device.
+ *          The entire chip can be put to low power sleep mode, or individual
+ *          gyros can be turned on/off.
+ *
+ *          Putting the device into sleep mode depending upon the changing needs
+ *          of the associated applications is a recommended method for reducing
+ *          power consuption.  It is a safe opearation in that sleep/wake up of
+ *          gyros while running will not result in any interruption of data.
+ *
+ *          Although it is entirely allowed to put the device into full sleep
+ *          while running the DMP, it is not recomended because it will disrupt
+ *          the ongoing calculations carried on inside the DMP and consequently
+ *          the sensor fusion algorithm. Furthermore, while in sleep mode
+ *          read & write operation from the app processor on both registers and
+ *          memory are disabled and can only regained by restoring the MPU in
+ *          normal power mode.
+ *          Disabling any of the gyro axis will reduce the associated power
+ *          consuption from the PLL but will not stop the DMP from running
+ *          state.
+ *
+ * @param   reset
+ *              Non-zero to reset the device. Note that this setting
+ *              is volatile and the corresponding register bit will
+ *              clear itself right after.
+ * @param   sleep
+ *              Non-zero to put device into full sleep.
+ * @param   disable_gx
+ *              Non-zero to disable gyro X.
+ * @param   disable_gy
+ *              Non-zero to disable gyro Y.
+ * @param   disable_gz
+ *              Non-zero to disable gyro Z.
+ *
+ * @return  ML_SUCCESS if successfull; a non-zero error code otherwise.
+ */
+static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata,
+                           mlsl_handle_t mlsl_handle,
+                           unsigned char reset,
+                           unsigned char sleep,
+                           unsigned char disable_gx,
+                           unsigned char disable_gy, unsigned char disable_gz)
+{
+       unsigned char b;
+       int result;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1, &b);
+       ERROR_CHECK(result);
+
+       /* If we are awake, we need to put it in bypass before resetting */
+       if ((!(b & BIT_SLEEP)) && reset) {
+               result = MLDLSetI2CBypass(pdata, mlsl_handle, 1);
+       }
+
+       /* Reset if requested */
+       if (reset) {
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                         MPUREG_PWR_MGM, b | BIT_H_RESET);
+               MLOSSleep(5);
+       }
+
+       /* Some chips are awake after reset and some are asleep, check the status */
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1, &b);
+       ERROR_CHECK(result);
+
+       /* Update the suspended state just in case we return early */
+       if (b & BIT_SLEEP) {
+               pdata->is_suspended = TRUE;
+       } else {
+               pdata->is_suspended = FALSE;
+       }
+
+       if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG))
+           == ((sleep * BIT_SLEEP) |
+               (disable_gz * BIT_STBY_XG) |
+               (disable_gy * BIT_STBY_YG) | (disable_gz * BIT_STBY_ZG))) {
+               return ML_SUCCESS;
+       }
+
+       /*
+        *  This specific transition between states needs to be reinterpreted:
+        *     (1,1,1,1) -> (0,1,1,1) has to become
+        *     (1,1,1,1) -> (1,0,0,0) -> (0,1,1,1)
+        *  where
+        *     (1,1,1,1) stands for (sleep=1,disable_gx=1,disable_gy=1,disable_gz=1)
+        */
+       if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) == (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)        /* (1,1,1,1) */
+           && ((!sleep) && disable_gx && disable_gy && disable_gz)) {  /* (0,1,1,1) */
+
+               result = MLDLPowerMgmtMPU(pdata, mlsl_handle, 0, 1, 0, 0, 0);
+               if (result)
+                       return result;
+               b |= BIT_SLEEP;
+               b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
+       }
+
+       if ((b & BIT_SLEEP) != (sleep * BIT_SLEEP)) {
+               if (sleep) {
+                       result = MLDLSetI2CBypass(pdata, mlsl_handle, 1);
+                       ERROR_CHECK(result);
+                       b |= BIT_SLEEP;
+                       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                                      MPUREG_PWR_MGM, b);
+                       ERROR_CHECK(result);
+                       pdata->is_suspended = TRUE;
+               } else {
+                       b &= ~BIT_SLEEP;
+
+                       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                                      MPUREG_PWR_MGM, b);
+                       ERROR_CHECK(result);
+                       pdata->is_suspended = FALSE;
+                       MLOSSleep(5);
+               }
+       }
+    /*---
+      WORKAROUND FOR PUTTING GYRO AXIS in STAND-BY MODE
+      1) put one axis at a time in stand-by
+      ---*/
+       if ((b & BIT_STBY_XG) != (disable_gx * BIT_STBY_XG)) {
+               b ^= BIT_STBY_XG;
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                              MPUREG_PWR_MGM, b);
+               ERROR_CHECK(result);
+       }
+       if ((b & BIT_STBY_YG) != (disable_gy * BIT_STBY_YG)) {
+               b ^= BIT_STBY_YG;
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                              MPUREG_PWR_MGM, b);
+               ERROR_CHECK(result);
+       }
+       if ((b & BIT_STBY_ZG) != (disable_gz * BIT_STBY_ZG)) {
+               b ^= BIT_STBY_ZG;
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                              MPUREG_PWR_MGM, b);
+               ERROR_CHECK(result);
+       }
+
+       return ML_SUCCESS;
+}
+
+void mpu3050_print_cfg(struct mldl_cfg *mldl_cfg)
+{
+       struct mpu3050_platform_data *pdata = mldl_cfg->pdata;
+       struct ext_slave_platform_data *accel = &mldl_cfg->pdata->accel;
+       struct ext_slave_platform_data *compass = &mldl_cfg->pdata->compass;
+
+       MPL_LOGD("mldl_cfg.addr             = %02x\n", mldl_cfg->addr);
+       MPL_LOGD("mldl_cfg.int_config       = %02x\n", mldl_cfg->int_config);
+       MPL_LOGD("mldl_cfg.ext_sync         = %02x\n", mldl_cfg->ext_sync);
+       MPL_LOGD("mldl_cfg.full_scale       = %02x\n", mldl_cfg->full_scale);
+       MPL_LOGD("mldl_cfg.lpf              = %02x\n", mldl_cfg->lpf);
+       MPL_LOGD("mldl_cfg.clk_src          = %02x\n", mldl_cfg->clk_src);
+       MPL_LOGD("mldl_cfg.divider          = %02x\n", mldl_cfg->divider);
+       MPL_LOGD("mldl_cfg.dmp_enable       = %02x\n", mldl_cfg->dmp_enable);
+       MPL_LOGD("mldl_cfg.fifo_enable      = %02x\n", mldl_cfg->fifo_enable);
+       MPL_LOGD("mldl_cfg.dmp_cfg1         = %02x\n", mldl_cfg->dmp_cfg1);
+       MPL_LOGD("mldl_cfg.dmp_cfg2         = %02x\n", mldl_cfg->dmp_cfg2);
+       MPL_LOGD("mldl_cfg.offset_tc[0]     = %02x\n", mldl_cfg->offset_tc[0]);
+       MPL_LOGD("mldl_cfg.offset_tc[1]     = %02x\n", mldl_cfg->offset_tc[1]);
+       MPL_LOGD("mldl_cfg.offset_tc[2]     = %02x\n", mldl_cfg->offset_tc[2]);
+       MPL_LOGD("mldl_cfg.silicon_revision = %02x\n",
+                mldl_cfg->silicon_revision);
+       MPL_LOGD("mldl_cfg.product_id       = %02x\n", mldl_cfg->product_id);
+       MPL_LOGD("mldl_cfg.trim             = %02x\n", mldl_cfg->trim);
+
+       if (mldl_cfg->accel) {
+               MPL_LOGD("slave_accel->suspend      = %02x\n",
+                        (int)mldl_cfg->accel->suspend);
+               MPL_LOGD("slave_accel->resume       = %02x\n",
+                        (int)mldl_cfg->accel->resume);
+               MPL_LOGD("slave_accel->read         = %02x\n",
+                        (int)mldl_cfg->accel->read);
+               MPL_LOGD("slave_accel->type         = %02x\n",
+                        mldl_cfg->accel->type);
+               MPL_LOGD("slave_accel->reg          = %02x\n",
+                        mldl_cfg->accel->reg);
+               MPL_LOGD("slave_accel->len          = %02x\n",
+                        mldl_cfg->accel->len);
+               MPL_LOGD("slave_accel->endian       = %02x\n",
+                        mldl_cfg->accel->endian);
+               MPL_LOGD("slave_accel->range.mantissa= %02lx\n",
+                        mldl_cfg->accel->range.mantissa);
+               MPL_LOGD("slave_accel->range.fraction= %02lx\n",
+                        mldl_cfg->accel->range.fraction);
+       } else {
+               MPL_LOGD("slave_accel               = NULL\n");
+       }
+
+       if (mldl_cfg->compass) {
+               MPL_LOGD("slave_compass->suspend    = %02x\n",
+                        (int)mldl_cfg->compass->suspend);
+               MPL_LOGD("slave_compass->resume     = %02x\n",
+                        (int)mldl_cfg->compass->resume);
+               MPL_LOGD("slave_compass->read       = %02x\n",
+                        (int)mldl_cfg->compass->read);
+               MPL_LOGD("slave_compass->type       = %02x\n",
+                        mldl_cfg->compass->type);
+               MPL_LOGD("slave_compass->reg        = %02x\n",
+                        mldl_cfg->compass->reg);
+               MPL_LOGD("slave_compass->len        = %02x\n",
+                        mldl_cfg->compass->len);
+               MPL_LOGD("slave_compass->endian     = %02x\n",
+                        mldl_cfg->compass->endian);
+               MPL_LOGD("slave_compass->range.mantissa= %02lx\n",
+                        mldl_cfg->compass->range.mantissa);
+               MPL_LOGD("slave_compass->range.fraction= %02lx\n",
+                        mldl_cfg->compass->range.fraction);
+
+       } else {
+               MPL_LOGD("slave_compass             = NULL\n");
+       }
+       MPL_LOGD("accel->get_slave_descr    = %x\n",
+                (unsigned int)accel->get_slave_descr);
+       MPL_LOGD("accel->adapt_num          = %02x\n", accel->adapt_num);
+       MPL_LOGD("accel->bus                = %02x\n", accel->bus);
+       MPL_LOGD("accel->address            = %02x\n", accel->address);
+       MPL_LOGD("accel->orientation        = \n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n",
+                accel->orientation[0], accel->orientation[1],
+                accel->orientation[2], accel->orientation[3],
+                accel->orientation[4], accel->orientation[5],
+                accel->orientation[6], accel->orientation[7],
+                accel->orientation[8]);
+       MPL_LOGD("compass->get_slave_descr  = %x\n",
+                (unsigned int)compass->get_slave_descr);
+       MPL_LOGD("compass->adapt_num        = %02x\n", compass->adapt_num);
+       MPL_LOGD("compass->bus              = %02x\n", compass->bus);
+       MPL_LOGD("compass->address          = %02x\n", compass->address);
+       MPL_LOGD("compass->orientation      = \n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n",
+                compass->orientation[0], compass->orientation[1],
+                compass->orientation[2], compass->orientation[3],
+                compass->orientation[4], compass->orientation[5],
+                compass->orientation[6], compass->orientation[7],
+                compass->orientation[8]);
+
+       MPL_LOGD("pdata->int_config         = %02x\n", pdata->int_config);
+       MPL_LOGD("pdata->level_shifter      = %02x\n", pdata->level_shifter);
+       MPL_LOGD("pdata->orientation        = \n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n",
+                pdata->orientation[0], pdata->orientation[1],
+                pdata->orientation[2], pdata->orientation[3],
+                pdata->orientation[4], pdata->orientation[5],
+                pdata->orientation[6], pdata->orientation[7],
+                pdata->orientation[8]);
+
+       MPL_LOGD("Struct sizes: mldl_cfg: %d, "
+                "ext_slave_descr:%d, mpu3050_platform_data:%d: RamOffset: %d\n",
+                sizeof(struct mldl_cfg), sizeof(struct ext_slave_descr),
+                sizeof(struct mpu3050_platform_data),
+                offsetof(struct mldl_cfg, ram));
+}
+
+/*******************************************************************************
+ *******************************************************************************
+ * Exported functions
+ *******************************************************************************
+ ******************************************************************************/
+
+/**
+ * Initializes the pdata structure to defaults.
+ *
+ * Opens the device to read silicon revision, product id and whoami.
+ *
+ * @param mldl_cfg
+ *          The internal device configuration data structure.
+ * @param mlsl_handle
+ *          The serial communication handle.
+ *
+ * @return ML_SUCCESS if silicon revision, product id and woami are supported
+ *         by this software.
+ */
+int mpu3050_open(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle)
+{
+       int result;
+       /* Default is Logic HIGH, pushpull, latch disabled, anyread to clear */
+       mldl_cfg->int_config = BIT_INT_ANYRD_2CLEAR | BIT_DMP_INT_EN;
+       mldl_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ;
+       mldl_cfg->lpf = MPU_FILTER_42HZ;
+       mldl_cfg->full_scale = MPU_FS_2000DPS;
+       mldl_cfg->divider = 4;
+       mldl_cfg->dmp_enable = 1;
+       mldl_cfg->fifo_enable = 1;
+       mldl_cfg->ext_sync = 0;
+       mldl_cfg->dmp_cfg1 = 0;
+       mldl_cfg->dmp_cfg2 = 0;
+       if (mldl_cfg->addr == 0) {
+#ifdef __KERNEL__
+               return ML_ERROR_INVALID_PARAMETER;
+#else
+               mldl_cfg->addr = 0x68;
+#endif
+       }
+
+       /*
+        * Reset,
+        * Take the DMP out of sleep, and
+        * read the product_id, sillicon rev and whoami
+        */
+       result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 1, 0, 0, 0, 0);
+       ERROR_CHECK(result);
+
+       result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle);
+       ERROR_CHECK(result);
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_PRODUCT_ID, 1, &mldl_cfg->product_id);
+       ERROR_CHECK(result);
+
+       /* Get the factory temperature compensation offsets */
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_XG_OFFS_TC, 1, &mldl_cfg->offset_tc[0]);
+       ERROR_CHECK(result);
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_YG_OFFS_TC, 1, &mldl_cfg->offset_tc[1]);
+       ERROR_CHECK(result);
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_ZG_OFFS_TC, 1, &mldl_cfg->offset_tc[2]);
+       ERROR_CHECK(result);
+
+       /* Configure the MPU */
+       result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, 1, 0, 0, 0);
+       ERROR_CHECK(result);
+       return result;
+}
+
+int mpu3050_resume(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                  mlsl_handle_t accel_handle,
+                  mlsl_handle_t compass_handle,
+                  bool resume_accel, bool resume_compass)
+{
+       int result;
+       int ii;
+       int jj;
+       unsigned char reg;
+
+       /* mpu3050_print_cfg(mldl_cfg); */
+       /* Wake up the part */
+       result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 1, 0, 0, 0, 0);
+       ERROR_CHECK(result);
+
+       /* Configure the MPU */
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_INT_CFG,
+                                      (mldl_cfg->int_config | mldl_cfg->
+                                       pdata->int_config));
+       ERROR_CHECK(result);
+
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_PWR_MGM, 1, &reg);
+       ERROR_CHECK(result);
+       reg &= ~BITS_CLKSEL;
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_PWR_MGM, mldl_cfg->clk_src | reg);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_SMPLRT_DIV, mldl_cfg->divider);
+       ERROR_CHECK(result);
+
+       reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync,
+                                mldl_cfg->full_scale, mldl_cfg->lpf);
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_DLPF_FS_SYNC, reg);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_DMP_CFG_1, mldl_cfg->dmp_cfg1);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_DMP_CFG_2, mldl_cfg->dmp_cfg2);
+       ERROR_CHECK(result);
+
+       /* Write and verify memory */
+       for (ii = 0; ii < MPU_MEM_NUM_RAM_BANKS; ii++) {
+               unsigned char read[128];
+               result = MLSLSerialWriteMem(mlsl_handle, mldl_cfg->addr,
+                                           ((ii << 8)),
+                                           MPU_MEM_BANK_SIZE / 2,
+                                           mldl_cfg->ram[ii]);
+               ERROR_CHECK(result);
+               result = MLSLSerialReadMem(mlsl_handle, mldl_cfg->addr,
+                                          ((ii << 8) | 0),
+                                          MPU_MEM_BANK_SIZE / 2, read);
+               ERROR_CHECK(result);
+
+               for (jj = 0; jj < MPU_MEM_BANK_SIZE / 2; jj++) {
+                       /* skip the register memory locations */
+                       if (ii == 0 && jj < 20)
+                               continue;
+                       if (mldl_cfg->ram[ii][jj] != read[jj]) {
+                               result = ML_ERROR_SERIAL_WRITE;
+                               break;
+                       }
+               }
+               ERROR_CHECK(result);
+
+               result = MLSLSerialWriteMem(mlsl_handle, mldl_cfg->addr,
+                                           ((ii << 8) | MPU_MEM_BANK_SIZE / 2),
+                                           MPU_MEM_BANK_SIZE / 2,
+                                           &mldl_cfg->ram[ii][MPU_MEM_BANK_SIZE
+                                                              / 2]);
+               ERROR_CHECK(result);
+               result = MLSLSerialReadMem(mlsl_handle, mldl_cfg->addr,
+                                          ((ii << 8) | MPU_MEM_BANK_SIZE / 2),
+                                          MPU_MEM_BANK_SIZE / 2, read);
+               ERROR_CHECK(result);
+               for (jj = 0; jj < MPU_MEM_BANK_SIZE / 2; jj++) {
+                       if (mldl_cfg->ram[ii][MPU_MEM_BANK_SIZE / 2 + jj] !=
+                           read[jj]) {
+                               result = ML_ERROR_SERIAL_WRITE;
+                               break;
+                       }
+               }
+               ERROR_CHECK(result);
+       }
+
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_XG_OFFS_TC,
+                                      mldl_cfg->offset_tc[0]);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_YG_OFFS_TC,
+                                      mldl_cfg->offset_tc[1]);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                      MPUREG_ZG_OFFS_TC,
+                                      mldl_cfg->offset_tc[2]);
+       ERROR_CHECK(result);
+
+       /* Configure slaves */
+       result = MLDLSetLevelShifterBit(mldl_cfg, mlsl_handle,
+                                       mldl_cfg->pdata->level_shifter);
+       ERROR_CHECK(result);
+
+       if (resume_accel) {
+               if ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume)) {
+                       return ML_ERROR_INVALID_PARAMETER;
+               }
+               result = mldl_cfg->accel->resume(accel_handle,
+                                                mldl_cfg->accel,
+                                                &mldl_cfg->pdata->accel);
+               ERROR_CHECK(result);
+               if (EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+                       /* Address */
+                       result =
+                           MLSLSerialWriteSingle(accel_handle, mldl_cfg->addr,
+                                                 MPUREG_AUX_SLV_ADDR,
+                                                 mldl_cfg->pdata->
+                                                 accel.address);
+                       ERROR_CHECK(result);
+                       /* Register */
+                       result = MLSLSerialRead(accel_handle, mldl_cfg->addr,
+                                               MPUREG_ACCEL_BURST_ADDR, 1,
+                                               &reg);
+                       ERROR_CHECK(result);
+                       reg = ((reg & 0x80) | mldl_cfg->accel->reg);
+                       /* Set VDDIO bit for ST accel */
+                       if ((ACCEL_ID_LIS331 == mldl_cfg->accel->id)
+                           || (ACCEL_ID_LSM303 == mldl_cfg->accel->id)) {
+                               reg |= 0x80;
+                       }
+                       result =
+                           MLSLSerialWriteSingle(accel_handle, mldl_cfg->addr,
+                                                 MPUREG_ACCEL_BURST_ADDR, reg);
+                       ERROR_CHECK(result);
+                       /* Length */
+                       result = MLSLSerialRead(accel_handle, mldl_cfg->addr,
+                                               MPUREG_USER_CTRL, 1, &reg);
+                       ERROR_CHECK(result);
+                       reg = (reg & ~BIT_AUX_RD_LENG);
+                       result =
+                           MLSLSerialWriteSingle(accel_handle, mldl_cfg->addr,
+                                                 MPUREG_USER_CTRL, reg);
+                       ERROR_CHECK(result);
+                       result = MLDLSetI2CBypass(mldl_cfg, accel_handle, 0);
+                       ERROR_CHECK(result);
+               }
+       }
+
+       if (resume_compass) {
+               if ((mldl_cfg->compass) && (mldl_cfg->compass->resume)) {
+                       result = mldl_cfg->compass->resume(compass_handle,
+                                                          mldl_cfg->compass,
+                                                          &mldl_cfg->
+                                                          pdata->compass);
+                       ERROR_CHECK(result);
+               }
+       }
+
+       /* Now start */
+       result = MLDLDmpStart(mldl_cfg, mlsl_handle);
+       ERROR_CHECK(result);
+       return result;
+}
+
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                   mlsl_handle_t accel_handle,
+                   mlsl_handle_t compass_handle, bool accel, bool compass)
+{
+       int result;
+       /* This puts the bus into bypass mode */
+       result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, 1, 0, 0, 0);
+       if (ML_SUCCESS == result &&
+           accel && mldl_cfg->accel && mldl_cfg->accel->suspend) {
+               result = mldl_cfg->accel->suspend(accel_handle,
+                                                 mldl_cfg->accel,
+                                                 &mldl_cfg->pdata->accel);
+       }
+
+       if (ML_SUCCESS == result && compass &&
+           mldl_cfg->compass && mldl_cfg->compass->suspend) {
+               result = mldl_cfg->compass->suspend(compass_handle,
+                                                   mldl_cfg->compass,
+                                                   &mldl_cfg->pdata->compass);
+       }
+       return result;
+}
+
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                      unsigned char *data)
+{
+       if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read)
+               return mldl_cfg->accel->read(mlsl_handle,
+                                            mldl_cfg->accel,
+                                            &mldl_cfg->pdata->accel, data);
+       else
+               return ML_ERROR_NOT_OPENED;
+}
+
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                        unsigned char *data)
+{
+       if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read)
+               return mldl_cfg->compass->read(mlsl_handle,
+                                              mldl_cfg->compass,
+                                              &mldl_cfg->pdata->compass, data);
+       else
+               return ML_ERROR_NOT_OPENED;
+}
+
+/***************************/
+              /**@}*//* end of defgroup */
+/***************************/
diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h
new file mode 100755 (executable)
index 0000000..03f752b
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: mldl_cfg.h 3876 2010-10-12 02:42:22Z prao $
+ *
+ *******************************************************************************/
+
+/**
+ *  @addtogroup MLDL
+ *
+ *  @{
+ *      @file   mldl_cfg.h
+ *      @brief  The Motion Library Driver Layer Configuration header file.
+ */
+
+#ifndef __MLDL_CFG_H__
+#define __MLDL_CFG_H__
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#include "mlsl.h"
+#include "mpu3050.h"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/* Platform data for the MPU */
+struct mldl_cfg {
+       /* MPU related configuration */
+       unsigned char addr;
+       unsigned char int_config;
+       unsigned char ext_sync;
+       unsigned char full_scale;
+       unsigned char lpf;
+       unsigned char clk_src;
+       unsigned char divider;
+       unsigned char dmp_enable;
+       unsigned char fifo_enable;
+       unsigned char dmp_cfg1;
+       unsigned char dmp_cfg2;
+       unsigned char offset_tc[MPU_NUM_AXES];
+       unsigned char __packing;
+       unsigned char ram[MPU_MEM_NUM_RAM_BANKS][MPU_MEM_BANK_SIZE];
+
+       /* MPU Related stored status and info */
+       unsigned char silicon_revision;
+       unsigned char product_id;
+       unsigned short trim;
+
+       /* Driver/Kernel related state information */
+       int is_suspended;
+
+       /* Slave related information */
+       struct ext_slave_descr *accel;
+       struct ext_slave_descr *compass;
+
+       struct mpu3050_platform_data *pdata;
+};
+
+int mpu3050_open(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle);
+int mpu3050_resume(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                  mlsl_handle_t accel_handle,
+                  mlsl_handle_t compass_handle,
+                  bool resume_accel, bool resume_compass);
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                   mlsl_handle_t accel_handle,
+                   mlsl_handle_t compass_handle,
+                   bool suspend_accel, bool suspend_compass);
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                      unsigned char *data);
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg, mlsl_handle_t mlsl_handle,
+                        unsigned char *data);
+
+#endif                         /* __MLDL_CFG_H__ */
+
+/***************************/
+              /**@}*//* end of defgroup */
+/***************************/
diff --git a/drivers/misc/mpu3050/mlos-kernel.c b/drivers/misc/mpu3050/mlos-kernel.c
new file mode 100755 (executable)
index 0000000..9492ec1
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/***************************************************************************** *
+ * $Id: mlos-kernel.c 3863 2010-10-08 22:05:31Z nroyer $
+ ******************************************************************************/
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ * @file     mlos-kernel.c
+ * @brief
+ *
+ *
+ */
+
+#include "mlos.h"
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+void *MLOSMalloc(unsigned int numBytes)
+{
+       return kmalloc(numBytes, GFP_KERNEL);
+}
+
+tMLError MLOSFree(void *ptr)
+{
+       kfree(ptr);
+       return ML_SUCCESS;
+}
+
+tMLError MLOSCreateMutex(HANDLE *mutex)
+{
+       /* @todo implement if needed */
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+tMLError MLOSLockMutex(HANDLE mutex)
+{
+       /* @todo implement if needed */
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+tMLError MLOSUnlockMutex(HANDLE mutex)
+{
+       /* @todo implement if needed */
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+tMLError MLOSDestroyMutex(HANDLE handle)
+{
+       /* @todo implement if needed */
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+FILE *MLOSFOpen(char *filename)
+{
+       /* @todo implement if needed */
+       return NULL;
+}
+
+void MLOSFClose(FILE *fp)
+{
+       /* @todo implement if needed */
+}
+
+void MLOSSleep(int mSecs)
+{
+       msleep(mSecs);
+}
+
+unsigned long MLOSGetTickCount(void)
+{
+       /* @todo implement if needed */
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
diff --git a/drivers/misc/mpu3050/mlos.h b/drivers/misc/mpu3050/mlos.h
new file mode 100755 (executable)
index 0000000..4a54ce2
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: mlos.h 3863 2010-10-08 22:05:31Z nroyer $
+ *
+ *******************************************************************************/
+
+#ifndef _MLOS_H
+#define _MLOS_H
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#endif
+
+#include "mltypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+       /* ------------ */
+       /* - Defines. - */
+       /* ------------ */
+
+       /* - MLOSCreateFile defines. - */
+
+#define MLOS_GENERIC_READ         ((unsigned int)0x80000000)
+#define MLOS_GENERIC_WRITE        ((unsigned int)0x40000000)
+#define MLOS_FILE_SHARE_READ      ((unsigned int)0x00000001)
+#define MLOS_FILE_SHARE_WRITE     ((unsigned int)0x00000002)
+#define MLOS_OPEN_EXISTING        ((unsigned int)0x00000003)
+
+       /* ---------- */
+       /* - Enums. - */
+       /* ---------- */
+
+       /* --------------- */
+       /* - Structures. - */
+       /* --------------- */
+
+       /* --------------------- */
+       /* - Function p-types. - */
+       /* --------------------- */
+
+       void *MLOSMalloc(unsigned int numBytes);
+       tMLError MLOSFree(void *ptr);
+       tMLError MLOSCreateMutex(HANDLE *mutex);
+       tMLError MLOSLockMutex(HANDLE mutex);
+       tMLError MLOSUnlockMutex(HANDLE mutex);
+       FILE *MLOSFOpen(char *filename);
+       void MLOSFClose(FILE *fp);
+
+       tMLError MLOSDestroyMutex(HANDLE handle);
+
+       void MLOSSleep(int mSecs);
+       unsigned long MLOSGetTickCount(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif                         /* _MLOS_H */
diff --git a/drivers/misc/mpu3050/mlsl-kernel.c b/drivers/misc/mpu3050/mlsl-kernel.c
new file mode 100755 (executable)
index 0000000..4b9494f
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: mlsl-kernel.c 3863 2010-10-08 22:05:31Z nroyer $
+ *
+ ******************************************************************************/
+
+#include "mlsl.h"
+#include "mpu-i2c.h"
+
+/* ------------ */
+/* - Defines. - */
+/* ------------ */
+
+/* ---------------------- */
+/* - Types definitions. - */
+/* ---------------------- */
+
+/* --------------------- */
+/* - Function p-types. - */
+/* --------------------- */
+
+/**
+ *  @brief  used to open the I2C or SPI serial port.
+ *          This port is used to send and receive data to the MPU device.
+ *  @param  portNum
+ *              The COM port number associated with the device in use.
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+tMLError MLSLSerialOpen(char const *port, mlsl_handle_t * sl_handle)
+{
+       return ML_SUCCESS;
+}
+
+/**
+ *  @brief  used to reset any buffering the driver may be doing
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+tMLError MLSLSerialReset(mlsl_handle_t sl_handle)
+{
+       return ML_SUCCESS;
+}
+
+/**
+ *  @brief  used to close the I2C or SPI serial port.
+ *          This port is used to send and receive data to the MPU device.
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+tMLError MLSLSerialClose(mlsl_handle_t sl_handle)
+{
+       return ML_SUCCESS;
+}
+
+/**
+ *  @brief  used to read a single byte of data.
+ *          This should be sent by I2C or SPI.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  registerAddr    Register address to read.
+ *  @param  data            Single byte of data to read.
+ *
+ *  @return ML_SUCCESS if the command is successful, an error code otherwise.
+ */
+tMLError MLSLSerialWriteSingle(mlsl_handle_t sl_handle,
+                              unsigned char slaveAddr,
+                              unsigned char registerAddr, unsigned char data)
+{
+       return sensor_i2c_write_register((struct i2c_adapter *)sl_handle,
+                                        slaveAddr, registerAddr, data);
+
+}
+
+/**
+ *  @brief  used to read multiple bytes of data.
+ *          This should be sent by I2C or SPI.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  registerAddr    Register address to read.
+ *  @param  length          Length of burst data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if the command is successful; an error code otherwise
+ */
+tMLError MLSLSerialRead(mlsl_handle_t sl_handle,
+                       unsigned char slaveAddr,
+                       unsigned char registerAddr,
+                       unsigned short length, unsigned char *data)
+{
+       return sensor_i2c_read((struct i2c_adapter *)sl_handle,
+                              slaveAddr, registerAddr, length, data);
+}
+
+/**
+ *  @brief  used to write multiple bytes of data.
+ *          This should be sent by I2C or SPI.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  length          Length of burst data.
+ *  @param  data            Pointer to block of data.  First byte is the
+ *                          register address to write.
+ *
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+tMLError MLSLSerialWrite(mlsl_handle_t sl_handle,
+                        unsigned char slaveAddr,
+                        unsigned short length, unsigned char const *data)
+{
+       return sensor_i2c_write((struct i2c_adapter *)sl_handle,
+                               slaveAddr, length, data);
+}
+
+/**
+ *  @brief  used to read multiple bytes of data.
+ *          This should be sent by I2C or SPI.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  registerAddr    Register address to read.
+ *  @param  length          Length of burst data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if the command is successful; an error code otherwise
+ */
+tMLError MLSLSerialReadMem(mlsl_handle_t sl_handle,
+                          unsigned char slaveAddr,
+                          unsigned short memAddr,
+                          unsigned short length, unsigned char *data)
+{
+       return mpu_memory_read((struct i2c_adapter *)sl_handle,
+                              slaveAddr, memAddr, length, data);
+}
+
+/**
+ *  @brief  used to write multiple bytes of data.
+ *          This should be sent by I2C or SPI.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  length          Length of burst data.
+ *  @param  data            Pointer to block of data.  First byte is the
+ *                          register address to write.
+ *
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+tMLError MLSLSerialWriteMem(mlsl_handle_t sl_handle,
+                           unsigned char slaveAddr,
+                           unsigned short mem_addr,
+                           unsigned short length, unsigned char const *data)
+{
+       return mpu_memory_write((struct i2c_adapter *)sl_handle,
+                               slaveAddr, mem_addr, length, data);
+}
+
+/***********************/
+                  /** @} *//* defgroup */
+/*********************/
diff --git a/drivers/misc/mpu3050/mlsl.h b/drivers/misc/mpu3050/mlsl.h
new file mode 100755 (executable)
index 0000000..d41683e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: mlsl.h 3863 2010-10-08 22:05:31Z nroyer $
+ *
+ ******************************************************************************/
+
+#ifndef __MSSL_H__
+#define __MSSL_H__
+
+#include "mltypes.h"
+#include "mpu3050.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------ */
+/* - Defines. - */
+/* ------------ */
+
+/* ---------------------- */
+/* - Types definitions. - */
+/* ---------------------- */
+
+       typedef void *tMLSLHandle;      /* For MPL coding standards */
+
+/* --------------------- */
+/* - Function p-types. - */
+/* --------------------- */
+
+       tMLError MLSLSerialOpen(char const *port, mlsl_handle_t * sl_handle);
+       tMLError MLSLSerialReset(mlsl_handle_t sl_handle);
+       tMLError MLSLSerialClose(mlsl_handle_t sl_handle);
+       tMLError MLSLSerialWriteSingle(mlsl_handle_t sl_handle,
+                                      unsigned char slaveAddr,
+                                      unsigned char registerAddr,
+                                      unsigned char data);
+       tMLError MLSLSerialRead(mlsl_handle_t sl_handle,
+                               unsigned char slaveAddr,
+                               unsigned char registerAddr,
+                               unsigned short length, unsigned char *data);
+       tMLError MLSLSerialWrite(mlsl_handle_t sl_handle,
+                                unsigned char slaveAddr,
+                                unsigned short length,
+                                unsigned char const *data);
+       tMLError MLSLSerialReadMem(mlsl_handle_t sl_handle,
+                                  unsigned char slaveAddr,
+                                  unsigned short memAddr,
+                                  unsigned short length, unsigned char *data);
+       tMLError MLSLSerialWriteMem(mlsl_handle_t sl_handle,
+                                   unsigned char slaveAddr,
+                                   unsigned short memAddr,
+                                   unsigned short length,
+                                   unsigned char const *data);
+       tMLError MLSLWriteCal(unsigned char *cal, unsigned int len);
+       tMLError MLSLGetCalLength(unsigned int *len);
+       tMLError MLSLReadCal(unsigned char *cal, unsigned int len);
+
+#ifdef __cplusplus
+}
+#endif
+                                               /***********************//** @} *//* defgroup *//*********************/
+#endif                         // MLSL_H
diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h
new file mode 100755 (executable)
index 0000000..4ffc890
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/*******************************************************************************
+ *
+ * $Id: mltypes.h 3866 2010-10-09 00:51:32Z nroyer $
+ *
+ *******************************************************************************/
+
+/**
+ *  @defgroup MLERROR
+ *  @brief  Definition of the error codes used within the MPL and returned
+ *          to the user.
+ *          Every function tries to return a meaningful error code basing
+ *          on the occuring error condition. The error code is numeric.
+ *
+ *          The available error codes and their associated values are:
+ *          - (0)       ML_SUCCESS
+ *          - (1)       ML_ERROR
+ *          - (2)       ML_ERROR_INVALID_PARAMETER
+ *          - (3)       ML_ERROR_FEATURE_NOT_ENABLED
+ *          - (4)       ML_ERROR_FEATURE_NOT_IMPLEMENTED
+ *          - (6)       ML_ERROR_DMP_NOT_STARTED
+ *          - (7)       ML_ERROR_DMP_STARTED
+ *          - (8)       ML_ERROR_NOT_OPENED
+ *          - (9)       ML_ERROR_OPENED
+ *          - (10)      ML_ERROR_INVALID_MODULE
+ *          - (11)      ML_ERROR_MEMORY_EXAUSTED
+ *          - (12)      ML_ERROR_DIVIDE_BY_ZERO
+ *          - (13)      ML_ERROR_ASSERTION_FAILURE
+ *          - (14)      ML_ERROR_FILE_OPEN
+ *          - (15)      ML_ERROR_FILE_READ
+ *          - (16)      ML_ERROR_FILE_WRITE
+ *          - (20)      ML_ERROR_SERIAL_CLOSED
+ *          - (21)      ML_ERROR_SERIAL_OPEN_ERROR
+ *          - (22)      ML_ERROR_SERIAL_READ
+ *          - (23)      ML_ERROR_SERIAL_WRITE
+ *          - (24)      ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED
+ *          - (25)      ML_ERROR_SM_TRANSITION
+ *          - (26)      ML_ERROR_SM_IMPROPER_STATE
+ *          - (30)      ML_ERROR_FIFO_OVERFLOW
+ *          - (31)      ML_ERROR_FIFO_FOOTER
+ *          - (32)      ML_ERROR_FIFO_READ_COUNT
+ *          - (33)      ML_ERROR_FIFO_READ_DATA
+ *          - (40)      ML_ERROR_MEMORY_SET
+ *          - (50)      ML_ERROR_LOG_MEMORY_ERROR
+ *          - (51)      ML_ERROR_LOG_OUTPUT_ERROR
+ *          - (60)      ML_ERROR_OS_BAD_PTR
+ *          - (61)      ML_ERROR_OS_BAD_HANDLE
+ *          - (62)      ML_ERROR_OS_CREATE_FAILED
+ *          - (63)      ML_ERROR_OS_LOCK_FAILED
+ *          - (70)      ML_ERROR_COMPASS_DATA_OVERFLOW
+ *          - (71)      ML_ERROR_COMPASS_DATA_UNDERFLOW
+ *          - (72)      ML_ERROR_COMPASS_DATA_NOT_READY
+ *
+**/
+
+#ifndef MLTYPES_H
+#define MLTYPES_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include "stdint_invensense.h"
+#endif
+#include "log.h"
+
+/*---------------------------
+    ML Types
+---------------------------*/
+
+typedef long long MLS64;
+typedef int MLS32;
+typedef unsigned int MLU32;
+typedef short MLS16;
+typedef unsigned short MLU16;
+typedef char MLS8;
+typedef unsigned char MLU8;
+typedef unsigned char MLBOOL;
+typedef double MLDBL;
+typedef float MLFLT;
+
+typedef unsigned char tReg;
+
+/**
+ * @struct tMLError The MPL Error Code return type.
+ *
+ * @code
+ *      typedef unsigned char tMLError;
+ * @endcode
+ */
+typedef unsigned char tMLError;
+
+#if defined(LINUX) || defined (__KERNEL__)
+typedef unsigned int HANDLE;
+#endif
+
+#ifdef __KERNEL__
+typedef HANDLE FILE;
+#endif
+
+#ifndef __cplusplus
+#ifndef __KERNEL__
+typedef int_fast8_t bool;
+#endif
+#endif
+
+/*---------------------------
+    ML Defines
+---------------------------*/
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* Dimension of an array */
+#ifndef DIM
+#define DIM(array) (sizeof(array)/sizeof((array)[0]))
+#endif
+
+/* - ML Errors. - */
+#define ERROR_NAME(x)   (#x)
+#define ERROR_CHECK(x)                                                  \
+{                                                                       \
+       if (ML_SUCCESS != x) {                                                 \
+          MPL_LOGE("%s|%s|%d returning %d\n",                             \
+          __FILE__, __func__, __LINE__, x);                           \
+       return x;                                                       \
+    }                                                                   \
+}
+
+#define ERROR_CHECK_FIRST(first, x)       {if (ML_SUCCESS == first) first = x; }
+
+#define ML_SUCCESS                       (0)
+/* Generic Error code.  Propritary Error Codes only */
+#define ML_ERROR                         (1)
+
+/* Compatibility and other generic error codes */
+#define ML_ERROR_INVALID_PARAMETER       (2)
+#define ML_ERROR_FEATURE_NOT_ENABLED     (3)
+#define ML_ERROR_FEATURE_NOT_IMPLEMENTED (4)
+#define ML_ERROR_DMP_NOT_STARTED         (6)
+#define ML_ERROR_DMP_STARTED             (7)
+#define ML_ERROR_NOT_OPENED              (8)
+#define ML_ERROR_OPENED                  (9)
+#define ML_ERROR_INVALID_MODULE         (10)
+#define ML_ERROR_MEMORY_EXAUSTED        (11)
+#define ML_ERROR_DIVIDE_BY_ZERO         (12)
+#define ML_ERROR_ASSERTION_FAILURE      (13)
+#define ML_ERROR_FILE_OPEN              (14)
+#define ML_ERROR_FILE_READ              (15)
+#define ML_ERROR_FILE_WRITE             (16)
+
+/* Serial Communication */
+#define ML_ERROR_SERIAL_CLOSED          (20)
+#define ML_ERROR_SERIAL_OPEN_ERROR      (21)
+#define ML_ERROR_SERIAL_READ            (22)
+#define ML_ERROR_SERIAL_WRITE           (23)
+#define ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED  (24)
+
+/* SM = State Machine */
+#define ML_ERROR_SM_TRANSITION          (25)
+#define ML_ERROR_SM_IMPROPER_STATE      (26)
+
+/* Fifo */
+#define ML_ERROR_FIFO_OVERFLOW          (30)
+#define ML_ERROR_FIFO_FOOTER            (31)
+#define ML_ERROR_FIFO_READ_COUNT        (32)
+#define ML_ERROR_FIFO_READ_DATA         (33)
+
+/* Memory & Registers, Set & Get */
+#define ML_ERROR_MEMORY_SET             (40)
+
+#define ML_ERROR_LOG_MEMORY_ERROR       (50)
+#define ML_ERROR_LOG_OUTPUT_ERROR       (51)
+
+/*OS interface errors */
+#define ML_ERROR_OS_BAD_PTR             (60)
+#define ML_ERROR_OS_BAD_HANDLE          (61)
+#define ML_ERROR_OS_CREATE_FAILED       (62)
+#define ML_ERROR_OS_LOCK_FAILED         (63)
+
+/* Compass errors */
+#define ML_ERROR_COMPASS_DATA_OVERFLOW  (70)
+#define ML_ERROR_COMPASS_DATA_UNDERFLOW (71)
+#define ML_ERROR_COMPASS_DATA_NOT_READY (72)
+
+/*---------------------------
+    p-Types
+---------------------------*/
+
+#endif                         /* MLTYPES_H */
diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c
new file mode 100755 (executable)
index 0000000..dde346b
--- /dev/null
@@ -0,0 +1,835 @@
+/*
+    mpu-dev.c - mpu3050 char device interface
+
+    Copyright (C) 1995-97 Simon G. Vogl
+    Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/* Code inside mpudev_ioctl_rdrw is copied from i2c-dev.c
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "mpuirq.h"
+#include "mlsl.h"
+#include "mpu-i2c.h"
+#include "mldl_cfg.h"
+#include "mpu3050.h"
+
+#define MPU3050_EARLY_SUSPEND_IN_DRIVER 0
+#define MPU_NAME "mpu"
+#define MPU_SLAVE_ADDR (0x68)
+
+#define MPU_GET_INTERRUPT_CNT  (2)
+#define MPU_GET_IRQ_TIME       (3)
+#define MPU_GET_LED_VALUE      (4)
+#define MPU_SET_TIMEOUT        (5)
+
+/* Platform data for the MPU */
+struct mpu_private_data {
+       struct mldl_cfg mldl_cfg;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       struct early_suspend early_suspend;
+#endif
+};
+
+static int pid;
+
+static struct i2c_client *this_client;
+
+static int mpu_open(struct inode *inode, struct file *file)
+{
+       printk("mpu_open\n");
+       printk("current->pid %d\n", current->pid);
+       pid = current->pid;
+       file->private_data = this_client;
+       /* we could do some checking on the flags supplied by "open"
+       // i.e. O_NONBLOCK
+       // -> set some flag to disable interruptible_sleep_on in mpu_read */
+       return 0;
+}
+
+/* close function - called when the "file" /dev/mpu is closed in userspace */
+static int mpu_release(struct inode *inode, struct file *file)
+{
+       struct i2c_client *client = (struct i2c_client *)file->private_data;
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       int result = 0;
+
+       pid = 0;
+
+       if (!mldl_cfg->is_suspended) {
+               struct i2c_adapter *accel_adapter;
+               struct i2c_adapter *compass_adapter;
+               accel_adapter =
+                   i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+               compass_adapter =
+                   i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+               result =
+                   mpu3050_suspend(mldl_cfg, client->adapter, accel_adapter,
+                                   compass_adapter, TRUE, TRUE);
+       }
+
+       printk("mpu_release\n");
+       return result;
+}
+
+static noinline int mpudev_ioctl_rdrw(struct i2c_client *client,
+                                     unsigned long arg)
+{
+       struct i2c_rdwr_ioctl_data rdwr_arg;
+       struct i2c_msg *rdwr_pa;
+       u8 __user **data_ptrs;
+       int i, res;
+
+       if (copy_from_user(&rdwr_arg,
+                          (struct i2c_rdwr_ioctl_data __user *)arg,
+                          sizeof(rdwr_arg)))
+               return -EFAULT;
+
+       /* Put an arbitrary limit on the number of messages that can
+        * be sent at once */
+       if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+               return -EINVAL;
+
+       rdwr_pa = (struct i2c_msg *)
+           kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
+       if (!rdwr_pa)
+               return -ENOMEM;
+
+       if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
+                          rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
+               kfree(rdwr_pa);
+               return -EFAULT;
+       }
+
+       data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
+       if (data_ptrs == NULL) {
+               kfree(rdwr_pa);
+               return -ENOMEM;
+       }
+
+       res = 0;
+       for (i = 0; i < rdwr_arg.nmsgs; i++) {
+               /* Limit the size of the message to a sane amount;
+                * and don't let length change either. */
+               if ((rdwr_pa[i].len > 8192) ||
+                   (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
+                       res = -EINVAL;
+                       break;
+               }
+               data_ptrs[i] = (u8 __user *) rdwr_pa[i].buf;
+               rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
+               if (rdwr_pa[i].buf == NULL) {
+                       res = -ENOMEM;
+                       break;
+               }
+               if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
+                                  rdwr_pa[i].len)) {
+                       ++i;    /* Needs to be kfreed too */
+                       res = -EFAULT;
+                       break;
+               }
+       }
+       if (res < 0) {
+               int j;
+               for (j = 0; j < i; ++j)
+                       kfree(rdwr_pa[j].buf);
+               kfree(data_ptrs);
+               kfree(rdwr_pa);
+               return res;
+       }
+
+       res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+       while (i-- > 0) {
+               if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
+                       if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
+                                        rdwr_pa[i].len))
+                               res = -EFAULT;
+               }
+               kfree(rdwr_pa[i].buf);
+       }
+       kfree(data_ptrs);
+       kfree(rdwr_pa);
+       return res;
+}
+
+/* read function called when from /dev/mpu is read.  Read from the FIFO */
+static ssize_t mpu_read(struct file *file,
+                       char __user *buf, size_t count, loff_t *offset)
+{
+       char *tmp;
+       int ret;
+
+       struct i2c_client *client = (struct i2c_client *)file->private_data;
+
+       if (count > 8192)
+               count = 8192;
+
+       tmp = kmalloc(count, GFP_KERNEL);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
+                iminor(file->f_path.dentry->d_inode), count);
+
+/* @todo fix this to do a i2c trasnfer from the FIFO */
+       ret = i2c_master_recv(client, tmp, count);
+       if (ret >= 0)
+               ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
+       kfree(tmp);
+       return ret;
+}
+
+static int mpu_ioctl_get_mpu_pdata(struct i2c_client *client, unsigned long arg)
+{
+       int result;
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       int accel_adapt_num = mldl_cfg->pdata->accel.adapt_num;
+       int compass_adapt_num = mldl_cfg->pdata->compass.adapt_num;
+       int accel_bus = mldl_cfg->pdata->accel.bus;
+       int compass_bus = mldl_cfg->pdata->compass.bus;
+
+       result = copy_from_user(mldl_cfg->pdata,
+                               (unsigned char *)arg,
+                               sizeof(struct mpu3050_platform_data));
+       /* Don't allow userspace to change the adapter number or bus */
+       mldl_cfg->pdata->accel.adapt_num = accel_adapt_num;
+       mldl_cfg->pdata->compass.adapt_num = compass_adapt_num;
+       mldl_cfg->pdata->accel.bus = accel_bus;
+       mldl_cfg->pdata->compass.bus = compass_bus;
+
+       return result;
+}
+
+static int
+mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg)
+{
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+
+       printk("%s\n", __func__);
+       /*
+        * User space is not allowed to modify accel compass or pdata structs,
+        * as well as silicon_revision product_id or trim
+        */
+       if (copy_from_user(mldl_cfg,
+                          (struct mldl_cfg *)arg,
+                          offsetof(struct mldl_cfg, silicon_revision)))
+                return -EFAULT;
+
+       return 0;
+}
+
+static int
+mpu_ioctl_get_mpu_config(struct i2c_client *client, unsigned long arg)
+{
+       /* Have to be careful as there are 3 pointers in the mldl_cfg
+        * structure */
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct mldl_cfg *local_mldl_cfg;
+       int retval = 0;
+
+       local_mldl_cfg = kmalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
+       if (NULL == local_mldl_cfg)
+               return -ENOMEM;
+
+       retval =
+           copy_from_user(local_mldl_cfg, (void *)arg,
+                          sizeof(struct mldl_cfg));
+       if (retval)
+               goto out;
+
+       /* Fill in the accel, compass and pdata pointers */
+       if (mldl_cfg->accel) {
+               retval = copy_to_user(local_mldl_cfg->accel,
+                                     mldl_cfg->accel,
+                                     sizeof(*mldl_cfg->accel));
+               if (retval)
+                       goto out;
+       }
+
+       if (mldl_cfg->compass) {
+               retval = copy_to_user(local_mldl_cfg->compass,
+                                     mldl_cfg->compass,
+                                     sizeof(*mldl_cfg->compass));
+               if (retval)
+                       goto out;
+       }
+
+       if (mldl_cfg->pdata) {
+               retval = copy_to_user(local_mldl_cfg->pdata,
+                                     mldl_cfg->pdata,
+                                     sizeof(*mldl_cfg->pdata));
+               if (retval)
+                       goto out;
+       }
+
+       /* Do not modify the accel, compass and pdata pointers */
+       retval = copy_to_user((struct mldl_cfg *)arg,
+                             mldl_cfg, offsetof(struct mldl_cfg, accel));
+
+ out:
+       kfree(local_mldl_cfg);
+       return retval;
+}
+
+/* ioctl - I/O control */
+static long mpu_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct i2c_client *client = (struct i2c_client *)file->private_data;
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       int retval = 0;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+
+       switch (cmd) {
+       case I2C_RDWR:
+               mpudev_ioctl_rdrw(client, arg);
+               break;
+       case I2C_SLAVE:
+               if ((arg & 0x7E) != (client->addr & 0x7E)) {
+                       printk("%s: Invalid I2C_SLAVE arg %lu \n",
+                              __func__, arg);
+               }
+               break;
+       case MPU_SET_MPU_CONFIG:
+               retval = mpu_ioctl_set_mpu_config(client, arg);
+               break;
+       case MPU_SET_INT_CONFIG:
+               mldl_cfg->int_config = (unsigned char)arg;
+               break;
+       case MPU_SET_EXT_SYNC:
+               mldl_cfg->ext_sync = (enum mpu_ext_sync)arg;
+               break;
+       case MPU_SET_FULL_SCALE:
+               mldl_cfg->full_scale = (enum mpu_fullscale)arg;
+               break;
+       case MPU_SET_LPF:
+               mldl_cfg->lpf = (enum mpu_filter)arg;
+               break;
+       case MPU_SET_CLK_SRC:
+               mldl_cfg->clk_src = (enum mpu_clock_sel)arg;
+               break;
+       case MPU_SET_DIVIDER:
+               mldl_cfg->divider = (unsigned char)arg;
+               break;
+       case MPU_SET_LEVEL_SHIFTER:
+               mldl_cfg->pdata->level_shifter = (unsigned char)arg;
+               break;
+       case MPU_SET_DMP_ENABLE:
+               mldl_cfg->dmp_enable = (unsigned char)arg;
+               break;
+       case MPU_SET_FIFO_ENABLE:
+               mldl_cfg->fifo_enable = (unsigned char)arg;
+               break;
+       case MPU_SET_DMP_CFG1:
+               mldl_cfg->dmp_cfg1 = (unsigned char)arg;
+               break;
+       case MPU_SET_DMP_CFG2:
+               mldl_cfg->dmp_cfg2 = (unsigned char)arg;
+               break;
+       case MPU_SET_OFFSET_TC:
+               retval = copy_from_user(mldl_cfg->offset_tc,
+                                       (unsigned char *)arg,
+                                       sizeof(mldl_cfg->offset_tc));
+               break;
+       case MPU_SET_RAM:
+               retval = copy_from_user(mldl_cfg->ram,
+                                       (unsigned char *)arg,
+                                       sizeof(mldl_cfg->ram));
+               break;
+       case MPU_SET_PLATFORM_DATA:
+               retval = mpu_ioctl_get_mpu_pdata(client, arg);
+               break;
+       case MPU_GET_MPU_CONFIG:
+               retval = mpu_ioctl_get_mpu_config(client, arg);
+               break;
+       case MPU_GET_INT_CONFIG:
+               mldl_cfg->int_config = (unsigned char)arg;
+               break;
+       case MPU_GET_EXT_SYNC:
+               mldl_cfg->ext_sync = (enum mpu_ext_sync)arg;
+               break;
+       case MPU_GET_FULL_SCALE:
+               mldl_cfg->full_scale = (enum mpu_fullscale)arg;
+               break;
+       case MPU_GET_LPF:
+               mldl_cfg->lpf = (enum mpu_filter)arg;
+               break;
+       case MPU_GET_CLK_SRC:
+               mldl_cfg->clk_src = (enum mpu_clock_sel)arg;
+               break;
+       case MPU_GET_DIVIDER:
+               mldl_cfg->divider = (unsigned char)arg;
+               break;
+       case MPU_GET_LEVEL_SHIFTER:
+               mldl_cfg->pdata->level_shifter = (unsigned char)arg;
+               break;
+       case MPU_GET_DMP_ENABLE:
+               mldl_cfg->dmp_enable = (unsigned char)arg;
+               break;
+       case MPU_GET_FIFO_ENABLE:
+               mldl_cfg->fifo_enable = (unsigned char)arg;
+               break;
+       case MPU_GET_DMP_CFG1:
+               mldl_cfg->dmp_cfg1 = (unsigned char)arg;
+               break;
+       case MPU_GET_DMP_CFG2:
+               mldl_cfg->dmp_cfg2 = (unsigned char)arg;
+               break;
+       case MPU_GET_OFFSET_TC:
+               retval = copy_to_user((unsigned char *)arg,
+                                     mldl_cfg->offset_tc,
+                                     sizeof(mldl_cfg->offset_tc));
+               break;
+       case MPU_GET_RAM:
+               retval = copy_to_user((unsigned char *)arg,
+                                     mldl_cfg->ram, sizeof(mldl_cfg->ram));
+               break;
+       case MPU_READ_MEMORY:
+       case MPU_WRITE_MEMORY:
+       case MPU_SUSPEND:
+               {
+                       struct mpu_suspend_resume suspend;
+                       retval =
+                           copy_from_user(&suspend,
+                                          (struct mpu_suspend_resume *)
+                                          arg, sizeof(suspend));
+                       if (retval)
+                               break;
+                       if (suspend.gyro) {
+                               retval =
+                                   mpu3050_suspend(mldl_cfg,
+                                                   client->adapter,
+                                                   accel_adapter,
+                                                   compass_adapter,
+                                                   suspend.accel,
+                                                   suspend.compass);
+                       } else {
+                               /* Cannot suspend the compass or accel while
+                                * the MPU is running */
+                               retval = ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+                       }
+               }
+               break;
+       case MPU_RESUME:
+               {
+                       struct mpu_suspend_resume resume;
+                       retval =
+                           copy_from_user(&resume,
+                                          (struct mpu_suspend_resume *)
+                                          arg, sizeof(resume));
+                       if (retval)
+                               break;
+                       if (resume.gyro) {
+                               retval =
+                                   mpu3050_resume(mldl_cfg,
+                                                  client->adapter,
+                                                  accel_adapter,
+                                                  compass_adapter,
+                                                  resume.accel,
+                                                  resume.compass);
+                       } else if (mldl_cfg->is_suspended) {
+                               if (resume.accel) {
+                                       retval =
+                                           mldl_cfg->accel->
+                                           resume(accel_adapter,
+                                                  mldl_cfg->accel,
+                                                  &mldl_cfg->pdata->accel);
+                                       if (retval)
+                                               break;
+                               }
+
+                               if (resume.compass)
+                                       retval =
+                                           mldl_cfg->compass->
+                                           resume(compass_adapter,
+                                                  mldl_cfg->compass,
+                                                  &mldl_cfg->pdata->compass);
+                       } else {
+                               /* Cannot resume the compass or accel while
+                                * the MPU is running */
+                               retval = ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+                       }
+               }
+               break;
+       case MPU_READ_ACCEL:
+               {
+                       unsigned char data[6];
+                       retval =
+                           mpu3050_read_accel(mldl_cfg, client->adapter, data);
+                       if (ML_SUCCESS == retval)
+                               retval =
+                                   copy_to_user((unsigned char *)arg,
+                                                data, sizeof(data));
+               }
+               break;
+       case MPU_READ_COMPASS:
+               {
+                       unsigned char data[6];
+                       struct i2c_adapter *compass_adapt =
+                           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+                       retval =
+                           mpu3050_read_compass(mldl_cfg, compass_adapt, data);
+                       if (ML_SUCCESS == retval)
+                               retval =
+                                   copy_to_user((unsigned char *)arg,
+                                                data, sizeof(data));
+               }
+               break;
+       default:
+               printk("%s: Unknown cmd %d, arg %lu \n", __func__, cmd, arg);
+               retval = -EINVAL;
+       }
+
+       return retval;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void mpu3050_early_suspend(struct early_suspend *h)
+{
+       struct mpu_private_data *mpu = container_of(h,
+                                                   struct
+                                                   mpu_private_data,
+                                                   early_suspend);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+
+       printk("%s: %d, %d\n", __func__, h->level, mpu->mldl_cfg.is_suspended);
+       if (MPU3050_EARLY_SUSPEND_IN_DRIVER)
+               (void)mpu3050_suspend(mldl_cfg,
+                                     accel_adapter, compass_adapter,
+                                     this_client->adapter, TRUE, TRUE);
+}
+
+void mpu3050_early_resume(struct early_suspend *h)
+{
+       struct mpu_private_data *mpu = container_of(h,
+                                                   struct
+                                                   mpu_private_data,
+                                                   early_suspend);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+
+       if (MPU3050_EARLY_SUSPEND_IN_DRIVER) {
+               if (pid) {
+                       (void)mpu3050_resume(mldl_cfg,
+                                            accel_adapter, compass_adapter,
+                                            this_client->adapter, TRUE, TRUE);
+                       printk("%s for pid %d\n", __func__, pid);
+               }
+       }
+       printk("%s: %d\n", __func__, h->level);
+}
+#endif
+
+void mpu_shutdown(struct i2c_client *client)
+{
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+
+       (void)mpu3050_suspend(mldl_cfg, this_client->adapter,
+                             accel_adapter, compass_adapter, TRUE, TRUE);
+       printk("%s\n", __func__);
+}
+
+int mpu_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+
+       if (!mpu->mldl_cfg.is_suspended) {
+               printk("%s: suspending on event %d\n", __func__, mesg.event);
+               (void)mpu3050_suspend(mldl_cfg, this_client->adapter,
+                                     accel_adapter, compass_adapter,
+                                     TRUE, TRUE);
+       } else {
+               printk("%s: Already suspended %d\n", __func__, mesg.event);
+       }
+       return 0;
+}
+
+int mpu_resume(struct i2c_client *client)
+{
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *)i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+
+       if (pid) {
+               (void)mpu3050_resume(mldl_cfg, this_client->adapter,
+                                    accel_adapter, compass_adapter,
+                                    TRUE, TRUE);
+               printk("%s for pid %d\n", __func__, pid);
+       }
+       return 0;
+}
+
+/* define which file operations are supported */
+struct file_operations mpu_fops = {
+       .owner = THIS_MODULE,
+       .read = mpu_read,
+#if HAVE_COMPAT_IOCTL
+       .compat_ioctl = mpu_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+       .unlocked_ioctl = mpu_ioctl,
+#endif
+       .open = mpu_open,
+       .release = mpu_release,
+};
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
+I2C_CLIENT_INSMOD;
+#endif
+
+static struct miscdevice i2c_mpu_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = MPU_NAME,
+       .fops = &mpu_fops,
+};
+
+int mpu3050_probe(struct i2c_client *client, const struct i2c_device_id *devid)
+{
+       struct mpu3050_platform_data *pdata;
+       struct mpu_private_data *mpu;
+       int res = 0;
+       printk("%s\n", __func__);
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               res = -ENODEV;
+               goto out_check_functionality_failed;
+       }
+
+       mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL);
+       if (!mpu) {
+               res = -ENOMEM;
+               goto out_alloc_data_failed;
+       }
+
+       i2c_set_clientdata(client, mpu);
+       this_client = client;
+
+       pdata = (struct mpu3050_platform_data *)client->dev.platform_data;
+       if (!pdata) {
+               printk("Warning no platform data for mpu3050\n");
+       } else {
+               mpu->mldl_cfg.pdata = pdata;
+
+#ifdef CONFIG_SENSORS_MPU3050_MODULE
+               pdata->accel.get_slave_descr = get_accel_slave_descr;
+               pdata->compass.get_slave_descr = get_compass_slave_descr;
+#endif
+
+               if (pdata->accel.get_slave_descr) {
+                       mpu->mldl_cfg.accel = pdata->accel.get_slave_descr();
+                       printk("MPU3050: +%s\n", mpu->mldl_cfg.accel->name);
+               } else {
+                       printk("MPU3050: No Accel Present\n");
+               }
+
+               if (pdata->compass.get_slave_descr) {
+                       mpu->mldl_cfg.compass =
+                           pdata->compass.get_slave_descr();
+                       printk("MPU3050: +%s\n", mpu->mldl_cfg.compass->name);
+               } else {
+                       printk("MPU3050: No Compass Present\n");
+               }
+       }
+
+       mpu->mldl_cfg.addr = client->addr;
+       res = mpu3050_open(&mpu->mldl_cfg, (tMLSLHandle) client->adapter);
+
+       if (res) {
+               printk("Unable to open MPU3050 %d\n", res);
+               res = -ENODEV;
+               goto out_whoami_failed;
+       }
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       mpu->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+       mpu->early_suspend.suspend = mpu3050_early_suspend;
+       mpu->early_suspend.resume = mpu3050_early_resume;
+       register_early_suspend(&mpu->early_suspend);
+#endif
+
+       res = misc_register(&i2c_mpu_device);
+       if (res < 0) {
+               printk("ERROR: misc_register returned %d\n", res);
+               goto out_misc_register_failed;
+       }
+
+       if (this_client->irq > 0) {
+               printk("Installing irq using %d\n", this_client->irq);
+               res = mpuirq_init(this_client);
+               if (res) {
+                       goto out_mpuirq_failed;
+               }
+       } else {
+               printk("WARNING: mpu3050 irq not assigned\n");
+       }
+
+       return res;
+
+ out_mpuirq_failed:
+       misc_deregister(&i2c_mpu_device);
+ out_misc_register_failed:
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       unregister_early_suspend(&mpu->early_suspend);
+#endif
+ out_whoami_failed:
+       kfree(mpu);
+ out_alloc_data_failed:
+ out_check_functionality_failed:
+       printk(KERN_ERR "%s failed %d\n", __func__, res);
+       return res;
+
+}
+
+static int mpu3050_remove(struct i2c_client *client)
+{
+       struct mpu_private_data *mpu = i2c_get_clientdata(client);
+       printk("%s\n", __func__);
+
+       if (client->irq) {
+               mpuirq_exit();
+       }
+
+       misc_deregister(&i2c_mpu_device);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       unregister_early_suspend(&mpu->early_suspend);
+#endif
+       kfree(mpu);
+
+       return 0;
+}
+
+static const struct i2c_device_id mpu3050_id[] = {
+       {"mpu3050", 0},
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mpu3050_id);
+
+static struct i2c_driver mpu3050_driver = {
+       .class = I2C_CLASS_HWMON,
+       .probe = mpu3050_probe,
+       .remove = mpu3050_remove,
+       .id_table = mpu3050_id,
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = "mpu3050",
+                  },
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
+       .address_data = &addr_data,
+#else
+       .address_list = normal_i2c,
+#endif
+
+       .shutdown = mpu_shutdown,       /* optional */
+       .suspend = mpu_suspend, /* optional */
+       .resume = mpu_resume,   /* optional */
+
+};
+
+static int __init mpu_init(void)
+{
+       int res = i2c_add_driver(&mpu3050_driver);
+       printk("%s\n", __func__);
+       if (res) {
+               printk("%s failed\n", __func__);
+       }
+       return res;
+}
+
+static void __exit mpu_exit(void)
+{
+       printk("%s\n", __func__);
+       i2c_del_driver(&mpu3050_driver);
+}
+
+module_init(mpu_init);
+module_exit(mpu_exit);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("User space character device interface for MPU3050");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("mpu3050");
diff --git a/drivers/misc/mpu3050/mpu-i2c.c b/drivers/misc/mpu3050/mpu-i2c.c
new file mode 100755 (executable)
index 0000000..ca21b42
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/***************************************************************************** *
+ * $Id: mpu-i2c.c 3863 2010-10-08 22:05:31Z nroyer $
+ ******************************************************************************/
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ * @file     mpu-i2c.c
+ * @brief
+ *
+ *
+ */
+
+#include <linux/i2c.h>
+
+int sensor_i2c_write(struct i2c_adapter *i2c_adap,
+                    unsigned char address,
+                    unsigned int len, unsigned char *data)
+{
+       struct i2c_msg msgs[1];
+       int res;
+
+       if (NULL == data || NULL == i2c_adap)
+               return -EINVAL;
+
+       msgs[0].addr = address;
+       msgs[0].flags = 0;      /* write */
+       msgs[0].buf = (unsigned char *)data;
+       msgs[0].len = len;
+
+       res = i2c_transfer(i2c_adap, msgs, 1);
+       if (res < 1) {
+               return res;
+       } else {
+               return 0;
+       }
+}
+
+int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
+                             unsigned char address,
+                             unsigned char reg, unsigned char value)
+{
+       unsigned char data[2];
+
+       data[0] = reg;
+       data[1] = value;
+       return sensor_i2c_write(i2c_adap, address, 2, data);
+}
+
+int sensor_i2c_read(struct i2c_adapter *i2c_adap,
+                   unsigned char address,
+                   unsigned char reg, unsigned int len, unsigned char *data)
+{
+       struct i2c_msg msgs[2];
+       int res;
+
+       if (NULL == data || NULL == i2c_adap)
+               return -EINVAL;
+
+       msgs[0].addr = address;
+       msgs[0].flags = 0;      /* write */
+       msgs[0].buf = &reg;
+       msgs[0].len = 1;
+
+       msgs[1].addr = address;
+       msgs[1].flags = I2C_M_RD;
+       msgs[1].buf = data;
+       msgs[1].len = len;
+
+       res = i2c_transfer(i2c_adap, msgs, 2);
+       if (res < 2) {
+               return res;
+       } else {
+               return 0;
+       }
+}
+
+int mpu_memory_read(struct i2c_adapter *i2c_adap,
+                   unsigned char mpu_addr,
+                   unsigned short mem_addr,
+                   unsigned int len, unsigned char *data)
+{
+       unsigned char bank[2];
+       unsigned char addr[2];
+       unsigned char buf;
+
+       struct i2c_msg msgs[4];
+       int ret;
+
+       if (NULL == data || NULL == i2c_adap)
+               return -EINVAL;
+
+       bank[0] = 0x37;         /*MPUREG_BANK_SEL; */
+       bank[1] = mem_addr >> 8;
+
+       addr[0] = 0x38;         /*MPUREG_MEM_START_ADDR; */
+       addr[1] = mem_addr & 0xFF;
+
+       buf = 0x39;             /* MPUREG_MEM_R_W; */
+
+       /* Write Message */
+       msgs[0].addr = mpu_addr;
+       msgs[0].flags = 0;
+       msgs[0].buf = bank;
+       msgs[0].len = sizeof(bank);
+
+       msgs[1].addr = mpu_addr;
+       msgs[1].flags = 0;
+       msgs[1].buf = addr;
+       msgs[1].len = sizeof(addr);
+
+       msgs[2].addr = mpu_addr;
+       msgs[2].flags = 0;
+       msgs[2].buf = &buf;
+       msgs[2].len = 1;
+
+       msgs[3].addr = mpu_addr;
+       msgs[3].flags = I2C_M_RD;
+       msgs[3].buf = data;
+       msgs[3].len = len;
+
+       ret = i2c_transfer(i2c_adap, msgs, 4);
+       if (ret != 4)
+               return ret;
+       else
+               return 0;
+}
+
+int mpu_memory_write(struct i2c_adapter *i2c_adap,
+                    unsigned char mpu_addr,
+                    unsigned short mem_addr,
+                    unsigned int len, unsigned char *data)
+{
+       unsigned char bank[2];
+       unsigned char addr[2];
+       unsigned char buf[513];
+
+       struct i2c_msg msgs[3];
+       int ret;
+
+       if (NULL == data || NULL == i2c_adap)
+               return -EINVAL;
+       if (len >= (sizeof(buf) - 1))
+               return -ENOMEM;
+
+       bank[0] = 0x37;         /*MPUREG_BANK_SEL; */
+       bank[1] = mem_addr >> 8;
+
+       addr[0] = 0x38;         /*MPUREG_MEM_START_ADDR; */
+       addr[1] = mem_addr & 0xFF;
+
+       buf[0] = 0x39;          /* MPUREG_MEM_R_W; */
+       memcpy(buf + 1, data, len);
+
+       /* Write Message */
+       msgs[0].addr = mpu_addr;
+       msgs[0].flags = 0;
+       msgs[0].buf = bank;
+       msgs[0].len = sizeof(bank);
+
+       msgs[1].addr = mpu_addr;
+       msgs[1].flags = 0;
+       msgs[1].buf = addr;
+       msgs[1].len = sizeof(addr);
+
+       msgs[2].addr = mpu_addr;
+       msgs[2].flags = 0;
+       msgs[2].buf = (unsigned char *)buf;
+       msgs[2].len = len + 1;
+
+       ret = i2c_transfer(i2c_adap, msgs, 3);
+       if (ret != 3)
+               return ret;
+       else
+               return 0;
+}
diff --git a/drivers/misc/mpu3050/mpu-i2c.h b/drivers/misc/mpu3050/mpu-i2c.h
new file mode 100755 (executable)
index 0000000..ac3f7e9
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+/***************************************************************************** *
+ * $Id: mpu-i2c.h 3863 2010-10-08 22:05:31Z nroyer $
+ ******************************************************************************/
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ * @file     mpu-i2c.c
+ * @brief
+ *
+ *
+ */
+
+#ifndef __MPU_I2C_H__
+#define __MPU_I2C_H__
+
+#include <linux/i2c.h>
+
+int sensor_i2c_write(struct i2c_adapter *i2c_adap,
+                    unsigned char address,
+                    unsigned int len, unsigned char const *data);
+
+int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
+                             unsigned char address,
+                             unsigned char reg, unsigned char value);
+
+int sensor_i2c_read(struct i2c_adapter *i2c_adap,
+                   unsigned char address,
+                   unsigned char reg, unsigned int len, unsigned char *data);
+
+int mpu_memory_read(struct i2c_adapter *i2c_adap,
+                   unsigned char mpu_addr,
+                   unsigned short mem_addr,
+                   unsigned int len, unsigned char *data);
+
+int mpu_memory_write(struct i2c_adapter *i2c_adap,
+                    unsigned char mpu_addr,
+                    unsigned short mem_addr,
+                    unsigned int len, unsigned char const *data);
+
+#endif                         /* __MPU_I2C_H__ */
diff --git a/drivers/misc/mpu3050/mpuirq.c b/drivers/misc/mpu3050/mpuirq.c
new file mode 100755 (executable)
index 0000000..bf3c10f
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "mpu3050.h"
+#include "mpuirq.h"
+#include "mldl_cfg.h"
+#include "mpu-i2c.h"
+
+#define MPUIRQ_NAME "mpuirq"
+
+/* function which gets accel data and sends it to MPU */
+
+DECLARE_WAIT_QUEUE_HEAD(mpuirq_wait);
+
+struct mpuirq_dev_data {
+       struct work_struct work;
+       struct i2c_client *mpu_client;
+       struct miscdevice *dev;
+       int irq;
+       int pid;
+       int accel_divider;
+       int data_ready;
+       int timeout;
+};
+
+static struct mpuirq_dev_data mpuirq_dev_data;
+static struct mpuirq_data mpuirq_data;
+static char *interface = MPUIRQ_NAME;
+
+static void mpu_accel_data_work_fcn(struct work_struct *work);
+
+static int mpuirq_open(struct inode *inode, struct file *file)
+{
+       dev_dbg(mpuirq_dev_data.dev->this_device,
+               "%s current->pid %d\n", __func__, current->pid);
+       mpuirq_dev_data.pid = current->pid;
+       file->private_data = &mpuirq_dev_data;
+       /* we could do some checking on the flags supplied by "open"
+       // i.e. O_NONBLOCK
+       // -> set some flag to disable interruptible_sleep_on in mpuirq_read */
+       return 0;
+}
+
+/* close function - called when the "file" /dev/mpuirq is closed in userspace */
+static int mpuirq_release(struct inode *inode, struct file *file)
+{
+       dev_dbg(mpuirq_dev_data.dev->this_device, "mpuirq_release\n");
+       return 0;
+}
+
+/* read function called when from /dev/mpuirq is read */
+static ssize_t mpuirq_read(struct file *file,
+                          char *buf, size_t count, loff_t * ppos)
+{
+       int len, err;
+       struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data;
+
+       if (!mpuirq_dev_data.data_ready) {
+               wait_event_interruptible_timeout(mpuirq_wait,
+                                                mpuirq_dev_data.data_ready,
+                                                mpuirq_dev_data.timeout);
+       }
+
+       if (mpuirq_dev_data.data_ready && NULL != buf
+           && count >= sizeof(mpuirq_data)) {
+               err = copy_to_user(buf, &mpuirq_data, sizeof(mpuirq_data));
+       } else {
+               return 0;
+       }
+       if (err != 0) {
+               dev_err(p_mpuirq_dev_data->dev->this_device,
+                       "Copy to user returned %d\n", err);
+               return -EFAULT;
+       }
+       mpuirq_dev_data.data_ready = 0;
+       len = sizeof(mpuirq_data);
+       return len;
+}
+
+unsigned int mpuirq_poll(struct file *file, struct poll_table_struct *poll)
+{
+       int mask = 0;
+       struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data;
+
+       poll_wait(file, &mpuirq_wait, poll);
+       if (mpuirq_dev_data.data_ready)
+               mask |= POLLIN | POLLRDNORM;
+       dev_dbg(p_mpuirq_dev_data->dev->this_device,
+               "%s: returning %d\n", __func__, mask);
+       return mask;
+}
+
+/* ioctl - I/O control */
+static long mpuirq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int retval = 0;
+       int data;
+
+       switch (cmd) {
+       case MPUIRQ_SET_TIMEOUT:
+               mpuirq_dev_data.timeout = arg;
+               break;
+
+       case MPUIRQ_GET_INTERRUPT_CNT:
+               data = mpuirq_data.interruptcount - 1;
+               if (mpuirq_data.interruptcount > 1) {
+                       mpuirq_data.interruptcount = 1;
+               }
+               if (copy_to_user((int *)arg, &data, sizeof(int)))
+                       return -EFAULT;
+               break;
+       case MPUIRQ_GET_IRQ_TIME:
+               if (copy_to_user((int *)arg, &mpuirq_data.irqtime,
+                                sizeof(mpuirq_data.irqtime)))
+                       return -EFAULT;
+               mpuirq_data.irqtime = 0;
+               break;
+       case MPUIRQ_SET_FREQUENCY_DIVIDER:
+               mpuirq_dev_data.accel_divider = arg;
+               break;
+       default:
+               retval = -EINVAL;
+       }
+       return retval;
+}
+
+static void mpu_accel_data_work_fcn(struct work_struct *work)
+{
+       struct mpuirq_dev_data *mpuirq_dev_data =
+           (struct mpuirq_dev_data *)work;
+       struct mldl_cfg *mldl_cfg =
+           (struct mldl_cfg *)i2c_get_clientdata(mpuirq_dev_data->mpu_client);
+       struct i2c_adapter *accel_adapter;
+       unsigned char wbuff[16];
+       unsigned char rbuff[16];
+       int ii;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       mldl_cfg->accel->read((mlsl_handle_t) accel_adapter,
+                             mldl_cfg->accel, &mldl_cfg->pdata->accel, rbuff);
+
+       /* @todo add other data formats here as well */
+       if (EXT_SLAVE_BIG_ENDIAN == mldl_cfg->accel->endian) {
+               for (ii = 0; ii < 3; ii++) {
+                       wbuff[2 * ii + 1] = rbuff[2 * ii + 1];
+                       wbuff[2 * ii + 2] = rbuff[2 * ii + 0];
+               }
+       } else {
+               memcpy(wbuff + 1, rbuff, mldl_cfg->accel->len);
+       }
+
+       wbuff[7] = 0;
+       wbuff[8] = 1;           /*set semaphore */
+
+       mpu_memory_write(mpuirq_dev_data->mpu_client->adapter,
+                        mldl_cfg->addr, 0x0108, 8, wbuff);
+}
+
+static irqreturn_t mpuirq_handler(int irq, void *dev_id)
+{
+       static int mycount;
+       struct timeval irqtime;
+       mycount++;
+
+       mpuirq_data.interruptcount++;
+
+       /* wake up (unblock) for reading data from userspace
+       // and ignore first interrupt generated in module init */
+       if (mpuirq_data.interruptcount > 1) {
+               mpuirq_dev_data.data_ready = 1;
+
+               do_gettimeofday(&irqtime);
+               mpuirq_data.irqtime = (((long long)irqtime.tv_sec) << 32);
+               mpuirq_data.irqtime += irqtime.tv_usec;
+
+               if ((mpuirq_dev_data.accel_divider >= 0) &&
+                   (0 == (mycount % (mpuirq_dev_data.accel_divider + 1)))) {
+                       schedule_work((struct work_struct *)(&mpuirq_dev_data));
+               }
+
+               wake_up_interruptible(&mpuirq_wait);
+       }
+
+       return IRQ_HANDLED;
+
+}
+
+/* define which file operations are supported */
+struct file_operations mpuirq_fops = {
+       .owner = THIS_MODULE,
+       .read = mpuirq_read,
+       .poll = mpuirq_poll,
+
+#if HAVE_COMPAT_IOCTL
+       .compat_ioctl = mpuirq_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+       .unlocked_ioctl = mpuirq_ioctl,
+#endif
+       .open = mpuirq_open,
+       .release = mpuirq_release,
+};
+
+static struct miscdevice mpuirq_device = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = MPUIRQ_NAME,
+       .fops = &mpuirq_fops,
+};
+
+int mpuirq_init(struct i2c_client *mpu_client)
+{
+
+       int res;
+       struct mldl_cfg *mldl_cfg =
+           (struct mldl_cfg *)i2c_get_clientdata(mpu_client);
+
+       /* work_struct initialization */
+       INIT_WORK((struct work_struct *)&mpuirq_dev_data,
+                 mpu_accel_data_work_fcn);
+       mpuirq_dev_data.mpu_client = mpu_client;
+
+       dev_info(&mpu_client->adapter->dev,
+                "Module Param interface = %s\n", interface);
+
+       mpuirq_dev_data.irq = mpu_client->irq;
+       mpuirq_dev_data.pid = 0;
+       mpuirq_dev_data.accel_divider = -1;
+       mpuirq_dev_data.data_ready = 0;
+       mpuirq_dev_data.timeout = 0;
+       mpuirq_dev_data.dev = &mpuirq_device;
+
+       if (mpuirq_dev_data.irq) {
+               unsigned long flags;
+               if (BIT_ACTL_LOW == ((mldl_cfg->pdata->int_config) & BIT_ACTL))
+                       flags = IRQF_TRIGGER_FALLING;
+               else
+                       flags = IRQF_TRIGGER_RISING;
+
+               res =
+                   request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags,
+                               interface, &mpuirq_dev_data.irq);
+               if (res) {
+                       dev_err(&mpu_client->adapter->dev,
+                               "myirqtest: cannot register IRQ %d\n",
+                               mpuirq_dev_data.irq);
+               } else {
+                       res = misc_register(&mpuirq_device);
+                       if (res < 0) {
+                               dev_err(&mpu_client->adapter->dev,
+                                       "misc_register returned %d\n", res);
+                               free_irq(mpuirq_dev_data.irq,
+                                        &mpuirq_dev_data.irq);
+                       }
+               }
+
+       } else {
+               res = 0;
+       }
+
+       return res;
+}
+
+void mpuirq_exit(void)
+{
+       /* Free the IRQ first before flushing the work */
+       if (mpuirq_dev_data.irq > 0) {
+               free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq);
+       }
+       flush_scheduled_work();
+
+       dev_info(mpuirq_device.this_device, "Unregistering %s\n", MPUIRQ_NAME);
+       misc_deregister(&mpuirq_device);
+
+       return;
+}
+
+module_param(interface, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(interface, "The Interface name");
diff --git a/drivers/misc/mpu3050/mpuirq.h b/drivers/misc/mpu3050/mpuirq.h
new file mode 100755 (executable)
index 0000000..69b7eaa
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  $
+ */
+
+#ifndef __MPUIRQ__
+#define __MPUIRQ__
+
+#ifdef __KERNEL__
+#include <linux/i2c-dev.h>
+#endif
+
+#define MPUIRQ_ENABLE_DEBUG          (1)
+#define MPUIRQ_GET_INTERRUPT_CNT     (2)
+#define MPUIRQ_GET_IRQ_TIME          (3)
+#define MPUIRQ_GET_LED_VALUE         (4)
+#define MPUIRQ_SET_TIMEOUT           (5)
+#define MPUIRQ_SET_ACCEL_INFO        (6)
+#define MPUIRQ_SET_FREQUENCY_DIVIDER (7)
+
+struct mpuirq_data {
+       int interruptcount;
+       unsigned long long irqtime;
+       int data_type;
+       int data_size;
+       void *data;
+};
+
+#ifdef __KERNEL__
+
+void mpuirq_exit(void);
+int mpuirq_init(struct i2c_client *mpu_client);
+
+#endif
+
+#endif
diff --git a/include/linux/mpu3050.h b/include/linux/mpu3050.h
new file mode 100755 (executable)
index 0000000..9c8ddc2
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+       $License:
+       Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program.  If not, see <http://www.gnu.org/licenses/>.
+       $
+ */
+/******************************************************************************
+ *
+ *  $Id: mpu3050.h 3868 2010-10-09 01:22:37Z dsrivastava $
+ *
+ ******************************************************************************/
+
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ *      @file     mpu3050.h
+ *      @brief
+**/
+
+#ifndef __MPU3050_H_
+#define __MPU3050_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif
+
+typedef void *mlsl_handle_t;
+
+#define DEFAULT_MPU_SLAVEADDR       0x68
+
+/*==== MPU REGISTER SET ====*/
+enum mpu_register {
+       MPUREG_WHO_AM_I = 0,    /* 00 0x00 */
+       MPUREG_PRODUCT_ID,      /* 01 0x01 */
+       MPUREG_02_RSVD,         /* 02 0x02 */
+       MPUREG_03_RSVD,         /* 03 0x03 */
+       MPUREG_04_RSVD,         /* 04 0x04 */
+       MPUREG_XG_OFFS_TC,      /* 05 0x05 */
+       MPUREG_06_RSVD,         /* 06 0x06 */
+       MPUREG_07_RSVD,         /* 07 0x07 */
+       MPUREG_YG_OFFS_TC,      /* 08 0x08 */
+       MPUREG_09_RSVD,         /* 09 0x09 */
+       MPUREG_0A_RSVD,         /* 10 0x0a */
+       MPUREG_ZG_OFFS_TC,      /* 11 0x0b */
+       MPUREG_X_OFFS_USRH,     /* 12 0x0c */
+       MPUREG_X_OFFS_USRL,     /* 13 0x0d */
+       MPUREG_Y_OFFS_USRH,     /* 14 0x0e */
+       MPUREG_Y_OFFS_USRL,     /* 15 0x0f */
+       MPUREG_Z_OFFS_USRH,     /* 16 0x10 */
+       MPUREG_Z_OFFS_USRL,     /* 17 0x11 */
+       MPUREG_FIFO_EN1,        /* 18 0x12 */
+       MPUREG_FIFO_EN2,        /* 19 0x13 */
+       MPUREG_AUX_SLV_ADDR,    /* 20 0x14 */
+       MPUREG_SMPLRT_DIV,      /* 21 0x15 */
+       MPUREG_DLPF_FS_SYNC,    /* 22 0x16 */
+       MPUREG_INT_CFG,         /* 23 0x17 */
+       MPUREG_ACCEL_BURST_ADDR,        /* 24 0x18 */
+       MPUREG_19_RSVD,         /* 25 0x19 */
+       MPUREG_INT_STATUS,      /* 26 0x1a */
+       MPUREG_TEMP_OUT_H,      /* 27 0x1b */
+       MPUREG_TEMP_OUT_L,      /* 28 0x1c */
+       MPUREG_GYRO_XOUT_H,     /* 29 0x1d */
+       MPUREG_GYRO_XOUT_L,     /* 30 0x1e */
+       MPUREG_GYRO_YOUT_H,     /* 31 0x1f */
+       MPUREG_GYRO_YOUT_L,     /* 32 0x20 */
+       MPUREG_GYRO_ZOUT_H,     /* 33 0x21 */
+       MPUREG_GYRO_ZOUT_L,     /* 34 0x22 */
+       MPUREG_23_RSVD,         /* 35 0x23 */
+       MPUREG_24_RSVD,         /* 36 0x24 */
+       MPUREG_25_RSVD,         /* 37 0x25 */
+       MPUREG_26_RSVD,         /* 38 0x26 */
+       MPUREG_27_RSVD,         /* 39 0x27 */
+       MPUREG_28_RSVD,         /* 40 0x28 */
+       MPUREG_29_RSVD,         /* 41 0x29 */
+       MPUREG_2A_RSVD,         /* 42 0x2a */
+       MPUREG_2B_RSVD,         /* 43 0x2b */
+       MPUREG_2C_RSVD,         /* 44 0x2c */
+       MPUREG_2D_RSVD,         /* 45 0x2d */
+       MPUREG_2E_RSVD,         /* 46 0x2e */
+       MPUREG_2F_RSVD,         /* 47 0x2f */
+       MPUREG_30_RSVD,         /* 48 0x30 */
+       MPUREG_31_RSVD,         /* 49 0x31 */
+       MPUREG_32_RSVD,         /* 50 0x32 */
+       MPUREG_33_RSVD,         /* 51 0x33 */
+       MPUREG_34_RSVD,         /* 52 0x34 */
+       MPUREG_DMP_CFG_1,       /* 53 0x35 */
+       MPUREG_DMP_CFG_2,       /* 54 0x36 */
+       MPUREG_BANK_SEL,        /* 55 0x37 */
+       MPUREG_MEM_START_ADDR,  /* 56 0x38 */
+       MPUREG_MEM_R_W,         /* 57 0x39 */
+       MPUREG_FIFO_COUNTH,     /* 58 0x3a */
+       MPUREG_FIFO_COUNTL,     /* 59 0x3b */
+       MPUREG_FIFO_R_W,        /* 60 0x3c */
+       MPUREG_USER_CTRL,       /* 61 0x3d */
+       MPUREG_PWR_MGM,         /* 62 0x3e */
+       MPUREG_3F_RSVD,         /* 63 0x3f */
+       NUM_OF_MPU_REGISTERS    /* 64 0x40 */
+};
+
+/*==== BITS FOR MPU ====*/
+
+/*---- MPU 'FIFO_EN1' register (12) ----*/
+#define BIT_TEMP_OUT                0x80
+#define BIT_GYRO_XOUT               0x40
+#define BIT_GYRO_YOUT               0x20
+#define BIT_GYRO_ZOUT               0x10
+#define BIT_ACCEL_XOUT              0x08
+#define BIT_ACCEL_YOUT              0x04
+#define BIT_ACCEL_ZOUT              0x02
+#define BIT_AUX_1OUT                0x01
+/*---- MPU 'FIFO_EN2' register (13) ----*/
+#define BIT_AUX_2OUT                0x02
+#define BIT_AUX_3OUT                0x01
+/*---- MPU 'DLPF_FS_SYNC' register (16) ----*/
+#define BITS_EXT_SYNC_NONE          0x00
+#define BITS_EXT_SYNC_TEMP          0x20
+#define BITS_EXT_SYNC_GYROX         0x40
+#define BITS_EXT_SYNC_GYROY         0x60
+#define BITS_EXT_SYNC_GYROZ         0x80
+#define BITS_EXT_SYNC_ACCELX        0xA0
+#define BITS_EXT_SYNC_ACCELY        0xC0
+#define BITS_EXT_SYNC_ACCELZ        0xE0
+#define BITS_EXT_SYNC_MASK          0xE0
+#define BITS_FS_250DPS              0x00
+#define BITS_FS_500DPS              0x08
+#define BITS_FS_1000DPS             0x10
+#define BITS_FS_2000DPS             0x18
+#define BITS_FS_MASK                0x18
+#define BITS_DLPF_CFG_256HZ_NOLPF2  0x00
+#define BITS_DLPF_CFG_188HZ         0x01
+#define BITS_DLPF_CFG_98HZ          0x02
+#define BITS_DLPF_CFG_42HZ          0x03
+#define BITS_DLPF_CFG_20HZ          0x04
+#define BITS_DLPF_CFG_10HZ          0x05
+#define BITS_DLPF_CFG_5HZ           0x06
+#define BITS_DLPF_CFG_2100HZ_NOLPF  0x07
+#define BITS_DLPF_CFG_MASK          0x07
+/*---- MPU 'INT_CFG' register (17) ----*/
+#define BIT_ACTL                    0x80
+#define BIT_ACTL_LOW                0x80
+#define BIT_ACTL_HIGH               0x00
+#define BIT_OPEN                    0x40
+#define BIT_OPEN_DRAIN              0x40
+#define BIT_PUSH_PULL               0x00
+#define BIT_LATCH_INT_EN            0x20
+#define BIT_LATCH_INT_EN            0x20
+#define BIT_INT_PULSE_WIDTH_50US    0x00
+#define BIT_INT_ANYRD_2CLEAR        0x10
+#define BIT_INT_STAT_READ_2CLEAR    0x00
+#define BIT_MPU_RDY_EN              0x04
+#define BIT_DMP_INT_EN              0x02
+#define BIT_RAW_RDY_EN              0x01
+/*---- MPU 'INT_STATUS' register (1A) ----*/
+#define BIT_INT_STATUS_FIFO_OVERLOW (0x80)
+#define BIT_MPU_RDY                 0x04
+#define BIT_DMP_INT                 0x02
+#define BIT_RAW_RDY                 0x01
+/*---- MPU 'BANK_SEL' register (37) ----*/
+#define BIT_PRFTCH_EN               0x20
+#define BIT_CFG_USER_BANK           0x10
+#define BITS_MEM_SEL                0x0f
+/*---- MPU 'USER_CTRL' register (3D) ----*/
+#define BIT_DMP_EN                  0x80
+#define BIT_FIFO_EN                 0x40
+#define BIT_AUX_IF_EN               0x20
+#define BIT_AUX_RD_LENG             0x10
+#define BIT_AUX_IF_RST              0x08
+#define BIT_DMP_RST                 0x04
+#define BIT_FIFO_RST                0x02
+#define BIT_GYRO_RST                0x01
+/*---- MPU 'PWR_MGM' register (3E) ----*/
+#define BIT_H_RESET                 0x80
+#define BIT_SLEEP                   0x40
+#define BIT_STBY_XG                 0x20
+#define BIT_STBY_YG                 0x10
+#define BIT_STBY_ZG                 0x08
+#define BITS_CLKSEL                 0x07
+
+/*---- MPU Silicon Revision ----*/
+#define MPU_SILICON_REV_A4           1 /* MPU A4 Device */
+#define MPU_SILICON_REV_B1           2 /* MPU B1 Device */
+#define MPU_SILICON_REV_B4           3 /* MPU B4 Device */
+#define MPU_SILICON_REV_B6           4 /* MPU B6 Device */
+
+/*---- MPU Memory ----*/
+#define MPU_MEM_BANK_SIZE 256
+#define FIFO_HW_SIZE                (512)      /* FIFO hw is 512 bytes */
+
+typedef enum {
+       MPU_MEM_RAM_BANK_0 = 0,
+       MPU_MEM_RAM_BANK_1,
+       MPU_MEM_RAM_BANK_2,
+       MPU_MEM_RAM_BANK_3,
+       MPU_MEM_NUM_RAM_BANKS,
+       MPU_MEM_OTP_BANK_0 = MPU_MEM_NUM_RAM_BANKS,
+       /* This one is always last */
+       MPU_MEM_NUM_BANKS
+} tMPUMemoryBanks, MPU_MEMORY_BANKS;
+
+#define MPU_NUM_AXES (3)
+
+/*---- structure containing control variables used by MLDL ----*/
+/*---- MPU clock source settings ----*/
+/*---- MPU filter selections ----*/
+enum mpu_filter {
+       MPU_FILTER_256HZ_NOLPF2 = 0,
+       MPU_FILTER_188HZ,
+       MPU_FILTER_98HZ,
+       MPU_FILTER_42HZ,
+       MPU_FILTER_20HZ,
+       MPU_FILTER_10HZ,
+       MPU_FILTER_5HZ,
+       MPU_FILTER_2100HZ_NOLPF,
+       NUM_MPU_FILTER
+};
+
+enum mpu_fullscale {
+       MPU_FS_250DPS = 0,
+       MPU_FS_500DPS,
+       MPU_FS_1000DPS,
+       MPU_FS_2000DPS,
+       NUM_MPU_FS
+};
+
+enum mpu_clock_sel {
+       MPU_CLK_SEL_INTERNAL = 0,
+       MPU_CLK_SEL_PLLGYROX,
+       MPU_CLK_SEL_PLLGYROY,
+       MPU_CLK_SEL_PLLGYROZ,
+       MPU_CLK_SEL_PLLEXT32K,
+       MPU_CLK_SEL_PLLEXT19M,
+       MPU_CLK_SEL_RESERVED,
+       MPU_CLK_SEL_STOP,
+       NUM_CLK_SEL
+};
+
+enum mpu_ext_sync {
+       MPU_EXT_SYNC_NONE = 0,
+       MPU_EXT_SYNC_TEMP,
+       MPU_EXT_SYNC_GYROX,
+       MPU_EXT_SYNC_GYROY,
+       MPU_EXT_SYNC_GYROZ,
+       MPU_EXT_SYNC_ACCELX,
+       MPU_EXT_SYNC_ACCELY,
+       MPU_EXT_SYNC_ACCELZ,
+       NUM_MPU_EXT_SYNC
+};
+
+#define DLPF_FS_SYNC_VALUE(ext_sync, full_scale, lpf) \
+       ((ext_sync << 5) | (full_scale << 3) | lpf)
+
+/* IOCTL commands for /dev/mpu */
+#define MPU_SET_MPU_CONFIG          (0x00)
+#define MPU_SET_INT_CONFIG          (0x01)
+#define MPU_SET_EXT_SYNC            (0x02)
+#define MPU_SET_FULL_SCALE          (0x03)
+#define MPU_SET_LPF                 (0x04)
+#define MPU_SET_CLK_SRC             (0x05)
+#define MPU_SET_DIVIDER             (0x06)
+#define MPU_SET_LEVEL_SHIFTER       (0x07)
+#define MPU_SET_DMP_ENABLE          (0x08)
+#define MPU_SET_FIFO_ENABLE         (0x09)
+#define MPU_SET_DMP_CFG1            (0x0a)
+#define MPU_SET_DMP_CFG2            (0x0b)
+#define MPU_SET_OFFSET_TC           (0x0c)
+#define MPU_SET_RAM                 (0x0d)
+
+#define MPU_SET_PLATFORM_DATA       (0x0e)
+
+#define MPU_GET_MPU_CONFIG          (0x80)
+#define MPU_GET_INT_CONFIG          (0x81)
+#define MPU_GET_EXT_SYNC            (0x82)
+#define MPU_GET_FULL_SCALE          (0x83)
+#define MPU_GET_LPF                 (0x84)
+#define MPU_GET_CLK_SRC             (0x85)
+#define MPU_GET_DIVIDER             (0x86)
+#define MPU_GET_LEVEL_SHIFTER       (0x87)
+#define MPU_GET_DMP_ENABLE          (0x88)
+#define MPU_GET_FIFO_ENABLE         (0x89)
+#define MPU_GET_DMP_CFG1            (0x8a)
+#define MPU_GET_DMP_CFG2            (0x8b)
+#define MPU_GET_OFFSET_TC           (0x8c)
+#define MPU_GET_RAM                 (0x8d)
+
+#define MPU_READ_REGISTER           (0x40)
+#define MPU_WRITE_REGISTER          (0x41)
+#define MPU_READ_MEMORY             (0x42)
+#define MPU_WRITE_MEMORY            (0x43)
+
+#define MPU_SUSPEND                 (0x44)
+#define MPU_RESUME                  (0x45)
+#define MPU_READ_COMPASS            (0x46)
+#define MPU_READ_ACCEL              (0x47)
+
+/* Structure for the following IOCTL's:
+       MPU_SET_RAM
+       MPU_GET_RAM
+       MPU_READ_REGISTER
+       MPU_WRITE_REGISTER
+       MPU_READ_MEMORY
+       MPU_WRITE_MEMORY
+*/
+struct mpu_read_write {
+       unsigned short address;
+       unsigned short length;
+       unsigned char *data;
+};
+
+/* Structure for the following IOCTL's
+       MPU_SUSPEND
+       MPU_RESUME
+*/
+struct mpu_suspend_resume {
+       int gyro;
+       int accel;
+       int compass;
+};
+
+enum ext_slave_type {
+       EXT_SLAVE_TYPE_GYROSCOPE,
+       EXT_SLAVE_TYPE_ACCELEROMETER,
+       EXT_SLAVE_TYPE_COMPASS,
+       /* EXT_SLAVE_TYPE_PRESSURE, */
+       /* EXT_SLAVE_TYPE_TEMPERATURE */
+};
+
+enum ext_slave_id {
+       ID_INVALID = 0,
+
+       ACCEL_ID_LIS331,
+       ACCEL_ID_LSM303,
+       ACCEL_ID_KXSD9,
+       ACCEL_ID_KXTF9,
+       ACCEL_ID_BMA150,
+       ACCEL_ID_BMA222,
+       ACCEL_ID_ADI346,
+       ACCEL_ID_MMA8450,
+       ACCEL_ID_MMA8451,
+
+       COMPASS_ID_AKM,
+       COMPASS_ID_AICHI,
+       COMPASS_ID_YAS529,
+       COMPASS_ID_HMC5883,
+       COMPASS_ID_LSM303,
+       COMPASS_ID_MMC314X,
+};
+
+enum ext_slave_endian {
+       EXT_SLAVE_BIG_ENDIAN,
+       EXT_SLAVE_LITTLE_ENDIAN,
+       EXT_SLAVE_FS8_BIG_ENDIAN,
+       EXT_SLAVE_FS16_BIG_ENDIAN,
+};
+
+enum ext_slave_bus {
+       EXT_SLAVE_BUS_PRIMARY,
+       EXT_SLAVE_BUS_SECONDARY,
+};
+
+/**
+ *  struct ext_slave_platform_data - Platform data for mpu3050 slave devices
+ *
+ *  @get_slave_descr: Function pointer to retrieve the struct ext_slave_descr
+ *                     for this slave
+ *  @adapt_num: the I2C adapter number.
+ *  @bus: the bus the slave is attached to: enum ext_slave_bus
+ *  @address: the I2C slave address of the slave device.
+ *  @orientation: the mounting matrix of the device relative to MPU.
+ *  @private_data: additional data, user customizable.  Not touched by the MPU
+ *     driver.
+ *
+ * The orientation matricies are 3x3 rotation matricies
+ * that are applied to the data to rotate from the mounting orientation to the
+ * platform orientation.  The values must be one of 0, 1, or -1 and each row and
+ * column should have exactly 1 non-zero value.
+ *
+ * @code
+ *  struct ext_slave_platform_data {
+ *      struct ext_slave_descr* (*get_slave_descr) (void);
+ *      int                     adapt_num;
+ *      int                     bus;
+ *      unsigned char           address;
+ *      signed char             orientation[9];
+ *      void                   *private_data;
+ *  };
+ * @endcode
+ */
+struct ext_slave_platform_data {
+       struct ext_slave_descr *(*get_slave_descr) (void);
+       int adapt_num;
+       int bus;
+       unsigned char address;
+       signed char orientation[9];
+       void *private_data;
+};
+
+struct tFixPntRange {
+       long mantissa;
+       long fraction;
+};
+
+/**
+ *  struct ext_slave_descr - Description of the slave device for programming
+ *
+ *  @suspend: function pointer to put the device in suspended state
+ *  @resume:  function pointer to put the device in running state
+ *  @read:    function that reads the device data
+ *
+ *  @name:     text name of the device
+ *  @type:     device type. enum ext_slave_type
+ *  @id:       enum ext_slave_id
+ *  @reg:      starting register address to retrieve data.
+ *  @len:      length in bytes of the sensor data.  Should be 6.
+ *  @endian:   byte order of the data. enum ext_slave_endian
+ *  @range:    full scale range of the slave ouput: struct tFixPntRange
+ *
+ *  Defines the functions and information about the slave the mpu3050 needs to
+ *  use the slave device.
+ *
+ *  @code
+ *      struct ext_slave_descr {
+ *          int (*suspend)  (mlsl_handle_t mlsl_handle,
+ *                           struct ext_slave_descr *slave,
+ *                           struct ext_slave_platform_data *pdata);
+ *          int (*resume)   (mlsl_handle_t mlsl_handle,
+ *                           struct ext_slave_descr *slave,
+ *                           struct ext_slave_platform_data *pdata);
+ *          int (*read)     (mlsl_handle_t mlsl_handle,
+ *                           struct ext_slave_descr *slave,
+ *                           struct ext_slave_platform_data *pdata,
+ *                           unsigned char * data);
+ *
+ *          unsigned char         type;
+ *          unsigned char         id;
+ *          unsigned char         reg;
+ *          unsigned int          len;
+ *          unsigned char         endian;
+ *          struct tFixPntRange   range;
+ *      };
+ *  @endcode
+ */
+struct ext_slave_descr {
+       int (*suspend) (mlsl_handle_t mlsl_handle,
+                       struct ext_slave_descr *slave,
+                       struct ext_slave_platform_data *pdata);
+       int (*resume) (mlsl_handle_t mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata);
+       int (*read) (mlsl_handle_t mlsl_handle,
+                    struct ext_slave_descr *slave,
+                    struct ext_slave_platform_data *pdata,
+                    unsigned char *data);
+
+       char *name;
+       unsigned char type;
+       unsigned char id;
+       unsigned char reg;
+       unsigned int len;
+       unsigned char endian;
+       struct tFixPntRange range;
+};
+
+/**
+ * struct mpu3050_platform_data - Platform data for the mpu3050 driver
+ * @int_config:                Bits [7:3] of the int config register.
+ * @orientation:       Orientation matrix of the gyroscope
+ * @level_shifter:     0: VLogic 1: VDD
+ * @accel:             Accel platform data
+ * @compass:   Compass platform data
+ *
+ * Contains platform specific information on how to configure the MPU3050 to
+ * work on this platform.  The orientation matricies are 3x3 rotation matricies
+ * that are applied to the data to rotate from the mounting orientation to the
+ * platform orientation.  The values must be one of 0, 1, or -1 and each row and
+ * column should have exactly 1 non-zero value.
+ *
+ * @code
+ *      struct mpu3050_platform_data {
+ *          unsigned char                  int_config;
+ *          signed char                           orientation[MPU_NUM_AXES*MPU_NUM_AXES];
+ *          unsigned char                  level_shifter;
+ *          struct ext_slave_platform_data accel;
+ *          struct ext_slave_platform_data compass;
+ *      };
+ * @endcode
+ */
+struct mpu3050_platform_data {
+       unsigned char int_config;
+       signed char orientation[MPU_NUM_AXES * MPU_NUM_AXES];
+       unsigned char level_shifter;
+       struct ext_slave_platform_data accel;
+       struct ext_slave_platform_data compass;
+};
+
+/*
+       Accelerometer
+*/
+#define get_accel_slave_descr NULL
+
+#ifdef CONFIG_SENSORS_ADXL346  /* ADI accelerometer */
+struct ext_slave_descr *adxl346_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr adxl346_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_BMA150   /* Bosch accelerometer */
+struct ext_slave_descr *bma150_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr bma150_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_BMA222   /* Bosch 222 accelerometer */
+struct ext_slave_descr *bma222_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr bma222_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_KXSD9    /* Kionix accelerometer */
+struct ext_slave_descr *kxsd9_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr kxsd9_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_KXTF9_MPU        /* Kionix accelerometer */
+struct ext_slave_descr *kxtf9_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr kxtf9_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_LIS331DLH        /* ST accelerometer */
+struct ext_slave_descr *lis331dlh_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr lis331dlh_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_LSM303DLHA       /* ST accelerometer */
+struct ext_slave_descr *lsm303dlha_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr lsm303dlha_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_MMA8450  /* Freescale accelerometer */
+struct ext_slave_descr *mma8450_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr mma8450_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_MMA8451  /* Freescale accelerometer */
+struct ext_slave_descr *mma8451_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr mma8451_get_slave_descr
+#endif
+
+/*
+       Compass
+*/
+#define get_compass_slave_descr NULL
+
+#ifdef CONFIG_SENSORS_AK8975_MPU       /* AKM compass */
+struct ext_slave_descr *ak8975_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr ak8975_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_AMI304   /* AICHI Steel compass */
+struct ext_slave_descr *ami304_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr ami304_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_HMC5883  /* Honeywell compass */
+struct ext_slave_descr *hmc5883_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr hmc5883_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_MMC314X  /* MEMSIC compass */
+struct ext_slave_descr *mmc314x_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr mmc314x_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_LSM303DLHM       /* ST compass */
+struct ext_slave_descr *lsm303dlhm_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr lsm303dlhm_get_slave_descr
+#endif
+
+#ifdef CONFIG_SENSORS_YAS529   /* Yamaha compass */
+struct ext_slave_descr *yas529_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr yas529_get_slave_descr
+#endif
+
+#endif                         /* __MPU3050_H_ */