(xxm) update FIH: 1,add mpu3050 2,update rk29_FIH_defconfig 3,update touch screen
authorroot <root@rockchip-MID.(none)>
Tue, 1 Mar 2011 12:36:31 +0000 (20:36 +0800)
committerroot <root@rockchip-MID.(none)>
Tue, 1 Mar 2011 12:36:31 +0000 (20:36 +0800)
48 files changed:
arch/arm/configs/rk29_FIH_defconfig
arch/arm/mach-rk29/board-rk29-fih.c
drivers/input/gsensor/gs_fih.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/atmel_mxt224.c [new file with mode: 0644]
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/mpu3050/Kconfig [new file with mode: 0644]
drivers/misc/mpu3050/Makefile [new file with mode: 0644]
drivers/misc/mpu3050/README [new file with mode: 0644]
drivers/misc/mpu3050/accel/adxl346.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/bma150.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/bma222.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/cma3000.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/kxsd9.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/kxtf9.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/lis331.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/lsm303a.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/mantis.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/mma8450.c [new file with mode: 0644]
drivers/misc/mpu3050/accel/mma8451.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/ak8975.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/ami30x.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/hmc5883.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/hscdtd00xx.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/lsm303m.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/mmc314x.c [new file with mode: 0644]
drivers/misc/mpu3050/compass/yas529-kernel.c [new file with mode: 0644]
drivers/misc/mpu3050/log.h [new file with mode: 0644]
drivers/misc/mpu3050/mldl_cfg.c [new file with mode: 0644]
drivers/misc/mpu3050/mldl_cfg.h [new file with mode: 0644]
drivers/misc/mpu3050/mlos-kernel.c [new file with mode: 0644]
drivers/misc/mpu3050/mlos.h [new file with mode: 0644]
drivers/misc/mpu3050/mlsl-kernel.c [new file with mode: 0644]
drivers/misc/mpu3050/mlsl.h [new file with mode: 0644]
drivers/misc/mpu3050/mltypes.h [new file with mode: 0644]
drivers/misc/mpu3050/mpu-dev.c [new file with mode: 0644]
drivers/misc/mpu3050/mpu-i2c.c [new file with mode: 0644]
drivers/misc/mpu3050/mpu-i2c.h [new file with mode: 0644]
drivers/misc/mpu3050/mpuirq.c [new file with mode: 0644]
drivers/misc/mpu3050/mpuirq.h [new file with mode: 0644]
drivers/misc/mpu3050/slaveirq.c [new file with mode: 0644]
drivers/misc/mpu3050/slaveirq.h [new file with mode: 0644]
drivers/staging/iio/magnetometer/Kconfig
include/linux/mpu.h [new file with mode: 0644]
include/linux/mpu3050.h [new file with mode: 0644]
include/linux/mpu6000.h [new file with mode: 0644]

index 1493359ea9186701bdf73eeffea030ac5ebc5f13..8dd1c19c98d335da36cc8492922aba1f818dc1b7 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.32.27
-# Tue Mar  1 11:15:10 2011
+# Tue Mar  1 20:25:24 2011
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -610,6 +610,34 @@ CONFIG_APANIC_PLABEL="kpanic"
 # CONFIG_RK29_SUPPORT_MODEM is not set
 CONFIG_RK29_GPS=y
 CONFIG_GPS_GNS7560=y
+
+#
+# Motion Sensors Support
+#
+# CONFIG_MPU_NONE is not set
+CONFIG_SENSORS_MPU3050=y
+# CONFIG_SENSORS_MPU6000 is not set
+CONFIG_SENSORS_ACCELEROMETER_NONE=y
+# CONFIG_SENSORS_ADXL346 is not set
+# CONFIG_SENSORS_BMA150 is not set
+# CONFIG_SENSORS_BMA222 is not set
+# CONFIG_SENSORS_KXSD9 is not set
+# CONFIG_SENSORS_KXTF9 is not set
+# CONFIG_SENSORS_LIS331DLH is not set
+# CONFIG_SENSORS_LSM303DLHA is not set
+# CONFIG_SENSORS_MMA8450 is not set
+# CONFIG_SENSORS_MMA8451 is not set
+# CONFIG_SENSORS_COMPASS_NONE is not set
+CONFIG_SENSORS_AK8975=y
+# CONFIG_SENSORS_MMC314X is not set
+# CONFIG_SENSORS_AMI30X is not set
+# CONFIG_SENSORS_HMC5883 is not set
+# CONFIG_SENSORS_LSM303DLHM is not set
+# CONFIG_SENSORS_YAS529 is not set
+# CONFIG_SENSORS_HSCDTD00XX is not set
+CONFIG_SENSORS_PRESSURE_NONE=y
+# CONFIG_SENSORS_BMA085 is not set
+# CONFIG_SENSORS_MPU_DEBUG is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -807,17 +835,17 @@ CONFIG_TOUCHSCREEN_XPT2046_SPI_NOCHOOSE=y
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
 # CONFIG_TOUCHSCREEN_W90X900 is not set
 # CONFIG_HANNSTAR_P1003 is not set
+CONFIG_ATMEL_MXT224=y
+CONFIG_MXT224_MAX_X=4095
+CONFIG_MXT224_MAX_Y=4095
 # CONFIG_SINTEK_3FA16 is not set
-CONFIG_EETI_EGALAX=y
-CONFIG_EETI_EGALAX_MAX_X=1087
-CONFIG_EETI_EGALAX_MAX_Y=800
-# CONFIG_EETI_EGALAX_DEBUG is not set
+# CONFIG_EETI_EGALAX is not set
 # CONFIG_TOUCHSCREEN_IT7260 is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_PSENSOR_ISL29028 is not set
 # CONFIG_INPUT_LPSENSOR_CM3602 is not set
 CONFIG_INPUT_LSENSOR_CM3623=y
-CONFIG_INPUT_MPU3050=y
+# CONFIG_INPUT_MPU3050 is not set
 # CONFIG_INPUT_ATI_REMOTE is not set
 # CONFIG_INPUT_ATI_REMOTE2 is not set
 # CONFIG_INPUT_KEYCHORD is not set
@@ -1628,33 +1656,7 @@ CONFIG_ANDROID_LOW_MEMORY_KILLER=y
 # RAR Register Driver
 #
 # CONFIG_RAR_REGISTER is not set
-CONFIG_IIO=y
-# CONFIG_IIO_RING_BUFFER is not set
-# CONFIG_IIO_TRIGGER is not set
-
-#
-# Accelerometers
-#
-
-#
-# Analog to digital convertors
-#
-# CONFIG_MAX1363 is not set
-
-#
-# Light sensors
-#
-# CONFIG_TSL2561 is not set
-
-#
-# Magnetometer sensors
-#
-CONFIG_SENSORS_AK8975=y
-# CONFIG_SENSORS_AK8973 is not set
-
-#
-# Triggers - standalone
-#
+# CONFIG_IIO is not set
 
 #
 # DSP
index fbc83597dd4de387e19b726d49b4de06c0a7b590..1c37ba677bd02d3e0387c43c84028e3564c1dff1 100755 (executable)
@@ -25,6 +25,7 @@
 #include <linux/android_pmem.h>
 #include <linux/usb/android_composite.h>
 #include <linux/i2c/tps65910.h>
+#include <linux/mpu.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -402,7 +403,33 @@ static struct mma8452_platform_data mma8452_info = {
 
 };
 #endif
-
+#if 1
+/*mpu3050*/
+static struct mpu3050_platform_data mpu3050_data = {
+               .int_config = 0x10,
+               .orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 },
+               .level_shifter = 0,
+#if 0
+               .accel = {
+                               .get_slave_descr = bma150_get_slave_descr,
+                               .adapt_num = 0, // The i2c bus to which the mpu device is
+                               // connected
+                               .bus = EXT_SLAVE_BUS_SECONDARY,  //The secondary I2C of MPU
+                               .address = 0x38,
+                               .orientation = { 0, 1, 0,1, 0, 0,0, 0, -1 },
+               },
+#endif
+               .compass = {
+                               .get_slave_descr = ak8975_get_slave_descr,/*ak5883_get_slave_descr,*/
+                               .adapt_num = 0, // The i2c bus to which the compass device is. 
+                               // It can be difference with mpu
+                               // connected
+                               .bus = EXT_SLAVE_BUS_PRIMARY,
+                               .address = 0x1E,
+                               .orientation = { 0, 1, 0,-1, 0, 0,0, 0, 1 },
+               },
+};
+#endif
 
 /*****************************************************************************************
 * TI TPS65910 voltage regulator devices 
@@ -892,6 +919,16 @@ static struct i2c_board_info __initdata board_i2c0_devices[] = {
                .irq                    = RK29_PIN0_PA4,
        },
 #endif
+#if 1
+/*mpu3050*/
+       {
+               .type                   = "mpu3050",
+               .addr                   = 0x68,
+               .flags                  = 0,
+               .irq                    = RK29_PIN5_PA3,
+               .platform_data  = &mpu3050_data,
+       },
+#endif
 };
 #endif
 
@@ -912,7 +949,15 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
         .irq            = RK29_PIN1_PD7,
     },
 #endif
-
+#if defined (CONFIG_ATMEL_MXT224)
+    {
+      .type           = "mXT224_touch",
+      .addr           = 0x4B,
+      .flags          = 0,
+      .irq            = RK29_PIN0_PA2,
+      //.platform_data  = &p1003_info,
+    },
+#endif
 };
 #endif
 
index 28ce9b3b10c365055a440cdfc557cceda3e40430..f9ab7be1290acfd0962b6b58a674ea70bc5cf414 100644 (file)
@@ -546,13 +546,13 @@ static int mma8452_resume(struct i2c_client *client)
 #endif
 
 static const struct i2c_device_id mma8452_id[] = {
-               {"gs_mma8452", 0},
+               {"gs_fih", 0},
                { }
 };
 
 static struct i2c_driver mma8452_driver = {
        .driver = {
-               .name = "gs_mma8452",
+               .name = "gs_fih",
            },
        .id_table       = mma8452_id,
        .probe          = mma8452_probe,
index 4d89856c979359706ec53737195803fe4a90d078..40faa3160bb49b87a18486b99f451c65159a4e9a 100755 (executable)
@@ -602,6 +602,25 @@ config HANNSTAR_P1003
                default n
                help
                  RK29 hannstar touch debug
+config ATMEL_MXT224
+        tristate "Atmel mXT224 touchscreen"
+        depends on I2C2_RK29
+        help
+          RK29 Atmel_mXT224 touch
+
+        config MXT224_MAX_X
+                int "atmel_mxt224 touch X max"
+                depends on ATMEL_MXT224
+                default 4095
+                help
+                  RK29 atmel_mxt224 touch max X size
+
+        config MXT224_MAX_Y
+                int "atmel_mxt224 touch Y max"
+                depends on ATMEL_MXT224
+                default 4095
+                help
+                  RK29 atmel_mxt224 touch max Y size
 
 config SINTEK_3FA16
         tristate "Sintek 3FA16  touchscreen"
index 5ba46466857b5b038e723d34d099a909d825da24..486f923df8535781121533adaf9ad3ad8cf77eb0 100644 (file)
@@ -53,3 +53,4 @@ obj-$(CONFIG_HANNSTAR_P1003)          += hannstar_p1003.o
 obj-$(CONFIG_TOUCHSCREEN_IT7260)               += it7260_ts.o
 obj-$(CONFIG_SINTEK_3FA16)     +=  sintek_3FA16.o
 obj-$(CONFIG_EETI_EGALAX)              += eeti_egalax_i2c.o
+obj-$(CONFIG_ATMEL_MXT224)               += atmel_mxt224.o
diff --git a/drivers/input/touchscreen/atmel_mxt224.c b/drivers/input/touchscreen/atmel_mxt224.c
new file mode 100644 (file)
index 0000000..be4ae7d
--- /dev/null
@@ -0,0 +1,1011 @@
+/****************************************************************************************
+ * driver/input/touchscreen/atmel_mxt224.c
+ *Copyright    :ROCKCHIP  Inc
+ *Author       :       dqz
+ *Date         :  2011.2.28
+ *
+ *description£º
+ ********************************************************************************************/
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/async.h>
+#include <mach/gpio.h>
+#include <linux/irq.h>
+#include <mach/board.h>
+
+#define FEATURE_CFG_DUMP
+
+static int mxt224_i2c_write(struct i2c_client *client, u16 offset,void *buf,int size);
+static int mxt224_i2c_read(struct i2c_client *client, u16 offset,void *buf,int size);
+static int mXT224_probe(struct i2c_client *client, const struct i2c_device_id *id);
+static int mXT224_remove(struct i2c_client *client);
+
+#ifdef FEATURE_CFG_DUMP
+static int total_size = 0;
+static u8 *cfg_dmup;
+#endif
+#define local_debug 
+#define ID_INFORMATION_SIZE        0x7
+#define OBJECT_TABLE_ELEMENT_SIZE  0x6
+#define CRC_SIZE                   0x3
+#define TABLE_SIZE_ADDR            ID_INFORMATION_SIZE-1
+#define MESSAGE_T5                 0x5
+
+#define MXT224_REPORTID_T9_OFFSET 9
+#define MXT224_MT_SCAN_POINTS 2
+
+struct mxt224_id_info{
+    u8   family_id;
+    u8   variant_id;
+    u8   version;
+    u8   build;
+    u8   matrix_x_size;
+    u8   matrix_y_size;
+    u8   object_num;
+}__packed;
+
+struct mxt224_table_info{
+    u8   obj_type;
+    u8   start_addr_lsb;
+    u8   start_addr_msb;
+    u8   size;
+    u8   instance;
+    u8   report_id;
+}__packed;
+
+#define CFGERR_MASK (0x01<<3)
+
+union msg_body{
+    u8 msg[7];
+    struct{
+        u8  status;
+        u32 checksum:24;
+    }t6;
+    struct{
+        u8  status;
+        u8  x_msb;
+        u8  y_msb;
+        u8  xy_poslisb;
+        u8  area;
+        u8  tchamplitude;
+        u8  tchvector;
+    }t9;
+}__packed;
+
+struct message_t5{
+    u8 report_id;
+    union msg_body body;
+    u8 checksum;
+}__packed;
+
+struct mxt224_obj{
+    struct mxt224_id_info    *id_info;
+    u8                       *table_info_byte;
+    struct mxt224_table_info *table_info;
+    u8                        table_size;
+    u16                       msg_t5_addr;
+    u32                       info_crc;
+};
+
+struct mXT224_info {
+    int int_gpio;
+    int reset_gpio;
+    int cfg_delay;
+       int last_key_index;
+    u16 last_read_addr;
+
+       char phys[32];
+    //struct hrtimer timer;
+    struct i2c_client *client;
+    struct input_dev *input_dev;
+       struct delayed_work     work;
+       struct workqueue_struct *mxt224_wq;
+
+    int (*power)(int on);
+    /* Object table relation */
+    struct mxt224_obj obj;
+};
+
+static struct mXT224_info ts_data = {
+    .int_gpio = RK29_PIN0_PA2,
+    .reset_gpio = RK29_PIN6_PC3,
+    .cfg_delay = 0,
+    .last_key_index = 0,
+    .last_read_addr = 0,
+};
+
+struct report_id_table{
+    u8 report_start;
+    u8 report_end;
+    u8 obj_type;
+};
+
+static struct report_id_table* id_table = NULL;
+
+struct mxt224_cfg{
+    u8 type;
+    const u8* data;
+    int size;
+};
+
+
+struct mxt224_key_info{
+    u32  start;
+    u32  end;
+    u32  code;
+};
+const struct mxt224_key_info key_info[] = {
+       {0, 0, KEY_BACK},
+    {0, 0, KEY_MENU},
+    {0, 0, KEY_HOME},
+    {0, 0, KEY_SEARCH},
+};
+
+#if 1
+const u8 T7[] =  {0xff, 0xff, 0x32};
+const u8 T8[] =  {0x08, 0x05, 0x14, 0x14, 0x00, 0x00, 0x0a, 0x0f};
+const u8 T9[] =  {0x83, 0x00, 0x00, 0x0D, 0x0A, 0x00, 0x11, 0x28,
+                  0x02, 0x01, 0x00, 0x01, 0x01, 0x00, 0x0A, 0x0A,
+                  0x0A, 0x0A, 0x01, 0x5A, 0x00, 0xEF, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                  ///////////////////////////////////////
+                  //0x83, 0x0D, 0x0A, 0x03, 0x03, 0x00, 0x11, 0x28,
+                  //0x02, 0x03, 0x00, 0x01, 0x01, 0x00, 0x0A, 0x0A,
+                  //0x0A, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                  //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                  };
+const u8 T15[] = {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x41, 0x1E,
+                  0x02, 0x00, 0x00 };
+const u8 T18[] = {0x00, 0x00 };
+const u8 T19[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const u8 T20[] = {0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00 };
+const u8 T22[] = {0x15, 0x00, 0x00, 0x00, 0x19, 0xFF, 0xE7, 0x04,
+                  0x32, 0x00, 0x01, 0x0A, 0x0F, 0x14, 0x19, 0x1E,
+                  0x04,
+                  /////////////////////////////////////
+                  //0x15, 0x00, 0x00, 0x00, 0x19, 0xff, 0xe7, 0x04,
+                  //0x32, 0x00, 0x01, 0x0a, 0x0f, 0x14, 0x19, 0x1e,
+                  //0x04,
+                  };
+const u8 T23[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                  0x00, 0x00, 0x00, 0x00, 0x00 };
+const u8 T24[] = {0x03, 0x04, 0x03, 0xFF, 0x00, 0x64, 0x64, 0x01,
+                  0x0A, 0x14, 0x28, 0x00, 0x4B, 0x00, 0x02, 0x00,
+                  0x64, 0x00, 0x19 };
+const u8 T25[] = {0x00, 0x00, 0x2E, 0xE0, 0x1B, 0x58, 0x36, 0xB0,
+                  0x01, 0xF4, 0x00, 0x00, 0x00, 0x00 };
+const u8 T27[] = {0x03, 0x02, 0x00, 0xE0, 0x03, 0x00, 0x23};
+const u8 T28[] = {0x00, 0x00, 0x00, 0x04, 0x08, 0xF6 };
+const u8 T38[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+const struct mxt224_cfg cfg_table[] = {
+    {7,  T7,  sizeof(T7)},
+    {8,  T8,  sizeof(T8)},
+    {9,  T9,  sizeof(T9)},
+    {15, T15, sizeof(T15)},
+    {18, T18, sizeof(T18)},
+    {19, T19, sizeof(T19)},
+    {20, T20, sizeof(T20)},
+    {22, T22, sizeof(T22)},
+    {23, T23, sizeof(T23)},
+    {24, T24, sizeof(T24)},
+    {25, T25, sizeof(T25)},
+    {27, T27, sizeof(T27)},
+    {28, T28, sizeof(T28)},
+    {38, T38, sizeof(T38)}
+};
+#endif
+
+
+enum mXT224_type{
+    MSG_T9_MT_1 = 1,
+    MSG_T9_MT_2,
+    MSG_T9_MT_3,
+    MSG_T9_MT_4,
+    MSG_T9_MT_5,
+    MSG_T9_MT_6,
+    MSG_T9_MT_7,
+    MSG_T9_MT_8,
+    MSG_T9_MT_9,
+    MSG_T9_KEY_PRESS,
+
+    MSG_T6,
+};
+
+enum mXT224_touch_status{
+    STATUS_RELEASE = 0,
+    STATUS_PRESS,
+};
+
+
+u32 static crc24(u32 crc, u8 firstbyte, u8 secondbyte)
+{
+    const u32 crcpoly = 0x80001b;
+    u32 result;
+    u16 data_word;
+
+    data_word = (u16)((u16)(secondbyte<<8u)|firstbyte);
+    result = ((crc<<1u)^(u32)data_word);
+    if(result & 0x1000000){
+        result ^= crcpoly;
+    }
+    return result;
+}
+
+u32 static get_crc24(const u8* src, int cnt)
+{
+    int index = 0;
+    u32 crc = 0;
+
+    while(index < (cnt-1)){
+        crc = crc24(crc, *(src+index), *(src+index+1));
+        index += 2;
+    }
+    //1 TODO:
+    if(index != cnt){
+        crc = crc24(crc, *(src+index), 0);
+    }
+    crc = (crc & 0x00ffffff);
+    return crc;
+}
+
+static u32 mXT224_cfg_crc(void)
+{
+    int index;
+    int sub_index = 0;
+    u32 crc = 0;
+
+    /* Remove T38 */
+    for(index=0; index<((sizeof(cfg_table)/sizeof(cfg_table[0]))-1); index++){
+        const u8* data = cfg_table[index].data;
+        while(sub_index <(cfg_table[index].size-1)){
+            crc = crc24(crc, *(data+sub_index), *(data+sub_index+1));
+            sub_index += 2;
+        }
+        if(sub_index != cfg_table[index].size){
+            if(index == ((sizeof(cfg_table)/sizeof(cfg_table[0]))-1)){
+                crc = crc24(crc, *(data+sub_index), 0);
+            }else{
+                const u8* next_data = cfg_table[index+1].data;
+                crc = crc24(crc, *(data+sub_index), *(next_data));
+                crc = (crc & 0x00ffffff);
+                sub_index = 1;
+                continue;
+            }            
+        }
+        sub_index = 0;
+        crc = (crc & 0x00ffffff);
+    }
+    //1 TODO:
+    //crc = crc24(crc, 0, 0);
+    crc = (crc & 0x00ffffff);
+    return crc;
+}
+
+static void mxt224_mem_dbg(const void *src, int cnt)
+{
+#if 0
+    int index;
+    const u8* disp = (u8*)src;
+    local_debug(KERN_INFO "%s: start...\n", __func__);
+    for(index=0; index < cnt; index++){
+       local_debug(KERN_INFO "0x%2x  ", disp[index]);
+    }
+    local_debug(KERN_INFO "\n%s: ...end\n", __func__);
+#endif
+}
+
+
+
+static irqreturn_t mXT224_ts_interrupt(int irq, void *handle)
+{
+       struct mXT224_info *ts = handle;
+       local_debug(KERN_INFO "%s\n", __func__);
+
+       disable_irq_nosync(ts->int_gpio);
+       queue_delayed_work(ts->mxt224_wq, &ts->work, 0);
+
+       return IRQ_HANDLED;
+}
+
+
+static u16 mXT224_get_obj_addr(u8 type, struct mxt224_table_info *info, u8 info_size)
+{
+    int index;
+    u16 addr = 0;
+
+    for(index=0; index < info_size; index++){
+               if(type == info[index].obj_type){
+            addr = info[index].start_addr_msb;
+            addr <<= 8;
+            addr |= info[index].start_addr_lsb;
+            return addr;
+        }
+    }
+    return addr;
+}
+
+
+static struct report_id_table* mXT224_build_report_id_table(
+        struct mxt224_table_info *info, u8 info_size)
+{
+    int index;
+    int write_index;
+    u8  offset = 0;
+    id_table = (struct report_id_table*)kzalloc(info_size*sizeof(struct report_id_table), GFP_KERNEL);
+    
+    if(!id_table){
+        local_debug(KERN_INFO "%s: Can't get memory!\n", __func__);
+        return NULL;
+    }
+    
+    write_index = 0;
+    
+    for(index = 0; index < info_size; index++){     
+#ifdef FEATURE_CFG_DUMP
+        total_size += ((info[index].size+1)*(info[index].instance+1));
+#endif
+        if(info[index].obj_type == 0x5)
+            continue;
+        if(info[index].report_id == 0x00)
+            continue;
+        
+        id_table[write_index].obj_type = info[index].obj_type;
+        id_table[write_index].report_start = (offset+1);
+        id_table[write_index].report_end = id_table[write_index].report_start+
+                                                info[index].report_id*(info[index].instance+1)-1;
+        
+        offset = id_table[write_index].report_end;
+        write_index++;
+    }
+    
+#ifdef FEATURE_CFG_DUMP
+    for(index = 0; index < info_size; index++){
+               local_debug(KERN_INFO "%s: Object type:%d, size:[%d]\n", __func__, 
+                            info[index].obj_type, info[index].size+1);
+    }
+#endif
+    
+    return id_table;
+}
+
+
+static u8 mXT224_get_obj_type(u8 id, struct report_id_table* table, u8 table_size)
+{
+    int index;
+
+    for(index=0; index < table_size; index++){    
+               local_debug(KERN_INFO "%s: ID:%d, start:[%d], end:[%d], type:[%d]\n", __func__, 
+                         id, table[index].report_start, table[index].report_end, 
+               table[index].obj_type);
+        if(id>=table[index].report_start && id<=table[index].report_end){
+            break;
+        }
+    }
+    
+    switch(table[index].obj_type){
+        case 6:
+            return MSG_T6;
+            
+        case 9:
+        {
+            int t9_offset = id-table[index].report_start;
+            if(t9_offset < MXT224_REPORTID_T9_OFFSET){
+                return MSG_T9_MT_1+t9_offset;
+            }else{
+                return 0;
+            }
+        }   
+        case 15:
+               {
+                       return MSG_T9_KEY_PRESS;
+               }
+        default:
+            return 0;
+    }
+}
+
+
+#define TS_POLL_PERIOD 10000*1000
+
+
+static void mXT224_load_cfg(void)
+{
+    int index;
+    u8  buf[6] = {0};
+    u16 addr;
+    int rc;
+    
+    local_debug(KERN_INFO "%s\n", __func__);
+
+    if(ts_data.cfg_delay){
+        return;
+    }
+    ts_data.cfg_delay = 1;
+    
+   // hrtimer_start(&ts_data.timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_MODE_REL);
+    
+    for(index=0; index<(sizeof(cfg_table)/sizeof(cfg_table[0])); index++){
+
+        const u8* data = cfg_table[index].data;
+        u16 addr = mXT224_get_obj_addr(cfg_table[index].type, ts_data.obj.table_info,
+                                                              ts_data.obj.table_size);
+        rc = mxt224_i2c_write(ts_data.client, addr, data, cfg_table[index].size);
+        if(rc){
+            local_debug(KERN_INFO "%s: Load mXT224 config failed, addr: 0x%x!\n", __func__, addr);
+        }
+    }
+    
+    addr = mXT224_get_obj_addr(6, ts_data.obj.table_info, ts_data.obj.table_size);
+    
+    //buf[0] = 0x05;
+    buf[1] = 0x55;
+    
+    rc = mxt224_i2c_write(ts_data.client, addr, buf, 6);
+    
+    if(rc){
+        local_debug(KERN_INFO "%s: Back up NV failed!\n", __func__);
+    }
+    
+    /* Reset mXT224 */
+    msleep(5);
+    
+    gpio_set_value(ts_data.reset_gpio, 0);
+    msleep(1);
+    
+    gpio_set_value(ts_data.reset_gpio, 1);
+    msleep(50);
+    
+}
+
+
+
+#define DETECT_MASK     (0x01<<7)
+#define RELEASE_MASK    (0x01<<5)
+#define MOVE_MASK       (0x01<<4)
+
+
+static u32 cfg_crc;
+
+
+static int mXT224_process_msg(u8 id, u8 *msg)
+{
+
+    switch(id){
+        case MSG_T6:
+        {
+                       local_debug(KERN_INFO "%s: Process mXT224 msg MSG_T6!\n", __func__);
+            u32 checksum = ((union msg_body*)msg)->t6.checksum;
+            
+            u8  status = ((union msg_body*)msg)->t6.status;
+            
+            if(status & CFGERR_MASK){
+                local_debug(KERN_INFO "%s: Process mXT224 cfg error!\n", __func__);
+               // mXT224_load_cfg();
+            }
+            /*
+            if(checksum!=cfg_crc){
+                local_debug(KERN_INFO "%s: Process mXT224 cfg CRC error!\n", __func__);
+                local_debug(KERN_INFO "%s: Read CRC:[0x%x], Our CRC:[0x%x]\n", __func__, checksum, cfg_crc);
+                mXT224_load_cfg();
+            }
+            */
+            break;
+        }
+        
+        case MSG_T9_MT_1:
+          
+        case MSG_T9_MT_2:
+          
+        case MSG_T9_MT_3:
+               case MSG_T9_MT_4:
+               case MSG_T9_MT_5:
+        {
+                       local_debug(KERN_INFO "%s: Process mXT224 msg MSG_T9_MT!\n", __func__);
+            u32 x, y;
+           int tcStatus = 0;
+            x = ((union msg_body*)msg)->t9.x_msb;
+            x <<= 4;
+            x |= (((union msg_body*)msg)->t9.xy_poslisb>>4);
+
+            y = ((union msg_body*)msg)->t9.y_msb;
+            y <<= 4;
+            ((union msg_body*)msg)->t9.xy_poslisb &= 0x0f;
+            
+            y |= ((union msg_body*)msg)->t9.xy_poslisb;
+            
+            local_debug(KERN_INFO "%s: X[%d], Y[%d]\n", __func__, x, y);
+
+                       if(((union msg_body*)msg)->t9.status & DETECT_MASK)
+                       {
+                               tcStatus = STATUS_PRESS;
+                       }else if(((union msg_body*)msg)->t9.status & RELEASE_MASK)
+                       {
+                               tcStatus = STATUS_RELEASE;
+                       }
+                       
+            input_report_abs(ts_data.input_dev, ABS_MT_TRACKING_ID, id - 1);                                                   
+            input_report_abs(ts_data.input_dev, ABS_MT_TOUCH_MAJOR, tcStatus);                         
+            input_report_abs(ts_data.input_dev, ABS_MT_WIDTH_MAJOR, 0);        
+            input_report_abs(ts_data.input_dev, ABS_MT_POSITION_X, x);                         
+            input_report_abs(ts_data.input_dev, ABS_MT_POSITION_Y, y);                         
+            input_mt_sync(ts_data.input_dev);   
+                       local_debug(KERN_INFO "%s,input_report_abs x is %d,y is %d. status is [%d].\n", __func__, x, y, tcStatus);
+            break;
+        }       
+        case MSG_T9_KEY_PRESS:
+        {
+            int keyStatus, keyIndex;
+                       
+            keyStatus = ((union msg_body*)msg)->t9.status >> 7;
+                       if(keyStatus) //press.
+            {
+                keyIndex = ((union msg_body*)msg)->t9.x_msb;
+                               ts_data.last_key_index = keyIndex;
+                       }else{                                                  
+                           keyIndex = ts_data.last_key_index;
+                       }
+                   switch(keyIndex){
+                       case 1:
+                           {
+                                               keyIndex = 0;
+                                               break;
+                           }
+                               case 2:
+                                       {
+                                               keyIndex = 1;
+                                               break;
+                                   }
+                               case 4:
+                                       {
+                                               keyIndex = 2;
+                                               break;
+                                       }
+                               case 8:
+                                       {
+                                               keyIndex = 3;
+                                               break;
+                                       }
+                   default:
+                local_debug(KERN_INFO "%s: Default keyIndex [0x%x]\n", __func__, keyIndex);        
+            break;
+                   }
+
+            local_debug(KERN_INFO "%s: Touch KEY code is [%d], keyStatus is [%d]\n", __func__, key_info[keyIndex].code, keyStatus);
+            
+            input_report_key(ts_data.input_dev, key_info[keyIndex].code, keyStatus);
+            
+            break;
+        }
+
+
+        default:
+            local_debug(KERN_INFO "%s: Default id[0x%x]\n", __func__, id);
+            
+            break;
+    }
+    
+    return 0;
+}
+
+
+static void mXT224_work_func(struct work_struct *work)
+{
+    u8 track[MXT224_MT_SCAN_POINTS];
+    int index, ret, read_points;
+    struct message_t5 msg_t5_array[MXT224_MT_SCAN_POINTS];
+       
+    local_debug(KERN_INFO "%s\n", __func__);
+    
+    
+    ret = mxt224_i2c_read(ts_data.client, ts_data.obj.msg_t5_addr, 
+                        (u8*)&msg_t5_array[0], sizeof(struct message_t5) * MXT224_MT_SCAN_POINTS);
+       read_points = ret / sizeof(struct message_t5);
+
+       local_debug(KERN_INFO "%s, this time read_points is %d\n", __func__, read_points);
+    mxt224_mem_dbg((u8*)&msg_t5_array[0], sizeof(struct message_t5) * read_points);
+
+       for(index = 0; index < read_points; index++)
+       {
+               if(msg_t5_array[index].report_id == 0xFF) // dirty message, don't process.
+               {
+                       track[index] = 0xFF;
+                       continue;
+               }
+               track[index] = mXT224_get_obj_type(msg_t5_array[index].report_id, id_table, ts_data.obj.table_size);
+
+               if(track[index] == 0){
+                       local_debug(KERN_INFO "%s: Get object type failed!, report id[0x%x]\n", __func__, msg_t5_array[index].report_id);
+                       goto end;
+               }
+               
+               local_debug(KERN_INFO "%s,object's msg type is %d.\n", __func__, track[index]);
+       }
+
+       for(index = 0; index < read_points; index++)
+       {
+               if(track[index] == 0xFF)
+                       continue;
+           mXT224_process_msg(track[index], (u8*)&msg_t5_array[index].body);
+               if(track[index] == track[read_points - 1] || track[read_points - 1] == 0xFF)
+               {
+                   input_sync(ts_data.input_dev);
+                       local_debug(KERN_INFO "%s,input_sync ts_data.input_dev.\n", __func__);
+               }
+       }
+       
+end:
+       enable_irq(ts_data.int_gpio);
+}
+
+
+static int mxt224_i2c_write(struct i2c_client *client, u16 offset,void *buf,int size)
+{
+       unsigned char objectAddr[2+size];
+       int retlen;
+
+       objectAddr[0] = offset & 0x00FF;
+       objectAddr[1] = offset >> 8;
+       memcpy(&objectAddr[2], (char *)buf, size);
+       retlen = i2c_master_normal_send(client, objectAddr,2 + size, 200*1000);
+        
+    return retlen;
+}
+
+static int mxt224_i2c_read(struct i2c_client *client, u16 offset,void *buf,int size)
+{
+       unsigned char objectAddr[2];
+       int retlen;
+
+       if(ts_data.last_read_addr != offset)
+       {
+       ts_data.last_read_addr = offset;
+       objectAddr[0] = offset & 0x00FF;
+       objectAddr[1] = offset >> 8;
+       retlen = i2c_master_normal_send(client, objectAddr,2, 200*1000);
+       if(retlen <= 0)
+               return retlen;
+       }
+       retlen = i2c_master_normal_recv(client, (char *)buf, size, 200*1000);
+       
+       return retlen;
+}
+
+static int mXT224_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+    int     rc;
+    int     index;
+    int     info_size;
+    u32     crc;
+
+       struct message_t5 msg_t5;
+
+        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+                return -EIO;
+        /* Try get GPIO */
+        rc = gpio_request(ts_data.int_gpio, "Touch_int");
+        
+        if(rc)
+        {
+                local_debug(KERN_INFO "%s: Request GPIO failed!\n", __func__);
+                goto failed;
+        }
+
+        rc = gpio_request(ts_data.reset_gpio, "Touch_reset");
+        
+        if(rc)
+        {
+                local_debug(KERN_INFO "%s: Request mXT224 reset GPIO failed!\n", __func__);
+                goto failed;
+        }
+
+     /* store the value */
+    i2c_set_clientdata(client, &ts_data);
+    ts_data.client = client;
+       ts_data.int_gpio= client->irq;
+    //client->driver = &mXT224_driver;  
+
+       ts_data.mxt224_wq = create_rt_workqueue("mxt224_wq");
+       INIT_DELAYED_WORK(&ts_data.work, mXT224_work_func);     
+       
+    /* Reset mXT224 */
+       gpio_pull_updown(ts_data.int_gpio, 1);
+       
+       gpio_direction_output(ts_data.reset_gpio, 0);
+    gpio_set_value(ts_data.reset_gpio, GPIO_LOW);
+    msleep(10);
+    gpio_set_value(ts_data.reset_gpio, GPIO_HIGH);
+    msleep(500);
+
+
+    /* Try get mXT224 table size */
+    
+     rc = mxt224_i2c_read(client, TABLE_SIZE_ADDR, &ts_data.obj.table_size, 1);
+    
+    if(rc <= 0)
+    {
+        local_debug(KERN_INFO "%s: Get table size failed!\n", __func__);
+        goto failed;
+    }
+
+
+    
+    /* Try get mXT224 device info */
+    info_size = CRC_SIZE+ID_INFORMATION_SIZE+ts_data.obj.table_size*OBJECT_TABLE_ELEMENT_SIZE;
+    
+    ts_data.obj.table_info_byte = (u8*)kzalloc(info_size, GFP_KERNEL);
+    
+    if(!ts_data.obj.table_info_byte)
+    {
+        local_debug(KERN_INFO "%s: Can't get memory!\n", __func__);
+        rc = -1;
+        goto failed;
+    }
+    
+    rc = mxt224_i2c_read(client, 0, ts_data.obj.table_info_byte, info_size);
+    
+    if(rc <= 0)
+    {
+        local_debug(KERN_INFO "%s: Get mXT224 info failed!\n", __func__);
+        goto get_info_failed;
+    }
+    
+    ts_data.obj.table_info = (struct mxt224_table_info*)(ts_data.obj.table_info_byte+ID_INFORMATION_SIZE);
+    mxt224_mem_dbg(ts_data.obj.table_info_byte, info_size);
+
+
+#if 0
+    /* Try get and check CRC */
+    ts_data.obj.info_crc = (ts_data.obj.table_info_byte[info_size-3])|
+                           (ts_data.obj.table_info_byte[info_size-2]<<8)|
+                           (ts_data.obj.table_info_byte[info_size-1]<<16);
+    crc = get_crc24(ts_data.obj.table_info_byte, info_size-CRC_SIZE);
+    
+    if(ts_data.obj.info_crc != crc)
+    {
+        //1 TODO: Need set config table
+        
+        local_debug(KERN_INFO "%s:CRC failed, read CRC:[0x%x], get CRC:[0x%x]\n", __func__, ts_data.obj.info_crc, crc);
+        
+        mXT224_load_cfg();
+    }
+
+
+    /* Build cfg CRC */
+    cfg_crc = mXT224_cfg_crc();
+#endif 
+
+
+    /* Build report id table */
+    mXT224_build_report_id_table(ts_data.obj.table_info, ts_data.obj.table_size);
+
+
+    /* Dump mXT224 config setting */
+#ifdef FEATURE_CFG_DUMP
+    
+    local_debug(KERN_INFO "%s: Config size: %d\n", __func__, total_size);
+    
+    cfg_dmup = (u8*)kzalloc(info_size+total_size, GFP_KERNEL);
+    
+    if(!cfg_dmup)
+    {
+        local_debug(KERN_INFO "%s: Cannot get memory!\n", __func__);
+        goto failed;
+    }
+    
+    mxt224_i2c_read(client, 0, cfg_dmup, info_size+total_size);
+    mxt224_mem_dbg(cfg_dmup, info_size+total_size);
+#endif
+
+
+    /* Try get message T5 info */
+    if(gpio_get_value(ts_data.int_gpio))
+    {
+        //1 TODO: Need check touch interrput pin
+        
+        local_debug(KERN_INFO "%s: GPIO status error!\n", __func__);
+        
+        rc = -1;
+        goto failed;
+    }
+
+    ts_data.obj.msg_t5_addr = mXT224_get_obj_addr(0x5, ts_data.obj.table_info, ts_data.obj.table_size);
+    
+    rc = mxt224_i2c_read(client, ts_data.obj.msg_t5_addr, (u8*)&msg_t5, sizeof(struct message_t5));
+    
+    if(rc <= 0)
+    {
+        local_debug(KERN_INFO "%s:Can't get message T5!\n", __func__);
+        goto failed;
+    }
+    
+    mxt224_mem_dbg((u8*)&msg_t5, sizeof(struct message_t5));
+    mXT224_process_msg(mXT224_get_obj_type(msg_t5.report_id, id_table, ts_data.obj.table_size), (u8*)&msg_t5.body);
+    
+    //local_debug(KERN_INFO "%s:Find obj report: 0x%x\n", __func__, 
+    //            mXT224_get_obj_type(msg_t5.report_id, id_table, obj_table_size));
+    msleep(15);
+    
+    if(gpio_get_value(ts_data.int_gpio))
+    {
+        local_debug(KERN_INFO "%s: GPIO value is high\n", __func__);
+    }
+   
+
+    ts_data.input_dev = input_allocate_device();
+    if (!ts_data.input_dev)
+    {
+        rc = -ENOMEM;
+        goto failed;
+    }
+    
+    input_set_drvdata(ts_data.input_dev, &ts_data);
+
+       snprintf(ts_data.phys, sizeof(ts_data.phys),
+                "%s/input0", dev_name(&client->dev));
+
+    ts_data.input_dev->name = "mXT224_touch";
+    ts_data.input_dev->id.bustype = BUS_I2C;
+       ts_data.input_dev->phys = ts_data.phys;
+
+#if 0    
+    set_bit(EV_SYN, ts_data.input_dev->evbit);
+    set_bit(EV_KEY, ts_data.input_dev->evbit);
+    set_bit(BTN_TOUCH, ts_data.input_dev->keybit);
+    set_bit(BTN_2, ts_data.input_dev->keybit);
+    set_bit(EV_ABS, ts_data.input_dev->evbit);
+    
+    input_set_abs_params(ts_data.input_dev, ABS_X, 0, 240, 0, 0);
+    input_set_abs_params(ts_data.input_dev, ABS_Y, 0, 320, 0, 0);
+    
+    for(index=0; index<(sizeof(key_info)/sizeof(key_info[0])); index++)
+     {
+        input_set_capability(ts_data.input_dev, EV_KEY, key_info[index].code);
+    }
+#else
+       ts_data.input_dev->evbit[0] = BIT_MASK(EV_ABS)|BIT_MASK(EV_KEY)|BIT_MASK(EV_SYN);
+       ts_data.input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+       //ts_data.input_dev->keybit[BIT_WORD(BTN_2)] = BIT_MASK(BTN_2); 
+
+    for(index=0; index<(sizeof(key_info)/sizeof(key_info[0])); index++)
+     {
+        input_set_capability(ts_data.input_dev, EV_KEY, key_info[index].code);
+    }
+       input_set_abs_params(ts_data.input_dev, ABS_X, 0, CONFIG_MXT224_MAX_X, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_Y, 0, CONFIG_MXT224_MAX_Y, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_PRESSURE, 0, 255, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_HAT0X, 0, CONFIG_MXT224_MAX_X, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_HAT0Y, 0, CONFIG_MXT224_MAX_Y, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_MT_POSITION_X,0, CONFIG_MXT224_MAX_X, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_MT_POSITION_Y, 0, CONFIG_MXT224_MAX_Y, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+       input_set_abs_params(ts_data.input_dev, ABS_MT_TRACKING_ID, 0, 10, 0, 0);  
+
+#endif
+    rc = input_register_device(ts_data.input_dev);
+    
+    if (rc) 
+    {
+        dev_err(&client->dev, "mXT224: input_register_device rc=%d\n", rc);
+        goto failed;
+    }
+       
+       ts_data.int_gpio = gpio_to_irq(ts_data.int_gpio);
+
+    rc = request_irq(ts_data.int_gpio, mXT224_ts_interrupt,
+                     IRQF_TRIGGER_FALLING, "mXT224_touch", &ts_data);
+       if(rc)
+       {
+               local_debug(KERN_INFO "mXT224 request interrput failed!\n");
+       }else{
+               local_debug(KERN_INFO "mXT224 request interrput successed!\n");
+       }
+
+    
+    return 0;
+
+get_info_failed:
+    /* Free mXT224 info */
+failed:
+
+       if(ts_data.input_dev != NULL)
+       input_free_device(ts_data.input_dev);
+
+#ifdef FEATURE_CFG_DUMP
+       kfree(cfg_dmup);
+#endif
+       kfree(ts_data.obj.table_info_byte);
+
+       if(id_table != NULL)
+       {
+               kfree(id_table);
+               id_table = NULL;
+       }
+
+    return rc;
+}
+
+
+static int __devexit mXT224_remove(struct i2c_client *client)
+{
+       struct mXT224_info *ts = i2c_get_clientdata(client);
+       
+       free_irq(ts->int_gpio, ts);
+       if (cancel_delayed_work_sync(&ts->work)) {
+               /*
+                * Work was pending, therefore we need to enable
+                * IRQ here to balance the disable_irq() done in the
+                * interrupt handler.
+                */
+               enable_irq(ts->int_gpio);
+       }
+
+       input_unregister_device(ts->input_dev);
+       
+       if(id_table != NULL)
+       {
+               kfree(id_table);
+               id_table = NULL;
+       }
+       return 0;
+}
+
+static const struct i2c_device_id mXT224_ts_id[] = {
+    { "mXT224_touch", 0 },
+    { }
+};
+
+MODULE_DEVICE_TABLE(i2c, mXT224_ts_id);
+
+static struct i2c_driver mXT224_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "mXT224_touch"
+       },
+       .id_table       = mXT224_ts_id,
+       .probe          = mXT224_probe,
+       .remove         = __devexit_p(mXT224_remove),
+};
+
+static void __init mXT_init_async(void *unused, async_cookie_t cookie)
+{
+       local_debug("--------> %s <-------------\n",__func__);
+       i2c_add_driver(&mXT224_driver);
+}
+
+
+static int __init mXT_init(void)
+{
+       async_schedule(mXT_init_async, NULL);
+       return 0;
+
+}
+
+static void __exit mXT_exit(void)
+{
+ i2c_del_driver(&mXT224_driver);
+}
+
+
+module_init(mXT_init);
+module_exit(mXT_exit);
+
+MODULE_LICENSE("GPL");
index b68f4b249d0a2e0bcf5273e192136ce989bebe37..02badf554d043810746bcf93e7255b5bf1c806c7 100644 (file)
@@ -293,5 +293,5 @@ source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
 source "drivers/misc/rk29_modem/Kconfig"
 source "drivers/misc/gps/Kconfig"
-
+source "drivers/misc/mpu3050/Kconfig"
 endif # MISC_DEVICES
index 5403037fdca737651b75f5261ad20fed7cc38e39..c545d1c456b4de46a90b13891fc5b0e8517fc535 100644 (file)
@@ -30,4 +30,5 @@ obj-$(CONFIG_WL127X_RFKILL)   += wl127x-rfkill.o
 obj-$(CONFIG_APANIC)           += apanic.o
 obj-$(CONFIG_STE)              += ste.o
 obj-$(CONFIG_RK29_SUPPORT_MODEM)        += rk29_modem/
-obj-$(CONFIG_GPS_GNS7560)                      +=      gps/
\ No newline at end of file
+obj-$(CONFIG_GPS_GNS7560)                      +=      gps/
+obj-y += mpu3050/
diff --git a/drivers/misc/mpu3050/Kconfig b/drivers/misc/mpu3050/Kconfig
new file mode 100644 (file)
index 0000000..69ee202
--- /dev/null
@@ -0,0 +1,188 @@
+\r
+menu "Motion Sensors Support"\r
+\r
+choice\r
+    tristate "Motion Processing Unit"\r
+    depends on I2C\r
+    default MPU_NONE\r
+\r
+config MPU_NONE\r
+    bool "None"\r
+    help\r
+      This disables support for motion processing using the MPU family of \r
+      motion processing units.\r
+\r
+config SENSORS_MPU3050\r
+    tristate "MPU3050"\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_MPU6000\r
+    tristate "MPU6000"\r
+    depends on I2C\r
+    help\r
+      If you say yes here you get support for the MPU6000 Gyroscope driver\r
+      This driver can also be built as a module.  If so, the module\r
+      will be called mpu6000.\r
+\r
+endchoice\r
+\r
+choice\r
+    prompt "Accelerometer Type"\r
+    depends on SENSORS_MPU3050\r
+    default SENSORS_BMA150\r
+\r
+config SENSORS_ACCELEROMETER_NONE\r
+    bool "NONE"\r
+    depends on SENSORS_MPU3050 || SENSORS_MPU6000\r
+    help\r
+      This disables accelerometer support for the MPU3050\r
+\r
+config SENSORS_ADXL346\r
+    bool "ADI adxl346"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the ADI adxl346 accelerometer\r
+\r
+config SENSORS_BMA150\r
+    bool "Bosch BMA150"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Bosch BMA150 accelerometer\r
\r
+config SENSORS_BMA222\r
+    bool "Bosch BMA222"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Bosch BMA222 accelerometer\r
+      \r
+config SENSORS_KXSD9\r
+    bool "Kionix KXSD9"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Kionix KXSD9 accelerometer\r
+\r
+config SENSORS_KXTF9\r
+    bool "Kionix KXTF9"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Kionix KXFT9 accelerometer\r
+\r
+config SENSORS_LIS331DLH\r
+    bool "ST lis331dlh"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the ST lis331dlh accelerometer\r
+\r
+config SENSORS_LSM303DLHA\r
+    bool "ST lsm303dlh"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the ST lsm303dlh accelerometer\r
+\r
+config SENSORS_MMA8450\r
+    bool "Freescale mma8450"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Freescale mma8450 accelerometer\r
+\r
+config SENSORS_MMA8451\r
+    bool "Freescale mma8451"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Freescale mma8451 accelerometer\r
+\r
+endchoice\r
+\r
+choice\r
+    prompt "Compass Type"\r
+    depends on SENSORS_MPU6000 || SENSORS_MPU3050\r
+    default SENSORS_AK8975\r
+\r
+config SENSORS_COMPASS_NONE\r
+    bool "NONE"\r
+    depends on SENSORS_MPU6000 || SENSORS_MPU3050\r
+    help\r
+      This disables compass support for the MPU6000\r
+\r
+config SENSORS_AK8975\r
+    bool "AKM ak8975"\r
+    depends on SENSORS_MPU6000 || SENSORS_MPU3050\r
+    help\r
+      This enables support for the AKM ak8975 compass\r
+\r
+config SENSORS_MMC314X\r
+    bool "MEMSIC mmc314x"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the MEMSIC mmc314x compass\r
+\r
+config SENSORS_AMI30X\r
+    bool "Aichi Steel ami30X"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Aichi Steel ami304/ami305 compass\r
+\r
+config SENSORS_HMC5883\r
+    bool "Honeywell hmc5883"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Honeywell hmc5883 compass\r
+\r
+config SENSORS_LSM303DLHM\r
+    bool "ST lsm303dlh"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the ST lsm303dlh compass\r
+\r
+config SENSORS_MMC314X\r
+    bool "MEMSIC mmc314xMS"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the MEMSIC mmc314xMS compass\r
+\r
+config SENSORS_YAS529\r
+    bool "Yamaha yas529"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Yamaha yas529 compass\r
+\r
+config SENSORS_HSCDTD00XX\r
+    bool "Alps hscdtd00XX"\r
+    depends on SENSORS_MPU3050\r
+    help\r
+      This enables support for the Alps hscdtd002b/hscdtd004a compass\r
+\r
+endchoice\r
+\r
+choice\r
+    prompt "Pressure Type"\r
+    depends on SENSORS_MPU6000 || SENSORS_MPU3050\r
+    default SENSORS_BMA085\r
+\r
+config SENSORS_PRESSURE_NONE\r
+    bool "NONE"\r
+    depends on SENSORS_MPU6000 || SENSORS_MPU3050\r
+    help\r
+      This disables pressure sensor support for the MPU6000\r
+\r
+config SENSORS_BMA085\r
+    bool "Bosch BMA085"\r
+    depends on SENSORS_MPU6000 || SENSORS_MPU3050\r
+    help\r
+      This enables support for the Bosch bma085 pressure sensor\r
+\r
+endchoice\r
+\r
+config SENSORS_MPU_DEBUG\r
+    bool "MPU debug"\r
+    depends on SENSORS_MPU3050 || SENSORS_MPU6000\r
+    help\r
+      If you say yes here you get extra debug messages from the MPU3050\r
+      and other slave sensors.\r
+\r
+endmenu\r
+\r
diff --git a/drivers/misc/mpu3050/Makefile b/drivers/misc/mpu3050/Makefile
new file mode 100644 (file)
index 0000000..5114e43
--- /dev/null
@@ -0,0 +1,117 @@
+\r
+# Kernel makefile for motions sensors\r
+#\r
+# \r
+\r
+# MPU\r
+obj-$(CONFIG_SENSORS_MPU3050)  += mpu3050.o\r
+mpu3050-objs += mpuirq.o \\r
+       slaveirq.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_ADXL346\r
+mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_BMA150\r
+mpu3050-objs += $(MLLITE_DIR)accel/bma150.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_BMA222\r
+mpu3050-objs += $(MLLITE_DIR)accel/bma222.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_KXSD9\r
+mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_KXTF9\r
+mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_LIS331DLH\r
+mpu3050-objs += $(MLLITE_DIR)accel/lis331.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_LSM303DLHA\r
+mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_MMA8450\r
+mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_MMA8451\r
+mpu3050-objs += $(MLLITE_DIR)accel/mma8451.o\r
+endif\r
+\r
+#\r
+# Compass options\r
+#\r
+ifdef CONFIG_SENSORS_AK8975\r
+mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_AMI30X\r
+mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_HMC5883\r
+mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_LSM303DLHM\r
+mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_MMC314X\r
+mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_YAS529\r
+mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_HSCDTD00XX\r
+mpu3050-objs += $(MLLITE_DIR)compass/hscdtd00xx.o\r
+endif\r
+\r
+#\r
+# Pressure options\r
+#\r
+ifdef CONFIG_SENSORS_BMA085\r
+mpu3050-objs += $(MLLITE_DIR)pressure/bma085.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_MPU_DEBUG\r
+EXTRA_CFLAGS += -DDEBUG \r
+endif\r
+\r
+obj-$(CONFIG_SENSORS_MPU6000)= mpu6000.o\r
+mpu6000-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
+       $(MLLITE_DIR)accel/mantis.o\r
+\r
+ifdef CONFIG_SENSORS_AK8975\r
+mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o\r
+endif\r
+\r
+ifdef CONFIG_SENSORS_MPU6000\r
+EXTRA_CFLAGS += -DM_HW\r
+endif\r
diff --git a/drivers/misc/mpu3050/README b/drivers/misc/mpu3050/README
new file mode 100644 (file)
index 0000000..2734dc1
--- /dev/null
@@ -0,0 +1,250 @@
+Kernel driver mpu\r
+=====================\r
+\r
+Supported chips:\r
+  * InvenSense IMU3050\r
+    Prefix: 'mpu3050'\r
+    Datasheet:\r
+        PS-MPU-3000A-00.2.4b.pdf\r
+\r
+  * InvenSense IMU6000\r
+    Prefix: 'mpu6000'\r
+    Datasheet:\r
+        MPU-6000A-00 v1.0.pdf\r
+\r
+Author: InvenSense <http://invensense.com>\r
+\r
+Description\r
+-----------\r
+The mpu is a motion processor unit that controls the mpu3050 gyroscope, a slave\r
+accelerometer, a compass and a pressure sensor, or the mpu6000 and slave \r
+compass.  This document describes how to install the driver into a Linux kernel\r
+and a small note about how to set up the file permissions in an android file\r
+system.\r
+\r
+Sysfs entries\r
+-------------\r
+/dev/mpu\r
+/dev/mpuirq\r
+/dev/accelirq\r
+/dev/compassirq\r
+/dev/pressureirq\r
+\r
+General Remarks MPU3050\r
+-----------------------\r
+* Valid addresses for the MPU3050 is 0x68.\r
+* Accelerometer must be on the secondary I2C bus for MPU3050, the \r
+  magnetometer must be on the primary bus and pressure sensor must\r
+  be on the primary bus.\r
+\r
+General Remarks MPU6000\r
+-----------------------\r
+* Valid addresses for the MPU6000 is 0x68.\r
+* Magnetometer must be on the secondary I2C bus for the MPU6000.\r
+* Accelerometer slave address must be set to 0x68\r
+* Gyro and Accel orientation matrices should be the same\r
+\r
+Programming the chip using /dev/mpu\r
+----------------------------------\r
+Programming of MPU3050 or MPU6000 is done by first opening the /dev/mpu file and\r
+then performing a series of IOCTLS on the handle returned.  The IOCTL codes can\r
+be found in mpu.h.  Typically this is done by the mllite library in user\r
+space.\r
+\r
+Adding to a Kernel\r
+==================\r
+\r
+The mpu driver is designed to be inserted in the drivers/misc part of the \r
+kernel.  Extracting the tarball from the root kernel dir will place the\r
+contents of the tarball here:\r
+\r
+    <kernel root dir>/drivers/misc/mpu3050\r
+    <kernel root dir>/include/linux/mpu.h\r
+    <kernel root dir>/include/linux/mpu3050.h\r
+    <kernel root dir>/include/linux/mpu6000.h\r
+\r
+After this is done the drivers/misc/Kconfig must be edited to add the line:\r
+\r
+    source "drivers/misc/mpu3050/Kconfig"\r
+\r
+Similarly drivers/misc/Makefile must be edited to add the line:\r
+\r
+    obj-y += mpu3050/\r
+\r
+Configuration can then be done as normal.\r
+\r
+NOTE: This driver depends on a kernel patch to drivers/char/char.c.  This patch\r
+started to be included in most 2.6.35 based kernels.\r
+drivers: misc: pass miscdevice pointer via file private data\r
+https://patchwork.kernel.org/patch/96412/\r
+\r
+---\r
+ drivers/char/misc.c |    1 +\r
+ 1 files changed, 1 insertions(+), 0 deletions(-)\r
+\r
+\r
+diff --git a/drivers/char/misc.c b/drivers/char/misc.c\r
+index 92ab03d..cd650ca 100644\r
+--- a/drivers/char/misc.c\r
++++ b/drivers/char/misc.c\r
+@@ -144,6 +144,7 @@ static int misc_open(struct inode * inode, struct file * file)\r
+       old_fops = file->f_op;\r
+       file->f_op = new_fops;\r
+       if (file->f_op->open) {\r
++              file->private_data = c;\r
+               err=file->f_op->open(inode,file);\r
+               if (err) {\r
+                       fops_put(file->f_op);\r
+---\r
+\r
+Board and Platform Data\r
+-----------------------\r
+\r
+In order for the driver to work, board and platform data specific to the device\r
+needs to be added to the board file.  A mpu3050_platform_data structure must\r
+be created and populated and set in the i2c_board_info_structure.  For details\r
+of each structure member see mpu.h.  All values below are simply an example and\r
+should be modified for your platform.\r
+\r
+#include <linux/mpu.h>\r
+\r
+#if defined(CONFIG_SENSORS_MPU3050) || defined(CONFIG_SENSORS_MPU3050_MODULE)\r
+\r
+#define SENSOR_MPU_NAME "mpu3050"\r
+\r
+static struct mpu3050_platform_data mpu_data = {\r
+       .int_config  = 0x10,\r
+       .orientation = {  -1,  0,  0, \r
+                          0,  1,  0, \r
+                          0,  0, -1 },\r
+       /* accel */\r
+       .accel = {\r
+#ifdef CONFIG_SENSORS_MPU3050_MODULE\r
+                .get_slave_descr = NULL,\r
+#else\r
+                .get_slave_descr = get_accel_slave_descr,\r
+#endif\r
+                .adapt_num   = 2,\r
+                .bus         = EXT_SLAVE_BUS_SECONDARY,\r
+                .address     = 0x0F,\r
+                .orientation = {  -1,  0,  0, \r
+                                   0,  1,  0, \r
+                                   0,  0, -1 },\r
+        },\r
+       /* compass */\r
+       .compass = {\r
+#ifdef CONFIG_SENSORS_MPU3050_MODULE\r
+                .get_slave_descr = NULL,\r
+#else\r
+                .get_slave_descr = get_compass_slave_descr,\r
+#endif\r
+                .adapt_num   = 2,\r
+                .bus         = EXT_SLAVE_BUS_PRIMARY,\r
+                .address     = 0x0E,\r
+                .orientation = { 1, 0, 0, \r
+                                 0, 1, 0, \r
+                                 0, 0, 1 },\r
+        },\r
+       /* pressure */\r
+       .pressure = {\r
+#ifdef CONFIG_SENSORS_MPU3050_MODULE\r
+                .get_slave_descr = NULL,\r
+#else\r
+                .get_slave_descr = get_pressure_slave_descr,\r
+#endif\r
+                .adapt_num   = 2,\r
+                .bus         = EXT_SLAVE_BUS_PRIMARY,\r
+                .address     = 0x77,\r
+                .orientation = { 1, 0, 0, \r
+                                 0, 1, 0, \r
+                                 0, 0, 1 },\r
+        },\r
+};\r
+#endif\r
+\r
+#if defined(CONFIG_SENSORS_MPU6000) || defined(CONFIG_SENSORS_MPU6000_MODULE)\r
+\r
+#define SENSOR_MPU_NAME "mpu6000"\r
+\r
+static struct mpu3050_platform_data mpu_data = {\r
+       .int_config  = 0x10,\r
+       .orientation = {  -1,  0,  0,\r
+                          0,  1,  0,\r
+                          0,  0, -1 },\r
+       /* accel */\r
+       .accel = {\r
+#ifdef CONFIG_SENSORS_MPU6000_MODULE\r
+                .get_slave_descr = NULL,\r
+#else\r
+                .get_slave_descr = get_accel_slave_descr,\r
+#endif\r
+                .adapt_num   = 2,\r
+                .bus         = EXT_SLAVE_BUS_PRIMARY,\r
+                .address     = 0x68,\r
+                .orientation = {  -1,  0,  0,\r
+                                   0,  1,  0,\r
+                                   0,  0, -1 },\r
+        },\r
+       /* compass */\r
+       .compass = {\r
+#ifdef CONFIG_SENSORS_MPU6000_MODULE\r
+                .get_slave_descr = NULL,\r
+#else\r
+                .get_slave_descr = get_compass_slave_descr,\r
+#endif\r
+                .adapt_num   = 2,\r
+                .bus         = EXT_SLAVE_BUS_SECONDARY,\r
+                .address     = 0x0E,\r
+                .orientation = { 1, 0, 0,\r
+                                 0, 1, 0,\r
+                                 0, 0, 1 },\r
+        },\r
+       /* pressure */\r
+       .pressure = {\r
+#ifdef CONFIG_SENSORS_MPU6000_MODULE\r
+                .get_slave_descr = NULL,\r
+#else\r
+                .get_slave_descr = get_pressure_slave_descr,\r
+#endif\r
+                .adapt_num   = 2,\r
+                .bus         = EXT_SLAVE_BUS_PRIMARY,\r
+                .address     = 0x77,\r
+                .orientation = { 1, 0, 0, \r
+                                 0, 1, 0, \r
+                                 0, 0, 1 },\r
+        },\r
+\r
+};\r
+#endif\r
+\r
+static struct i2c_board_info __initdata beagle_i2c_2_boardinfo[] = {\r
+       {\r
+               I2C_BOARD_INFO(SENSOR_MPU_NAME, 0x68),\r
+               .irq = (IH_GPIO_BASE + MPU_GPIO_IRQ),\r
+               .platform_data = &mpu_data,\r
+       },\r
+};\r
+\r
+Typically the IRQ is a GPIO input pin and needs to be configured properly.  If\r
+in the above example GPIO 168 corresponds to IRQ 299, the following should be\r
+done as well:\r
+\r
+#define MPU_GPIO_IRQ 168\r
+\r
+    gpio_request(MPU_GPIO_IRQ,"MPUIRQ");\r
+    gpio_direction_input(MPU_GPIO_IRQ)\r
+\r
+\r
+Android File Permissions\r
+========================\r
+\r
+To set up the file permissions on an android system, the /dev/mpu and \r
+/dev/mpuirq files needs to be added to the system/core/init/devices.c file \r
+inside the perms_ structure.\r
+\r
+static struct perms_ devperms[] = {\r
+    { "/dev/mpu"           ,0640,   AID_SYSTEM,    AID_SYSTEM,     1 },\r
+};\r
+\r
+Sufficient file permissions need to be give to read and write it by the system.\r
+\r
diff --git a/drivers/misc/mpu3050/accel/adxl346.c b/drivers/misc/mpu3050/accel/adxl346.c
new file mode 100644 (file)
index 0000000..2f76313
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   adxl346.c
+ *      @brief  Accelerometer setup and handling methods for AD adxl346.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+#define ACCEL_ADI346_SLEEP_REG      (0x2D)
+#define ACCEL_ADI346_SLEEP_MASK     (0x04)
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int adxl346_suspend(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address,
+                          ACCEL_ADI346_SLEEP_REG, 1, &reg);
+       ERROR_CHECK(result);
+       reg |= ACCEL_ADI346_SLEEP_MASK;
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_ADI346_SLEEP_REG, reg);
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register & mask */
+#define ACCEL_ADI346_CTRL_REG      (0x31)
+#define ACCEL_ADI346_CTRL_MASK     (0x03)
+
+int adxl346_resume(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address,
+                          ACCEL_ADI346_SLEEP_REG, 1, &reg);
+       ERROR_CHECK(result);
+       reg &= ~ACCEL_ADI346_SLEEP_MASK;
+       /*wake up if sleeping */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      ACCEL_ADI346_SLEEP_REG, reg);
+       ERROR_CHECK(result);
+       /*MLOSSleep(10) */
+
+       /* Full Scale */
+       reg = 0x04;
+       reg &= ~ACCEL_ADI346_CTRL_MASK;
+       if (slave->range.mantissa == 4)
+               reg |= 0x1;
+       else if (slave->range.mantissa == 8)
+               reg |= 0x2;
+       else if (slave->range.mantissa == 16)
+               reg |= 0x3;
+       else {
+               slave->range.mantissa = 2;
+               reg |= 0x0;
+       }
+       slave->range.fraction = 0;
+
+       /* DATA_FORMAT: full resolution of +/-2g; data is left justified */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x31, reg);
+       ERROR_CHECK(result);
+       /* BW_RATE: normal power operation with output data rate of 200Hz */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x2C, 0x0B);
+       ERROR_CHECK(result);
+       /* POWER_CTL: power on in measurement mode */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x2D, 0x28);
+       ERROR_CHECK(result);
+       /*--- after wake up, it takes at least [1/(data rate) + 1.1]ms ==>
+         6.1ms to get valid sensor data ---*/
+       MLOSSleep(10);
+
+       return result;
+}
+
+int adxl346_read(void *mlsl_handle,
+                struct ext_slave_descr *slave,
+                struct ext_slave_platform_data *pdata,
+                unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+struct ext_slave_descr adxl346_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ adxl346_suspend,
+       /*.resume           = */ adxl346_resume,
+       /*.read             = */ adxl346_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "adx1346",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_ADI346,
+       /*.reg              = */ 0x32,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *adxl346_get_slave_descr(void)
+{
+       return &adxl346_descr;
+}
+EXPORT_SYMBOL(adxl346_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/bma150.c b/drivers/misc/mpu3050/accel/bma150.c
new file mode 100644 (file)
index 0000000..f5e99d1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   bma150.c
+ *      @brief  Accelerometer setup and handling methods.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlos.h"
+#include "mlsl.h"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*********************************************
+    Accelerometer Initialization Functions
+**********************************************/
+
+static int bma150_suspend(void *mlsl_handle,
+                         struct ext_slave_descr *slave,
+                         struct ext_slave_platform_data *pdata)
+{
+       int result;
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0a, 0x01);
+       MLOSSleep(3); /* 3 ms powerup time maximum */
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register and mask */
+#define ACCEL_BOSCH_CTRL_REG       (0x14)
+#define ACCEL_BOSCH_CTRL_MASK      (0x18)
+
+static int bma150_resume(void *mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg = 0;
+
+       /* Soft reset */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0a, 0x02);
+       ERROR_CHECK(result);
+       MLOSSleep(10);
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, 0x14, 1, &reg);
+       ERROR_CHECK(result);
+
+       /* Bandwidth */
+       reg &= 0xc0;
+       reg |= 3;               /* 3=190 Hz */
+
+       /* Full Scale */
+       reg &= ~ACCEL_BOSCH_CTRL_MASK;
+       if (slave->range.mantissa == 4)
+               reg |= 0x08;
+       else if (slave->range.mantissa == 8)
+               reg |= 0x10;
+       else {
+               slave->range.mantissa = 2;
+               reg |= 0x00;
+       }
+       slave->range.fraction = 0;
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x14, reg);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+static int bma150_read(void *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 bma150_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ bma150_suspend,
+       /*.resume           = */ bma150_resume,
+       /*.read             = */ bma150_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "bma150",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_BMA150,
+       /*.reg              = */ 0x02,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *bma150_get_slave_descr(void)
+{
+       return &bma150_descr;
+}
+EXPORT_SYMBOL(bma150_get_slave_descr);
+
+#ifdef __KERNEL__
+MODULE_AUTHOR("Invensense");
+MODULE_DESCRIPTION("User space IRQ handler for MPU3xxx devices");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("bma");
+#endif
+
+/**
+ *  @}
+ */
diff --git a/drivers/misc/mpu3050/accel/bma222.c b/drivers/misc/mpu3050/accel/bma222.c
new file mode 100644 (file)
index 0000000..bd0c87c
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/*
+ *  @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   bma222.c
+ *      @brief  Accelerometer setup and handling methods.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlos.h"
+#include "mlsl.h"
+
+#define ACCEL_BMA222_RANGE_REG          (0x0F)
+#define ACCEL_BMA222_BW_REG             (0x10)
+#define ACCEL_BMA222_SUSPEND_REG        (0x11)
+#define ACCEL_BMA222_SFT_RST_REG        (0x14)
+
+/*********************************************
+    Accelerometer Initialization Functions
+**********************************************/
+
+static int bma222_suspend(void *mlsl_handle,
+                         struct ext_slave_descr *slave,
+                         struct ext_slave_platform_data *pdata)
+{
+       int result;
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_BMA222_SUSPEND_REG, 0x80);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+static int bma222_resume(void *mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg = 0;
+
+       /* Soft reset */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_BMA222_SFT_RST_REG, 0xB6);
+       ERROR_CHECK(result);
+       MLOSSleep(10);
+
+       /*Bandwidth */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_BMA222_BW_REG, 0x0C);
+       ERROR_CHECK(result);
+
+       /* Full Scale */
+       if (slave->range.mantissa == 4)
+               reg |= 0x05;
+       else if (slave->range.mantissa == 8)
+               reg |= 0x08;
+       else if (slave->range.mantissa == 16)
+               reg |= 0x0C;
+       else {
+               slave->range.mantissa = 2;
+               reg |= 0x03;
+       }
+       slave->range.fraction = 0;
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_BMA222_RANGE_REG, reg);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+static int bma222_read(void *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 bma222_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ bma222_suspend,
+       /*.resume           = */ bma222_resume,
+       /*.read             = */ bma222_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "bma222",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_BMA222,
+       /*.reg              = */ 0x02,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *bma222_get_slave_descr(void)
+{
+       return &bma222_descr;
+}
+EXPORT_SYMBOL(bma222_get_slave_descr);
+
+/*
+ *  @}
+ */
diff --git a/drivers/misc/mpu3050/accel/cma3000.c b/drivers/misc/mpu3050/accel/cma3000.c
new file mode 100644 (file)
index 0000000..8c6b3c8
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   cma3000.c
+ *      @brief  Accelerometer setup and handling methods for VTI CMA3000
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+#include "accel.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int cma3000_suspend(void *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;
+}
+
+int cma3000_resume(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+
+
+       return ML_SUCCESS;
+}
+
+int cma3000_read(void *mlsl_handle,
+                struct ext_slave_descr *slave,
+                struct ext_slave_platform_data *pdata,
+                unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+struct ext_slave_descr cma3000_descr = {
+       /*.suspend          = */ cma3000_suspend,
+       /*.resume           = */ cma3000_resume,
+       /*.read             = */ cma3000_read,
+       /*.name             = */ "cma3000",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ID_INVALID,
+       /* fixme - id to added when support becomes available */
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ 65536,
+};
+
+struct ext_slave_descr *cma3000_get_slave_descr(void)
+{
+       return &cma3000_descr;
+}
+EXPORT_SYMBOL(cma3000_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/kxsd9.c b/drivers/misc/mpu3050/accel/kxsd9.c
new file mode 100644 (file)
index 0000000..10ed3b2
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   kxsd9.c
+ *      @brief  Accelerometer setup and handling methods.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/module.h>
+#endif
+
+#include "mpu.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 kxsd9_suspend(void *mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata)
+{
+       int result;
+       (void *) slave;
+       /* CTRL_REGB: low-power standby mode */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0d, 0x0);
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register and mask */
+#define ACCEL_KIONIX_CTRL_REG      (0x0C)
+#define ACCEL_KIONIX_CTRL_MASK     (0x3)
+
+static int kxsd9_resume(void *mlsl_handle,
+                       struct ext_slave_descr *slave,
+                       struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       /* Full Scale */
+       reg = 0x0;
+       reg &= ~ACCEL_KIONIX_CTRL_MASK;
+       reg |= 0x00;
+       if (slave->range.mantissa == 4) {       /* 4g scale = 4.9951 */
+               reg |= 0x2;
+               slave->range.fraction = 9951;
+       } else if (slave->range.mantissa == 7) { /* 6g scale = 7.5018 */
+               reg |= 0x1;
+               slave->range.fraction = 5018;
+       } else if (slave->range.mantissa == 9) {        /* 8g scale = 9.9902 */
+               reg |= 0x0;
+               slave->range.fraction = 9902;
+       } else {
+               slave->range.mantissa = 2; /* 2g scale = 2.5006 */
+               slave->range.fraction = 5006;
+               reg |= 0x3;
+       }
+       reg |= 0xC0;            /* 100Hz LPF */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_KIONIX_CTRL_REG, reg);
+       ERROR_CHECK(result);
+       /* normal operation */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0d, 0x40);
+       ERROR_CHECK(result);
+
+       return ML_SUCCESS;
+}
+
+static int kxsd9_read(void *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 kxsd9_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ kxsd9_suspend,
+       /*.resume           = */ kxsd9_resume,
+       /*.read             = */ kxsd9_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "kxsd9",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_KXSD9,
+       /*.reg              = */ 0x00,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {2, 5006},
+};
+
+struct ext_slave_descr *kxsd9_get_slave_descr(void)
+{
+       return &kxsd9_descr;
+}
+EXPORT_SYMBOL(kxsd9_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/kxtf9.c b/drivers/misc/mpu3050/accel/kxtf9.c
new file mode 100644 (file)
index 0000000..9eae342
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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 "mpu.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(void *mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata)
+{
+       int result;
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0);
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register and mask */
+#define ACCEL_KIONIX_CTRL_REG      (0x1b)
+#define ACCEL_KIONIX_CTRL_MASK     (0x18)
+
+static int kxtf9_resume(void *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);
+       ERROR_CHECK(result);
+       MLOSSleep(10);
+       /* Wake up */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, 0x42);
+       ERROR_CHECK(result);
+       /* INT_CTRL_REG1: */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1e, 0x14);
+       ERROR_CHECK(result);
+       /* WUF_THRESH: */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x5a, 0x00);
+       ERROR_CHECK(result);
+       /* DATA_CTRL_REG */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x04);
+       ERROR_CHECK(result);
+       /* WUF_TIMER */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x29, 0x02);
+       ERROR_CHECK(result);
+
+       /* Full Scale */
+       reg = 0xc2;
+       reg &= ~ACCEL_KIONIX_CTRL_MASK;
+       reg |= 0x00;
+       if (slave->range.mantissa == 4)
+               reg |= 0x08;
+       else if (slave->range.mantissa == 8)
+               reg |= 0x10;
+       else {
+               slave->range.mantissa = 2;
+               reg |= 0x00;
+       }
+       slave->range.fraction = 0;
+
+       /* Normal operation  */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x1b, reg);
+       ERROR_CHECK(result);
+       MLOSSleep(50);
+
+       return ML_SUCCESS;
+}
+
+static int kxtf9_read(void *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 = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ kxtf9_suspend,
+       /*.resume           = */ kxtf9_resume,
+       /*.read             = */ kxtf9_read,
+       /*.config           = */ NULL,
+       /*.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;
+}
+EXPORT_SYMBOL(kxtf9_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/lis331.c b/drivers/misc/mpu3050/accel/lis331.c
new file mode 100644 (file)
index 0000000..b98dbc6
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   lis331.c
+ *      @brief  Accelerometer setup and handling methods for ST LIS331
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+/* full scale setting - register & mask */
+#define LIS331_CTRL_REG1         (0x20)
+#define LIS331_CTRL_REG2         (0x21)
+#define LIS331_CTRL_REG3         (0x22)
+#define LIS331_CTRL_REG4         (0x23)
+#define LIS331_CTRL_REG5         (0x24)
+#define LIS331_HP_FILTER_RESET   (0x25)
+#define LIS331_REFERENCE         (0x26)
+#define LIS331_STATUS_REG        (0x27)
+#define LIS331_OUT_X_L           (0x28)
+#define LIS331_OUT_X_H           (0x29)
+#define LIS331_OUT_Y_L           (0x2a)
+#define LIS331_OUT_Y_H           (0x2b)
+#define LIS331_OUT_Z_L           (0x2b)
+#define LIS331_OUT_Z_H           (0x2d)
+
+#define LIS331_INT1_CFG          (0x30)
+#define LIS331_INT1_SRC          (0x31)
+#define LIS331_INT1_THS          (0x32)
+#define LIS331_INT1_DURATION     (0x33)
+
+#define LIS331_INT2_CFG          (0x34)
+#define LIS331_INT2_SRC          (0x35)
+#define LIS331_INT2_THS          (0x36)
+#define LIS331_INT2_DURATION     (0x37)
+
+#define LIS331_CTRL_MASK         (0x30)
+#define LIS331_SLEEP_MASK        (0x20)
+
+#define LIS331_MAX_DUR (0x7F)
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+struct lis331dlh_config {
+       unsigned int odr;
+       unsigned int fsr; /* full scale range mg */
+       unsigned int ths; /* Motion no-motion thseshold mg */
+       unsigned int dur; /* Motion no-motion duration ms */
+       unsigned char reg_ths;
+       unsigned char reg_dur;
+       unsigned char ctrl_reg1;
+};
+
+struct lis331dlh_private_data {
+       struct lis331dlh_config suspend;
+       struct lis331dlh_config resume;
+};
+
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+void lis331dlh_set_ths(struct lis331dlh_config *config,
+               long ths)
+{
+       if ((unsigned int) ths > 1000 * config->fsr)
+               ths = (long) 1000 * config->fsr;
+
+       if (ths < 0)
+               ths = 0;
+
+       config->ths = ths;
+       config->reg_ths = (unsigned char)(long)((ths * 128L) / (config->fsr));
+       MPL_LOGD("THS: %d, 0x%02x\n", config->ths, (int)config->reg_ths);
+}
+
+void lis331dlh_set_dur(struct lis331dlh_config *config,
+               long dur)
+{
+       long reg_dur = (dur * config->odr) / 1000000L;
+       config->dur = dur;
+
+       if (reg_dur > LIS331_MAX_DUR)
+               reg_dur = LIS331_MAX_DUR;
+
+       config->reg_dur = (unsigned char) reg_dur;
+       MPL_LOGD("DUR: %d, 0x%02x\n", config->dur, (int)config->reg_dur);
+}
+
+/**
+ * Set the Output data rate for the particular configuration
+ *
+ * @param config Config to modify with new ODR
+ * @param odr Output data rate in units of 1/1000Hz
+ */
+static void lis331dlh_set_odr(
+       struct lis331dlh_config *config,
+       long odr)
+{
+       unsigned char bits;
+
+       if (odr > 400000) {
+               config->odr = 1000000;
+               bits = 0x38;
+       } else if (odr > 100000) {
+               config->odr = 400000;
+               bits = 0x30;
+       } else if (odr > 50000) {
+               config->odr = 100000;
+               bits = 0x28;
+       } else if (odr > 10000) {
+               config->odr = 50000;
+               bits = 0x20;
+       } else if (odr > 5000) {
+               config->odr = 10000;
+               bits = 0xC0;
+       } else if (odr > 2000) {
+               config->odr = 5000;
+               bits = 0xB0;
+       } else if (odr > 1000) {
+               config->odr = 2000;
+               bits = 0x80;
+       } else if (odr > 500) {
+               config->odr = 1000;
+               bits = 0x60;
+       } else if (odr > 0) {
+               config->odr = 500;
+               bits = 0x40;
+       } else {
+               config->odr = 0;
+               bits = 0;
+       }
+
+       config->ctrl_reg1 = bits | (config->ctrl_reg1 & 0x7);
+       lis331dlh_set_dur(config, config->dur);
+       MPL_LOGD("ODR: %d, 0x%02x\n", config->odr, (int)config->ctrl_reg1);
+}
+
+static void lis331dlh_set_fsr(
+       struct lis331dlh_config *config,
+       long fsr)
+{
+       if (fsr <= 2048)
+               config->fsr = 2048;
+       else if (fsr <= 4096)
+               config->fsr = 4096;
+       else
+               config->fsr = 8192;
+
+       lis331dlh_set_ths(config, config->ths);
+       MPL_LOGD("FSR: %d\n", config->fsr);
+}
+
+int lis331dlh_suspend(void *mlsl_handle,
+                     struct ext_slave_descr *slave,
+                     struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+       struct lis331dlh_private_data *private_data = pdata->private_data;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG1,
+                                      private_data->suspend.ctrl_reg1);
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG2, 0x0f);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG3, 0x00);
+       reg = 0x40;
+       if (private_data->suspend.fsr == 8192)
+               reg |= 0x30;
+       else if (private_data->suspend.fsr == 4096)
+               reg |= 0x10;
+       /* else bits [4..5] are already zero */
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG4, reg);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_INT1_THS,
+                                      private_data->suspend.reg_ths);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_INT1_DURATION,
+                                      private_data->suspend.reg_dur);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_INT1_CFG, 0x2a);
+       result = MLSLSerialRead(mlsl_handle, pdata->address,
+                               LIS331_HP_FILTER_RESET, 1, &reg);
+       return result;
+}
+
+int lis331dlh_resume(void *mlsl_handle,
+                    struct ext_slave_descr *slave,
+                    struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+       struct lis331dlh_private_data *private_data = pdata->private_data;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG1,
+                                      private_data->resume.ctrl_reg1);
+       ERROR_CHECK(result);
+       MLOSSleep(6);
+
+       /* Full Scale */
+       reg = 0x40;
+       reg &= ~LIS331_CTRL_MASK;
+       if (private_data->resume.fsr == 8192)
+               reg |= 0x30;
+       else if (private_data->resume.fsr == 4096)
+               reg |= 0x10;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG4, reg);
+       ERROR_CHECK(result);
+
+       /* Configure high pass filter */
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG2, 0x0F);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_CTRL_REG3, 0x00);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_INT1_THS, 0x02);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_INT1_DURATION, 0x7F);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      LIS331_INT1_CFG, 0x95);
+       ERROR_CHECK(result);
+       result = MLSLSerialRead(mlsl_handle, pdata->address,
+                               LIS331_HP_FILTER_RESET, 1, &reg);
+       ERROR_CHECK(result);
+       return result;
+}
+
+int lis331dlh_read(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata,
+                  unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+static int lis331dlh_init(void *mlsl_handle,
+                         struct ext_slave_descr *slave,
+                         struct ext_slave_platform_data *pdata)
+{
+       struct lis331dlh_private_data *private_data;
+       private_data = (struct lis331dlh_private_data *)
+               MLOSMalloc(sizeof(struct lis331dlh_private_data));
+
+       if (!private_data)
+               return ML_ERROR_MEMORY_EXAUSTED;
+
+       pdata->private_data = private_data;
+
+       private_data->resume.ctrl_reg1 = 0x37;
+       private_data->suspend.ctrl_reg1 = 0x47;
+
+       lis331dlh_set_odr(&private_data->suspend, 50000);
+       lis331dlh_set_odr(&private_data->resume, 200000);
+       lis331dlh_set_fsr(&private_data->suspend, 2048);
+       lis331dlh_set_fsr(&private_data->resume, 2048);
+       lis331dlh_set_ths(&private_data->suspend, 80);
+       lis331dlh_set_ths(&private_data->resume, 40);
+       lis331dlh_set_dur(&private_data->suspend, 1000);
+       lis331dlh_set_dur(&private_data->resume,  2540);
+       return ML_SUCCESS;
+}
+
+static int lis331dlh_exit(void *mlsl_handle,
+                         struct ext_slave_descr *slave,
+                         struct ext_slave_platform_data *pdata)
+{
+       if (pdata->private_data)
+               return MLOSFree(pdata->private_data);
+       else
+               return ML_SUCCESS;
+}
+
+static int lis331dlh_config(void *mlsl_handle,
+                       struct ext_slave_descr *slave,
+                       struct ext_slave_platform_data *pdata,
+                       struct ext_slave_config *data)
+{
+       struct lis331dlh_private_data *private_data = pdata->private_data;
+       if (!data->data)
+               return ML_ERROR_INVALID_PARAMETER;
+
+       switch (data->key) {
+       case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+               lis331dlh_set_odr(&private_data->suspend,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_ODR_RESUME:
+               lis331dlh_set_odr(&private_data->resume,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+               lis331dlh_set_fsr(&private_data->suspend,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_FSR_RESUME:
+               lis331dlh_set_fsr(&private_data->resume,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_MOT_THS:
+               lis331dlh_set_ths(&private_data->suspend,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_NMOT_THS:
+               lis331dlh_set_ths(&private_data->resume,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_MOT_DUR:
+               lis331dlh_set_dur(&private_data->suspend,
+                               *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_NMOT_DUR:
+               lis331dlh_set_dur(&private_data->resume,
+                               *((long *)data->data));
+               break;
+       default:
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+       };
+
+       return ML_SUCCESS;
+}
+
+struct ext_slave_descr lis331dlh_descr = {
+       /*.init             = */ lis331dlh_init,
+       /*.exit             = */ lis331dlh_exit,
+       /*.suspend          = */ lis331dlh_suspend,
+       /*.resume           = */ lis331dlh_resume,
+       /*.read             = */ lis331dlh_read,
+       /*.config           = */ lis331dlh_config,
+       /*.name             = */ "lis331dlh",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_LIS331,
+       /*.reg              = */ (0x28 | 0x80), /* 0x80 for burst reads */
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {2, 480},
+};
+
+struct ext_slave_descr *lis331dlh_get_slave_descr(void)
+{
+       return &lis331dlh_descr;
+}
+EXPORT_SYMBOL(lis331dlh_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/lsm303a.c b/drivers/misc/mpu3050/accel/lsm303a.c
new file mode 100644 (file)
index 0000000..47e2ac1
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   lsm303a.c
+ *      @brief  Accelerometer setup and handling methods for ST LSM303
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+#define ACCEL_ST_SLEEP_REG          (0x20)
+#define ACCEL_ST_SLEEP_MASK         (0x20)
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int lsm303dlha_suspend(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, ACCEL_ST_SLEEP_REG,
+                          1, &reg);
+       ERROR_CHECK(result);
+       reg &= ~(0x27);
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_ST_SLEEP_REG, reg);
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register & mask */
+#define ACCEL_ST_CTRL_REG          (0x23)
+#define ACCEL_ST_CTRL_MASK         (0x30)
+
+int lsm303dlha_resume(void *mlsl_handle,
+                     struct ext_slave_descr *slave,
+                     struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, ACCEL_ST_SLEEP_REG,
+                          1, &reg);
+       ERROR_CHECK(result);
+       reg |= 0x27;
+       /*wake up if sleeping */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_ST_SLEEP_REG, reg);
+       ERROR_CHECK(result);
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x20, 0x37);
+       ERROR_CHECK(result);
+       MLOSSleep(500);
+
+       reg = 0x40;
+
+       /* Full Scale */
+       reg &= ~ACCEL_ST_CTRL_MASK;
+       if (slave->range.mantissa == 4) {
+               slave->range.fraction = 960;
+               reg |= 0x10;
+       } else if (slave->range.mantissa == 8) {
+               slave->range.fraction = 1920;
+               reg |= 0x30;
+       } else {
+               slave->range.mantissa = 2;
+               slave->range.fraction = 480;
+               reg |= 0x00;
+       }
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x23, reg);
+       ERROR_CHECK(result);
+
+       /* Configure high pass filter */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x21, 0x0F);
+       ERROR_CHECK(result);
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x32, 0x00);
+       ERROR_CHECK(result);
+       /* Configure INT1_DURATION */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x33, 0x7F);
+       ERROR_CHECK(result);
+       /* Configure INT1_CFG */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x30, 0x95);
+       ERROR_CHECK(result);
+       MLOSSleep(50);
+       return result;
+}
+
+int lsm303dlha_read(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata,
+                   unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+struct ext_slave_descr lsm303dlha_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ lsm303dlha_suspend,
+       /*.resume           = */ lsm303dlha_resume,
+       /*.read             = */ lsm303dlha_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "lsm303dlha",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_LSM303,
+       /*.reg              = */ (0x28 | 0x80), /* 0x80 for burst reads */
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {2, 480},
+};
+
+struct ext_slave_descr *lsm303dlha_get_slave_descr(void)
+{
+       return &lsm303dlha_descr;
+}
+EXPORT_SYMBOL(lsm303dlha_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/mantis.c b/drivers/misc/mpu3050/accel/mantis.c
new file mode 100644 (file)
index 0000000..9e6f3e4
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+/**
+ *  @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   lis331.c
+ *      @brief  Accelerometer setup and handling methods for ST LIS331
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+#define ACCEL_ST_SLEEP_REG          (0x20)
+#define ACCEL_ST_SLEEP_MASK         (0x20)
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int mantis_suspend(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       return ML_SUCCESS;
+}
+
+/* full scale setting - register & mask */
+#define ACCEL_ST_CTRL_REG          (0x23)
+#define ACCEL_ST_CTRL_MASK         (0x30)
+
+int mantis_resume(void *mlsl_handle,
+                 struct ext_slave_descr *slave,
+                 struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+#ifdef M_HW
+       unsigned char reg;
+
+       if (slave->range.mantissa == 2)
+               reg = 0;
+       else if (slave->range.mantissa == 4)
+               reg = 1 << 3;
+       else if (slave->range.mantissa == 8)
+               reg = 2 << 3;
+       else if (slave->range.mantissa == 16)
+               reg = 3 << 3;
+       else
+               return ML_ERROR;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                      MPUREG_ACCEL_CONFIG, reg);
+#endif
+       return result;
+}
+
+int mantis_read(void *mlsl_handle,
+               struct ext_slave_descr *slave,
+               struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+struct ext_slave_descr mantis_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ mantis_suspend,
+       /*.resume           = */ mantis_resume,
+       /*.read             = */ mantis_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "mantis",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_MPU6000,
+       /*.reg              = */ 0xA8,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *mantis_get_slave_descr(void)
+{
+       return &mantis_descr;
+}
+EXPORT_SYMBOL(mantis_get_slave_descr);
+
+/**
+ *  @}
+ */
+
diff --git a/drivers/misc/mpu3050/accel/mma8450.c b/drivers/misc/mpu3050/accel/mma8450.c
new file mode 100644 (file)
index 0000000..fec9c74
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   mma8450.c
+ *      @brief  Accelerometer setup and handling methods for Freescale MMA8450
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+#define ACCEL_MMA8450_SLEEP_REG      (0x38)
+#define ACCEL_MMA8450_SLEEP_MASK     (0x3)
+
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int mma8450_suspend(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address,
+                          ACCEL_MMA8450_SLEEP_REG, 1, &reg);
+       ERROR_CHECK(result);
+       reg &= ~ACCEL_MMA8450_SLEEP_MASK;
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_MMA8450_SLEEP_REG, reg);
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register & mask */
+#define ACCEL_MMA8450_CTRL_REG      (0x38)
+#define ACCEL_MMA8450_CTRL_MASK     (0x3)
+
+int mma8450_resume(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address,
+                          ACCEL_MMA8450_CTRL_REG, 1, &reg);
+       ERROR_CHECK(result);
+
+       /* data rate = 200Hz */
+       reg &= 0xE3;
+       reg |= 0x4;
+
+       /* Full Scale */
+       reg &= ~ACCEL_MMA8450_CTRL_MASK;
+       if (slave->range.mantissa == 4)
+               reg |= 0x2;
+       else if (slave->range.mantissa == 8)
+               reg |= 0x3;
+       else {
+               slave->range.mantissa = 2;
+               reg |= 0x1;
+       }
+       slave->range.fraction = 0;
+
+       /* XYZ_DATA_CFG: event flag enabled on all axis */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x16, 0x05);
+       ERROR_CHECK(result);
+       /* CTRL_REG1: rate + scale config + wakeup */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_MMA8450_CTRL_REG, reg);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+int mma8450_read(void *mlsl_handle,
+                struct ext_slave_descr *slave,
+                struct ext_slave_platform_data *pdata,
+                unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+struct ext_slave_descr mma8450_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ mma8450_suspend,
+       /*.resume           = */ mma8450_resume,
+       /*.read             = */ mma8450_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "mma8450",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_MMA8450,
+       /*.reg              = */ 0x00,
+       /*.len              = */ 3,
+       /*.endian           = */ EXT_SLAVE_FS8_BIG_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *mma8450_get_slave_descr(void)
+{
+       return &mma8450_descr;
+}
+EXPORT_SYMBOL(mma8450_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/accel/mma8451.c b/drivers/misc/mpu3050/accel/mma8451.c
new file mode 100644 (file)
index 0000000..4acf449
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   mma8451.c
+ *      @brief  Accelerometer setup and handling methods for Freescale MMA8451
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+#define ACCEL_MMA8451_SLEEP_REG      (0x2A)
+#define ACCEL_MMA8451_SLEEP_MASK     (0x01)
+
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int mma8451_suspend(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address,
+                          ACCEL_MMA8451_SLEEP_REG, 1, &reg);
+       ERROR_CHECK(result);
+       reg &= ~ACCEL_MMA8451_SLEEP_MASK;
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 ACCEL_MMA8451_SLEEP_REG, reg);
+       ERROR_CHECK(result);
+       return result;
+}
+
+/* full scale setting - register & mask */
+#define ACCEL_MMA8451_CTRL_REG      (0x0E)
+#define ACCEL_MMA8451_CTRL_MASK     (0x03)
+
+int mma8451_resume(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, 0x0E, 1, &reg);
+       ERROR_CHECK(result);
+
+       /* data rate = 200Hz */
+
+       /* Full Scale */
+       reg &= ~ACCEL_MMA8451_CTRL_MASK;
+       if (slave->range.mantissa == 4)
+               reg |= 0x1;
+       else if (slave->range.mantissa == 8)
+               reg |= 0x2;
+       else {
+               slave->range.mantissa = 2;
+               reg |= 0x0;
+       }
+       slave->range.fraction = 0;
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x0E, reg);
+       ERROR_CHECK(result);
+       /* 200Hz + active mode */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address, 0x2A, 0x11);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+int mma8451_read(void *mlsl_handle,
+                struct ext_slave_descr *slave,
+                struct ext_slave_platform_data *pdata,
+                unsigned char *data)
+{
+       return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+struct ext_slave_descr mma8451_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ mma8451_suspend,
+       /*.resume           = */ mma8451_resume,
+       /*.read             = */ mma8451_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "mma8451",
+       /*.type             = */ EXT_SLAVE_TYPE_ACCELEROMETER,
+       /*.id               = */ ACCEL_ID_MMA8451,
+       /*.reg              = */ 0x00,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_FS16_BIG_ENDIAN,
+       /*.range            = */ {2, 0},
+};
+
+struct ext_slave_descr *mma8451_get_slave_descr(void)
+{
+       return &mma8451_descr;
+}
+EXPORT_SYMBOL(mma8451_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/ak8975.c b/drivers/misc/mpu3050/compass/ak8975.c
new file mode 100644 (file)
index 0000000..5f020cf
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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. - */
+/* ------------------ */
+
+#include <string.h>
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.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(void *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);
+       MLOSSleep(1);           /* wait at least 100us */
+       ERROR_CHECK(result);
+       return result;
+}
+
+int ak8975_resume(void *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);
+       ERROR_CHECK(result);
+       return result;
+}
+
+int ak8975_read(void *mlsl_handle,
+               struct ext_slave_descr *slave,
+               struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+       unsigned char regs[8];
+       unsigned char *stat = &regs[0];
+       unsigned char *stat2 = &regs[7];
+       int result = ML_SUCCESS;
+       int status = ML_SUCCESS;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1,
+                          8, regs);
+       ERROR_CHECK(result);
+
+       /*
+        * ST : data ready -
+        * Measurement has been completed and data is ready to be read.
+        */
+       if (*stat & 0x01) {
+               memcpy(data, &regs[1], 6);
+               status = ML_SUCCESS;
+       }
+
+       /*
+        * ST2 : data error -
+        * occurs when data read is started outside of a readable period;
+        * data read would not be correct.
+        * Valid in continuous measurement mode only.
+        * In single measurement mode this error should not occour but we
+        * stil account for it and return an error, since the data would be
+        * corrupted.
+        * DERR bit is self-clearing when ST2 register is read.
+        */
+       if (*stat2 & 0x04)
+               status = ML_ERROR_COMPASS_DATA_ERROR;
+       /*
+        * ST2 : overflow -
+        * the sum of the absolute values of all axis |X|+|Y|+|Z| < 2400uT.
+        * This is likely to happen in presence of an external magnetic
+        * disturbance; it indicates, the sensor data is incorrect and should
+        * be ignored.
+        * An error is returned.
+        * HOFL bit clears when a new measurement starts.
+        */
+       if (*stat2 & 0x08)
+               status = ML_ERROR_COMPASS_DATA_OVERFLOW;
+       /*
+        * ST : overrun -
+        * the previous sample was not fetched and lost.
+        * Valid in continuous measurement mode only.
+        * In single measurement mode this error should not occour and we
+        * don't consider this condition an error.
+        * DOR bit is self-clearing when ST2 or any meas. data register is
+        * read.
+        */
+       if (*stat & 0x02) {
+               /* status = ML_ERROR_COMPASS_DATA_UNDERFLOW; */
+               status = ML_SUCCESS;
+       }
+
+       /*
+        * trigger next measurement if:
+        *    - stat is non zero;
+        *    - if stat is zero and stat2 is non zero.
+        * Won't trigger if data is not ready and there was no error.
+        */
+       if (*stat != 0x00 || *stat2 != 0x00) {
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         AK8975_REG_CNTL,
+                                         AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
+               ERROR_CHECK(result);
+       }
+
+       return status;
+}
+
+struct ext_slave_descr ak8975_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ ak8975_suspend,
+       /*.resume           = */ ak8975_resume,
+       /*.read             = */ ak8975_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "ak8975",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_AKM,
+       /*.reg              = */ 0x01,
+       /*.len              = */ 9,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {9830, 4000}
+};
+
+struct ext_slave_descr *ak8975_get_slave_descr(void)
+{
+       return &ak8975_descr;
+}
+EXPORT_SYMBOL(ak8975_get_slave_descr);
+
+/**
+ *  @}
+ */
diff --git a/drivers/misc/mpu3050/compass/ami30x.c b/drivers/misc/mpu3050/compass/ami30x.c
new file mode 100644 (file)
index 0000000..28cd5f4
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   ami30x.c
+ *     @brief  Magnetometer setup and handling methods for Aichi AMI304/AMI305
+ *             compass.
+*/
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+#define AMI30X_REG_DATAX (0x10)
+#define AMI30X_REG_STAT1 (0x18)
+#define AMI30X_REG_CNTL1 (0x1B)
+#define AMI30X_REG_CNTL2 (0x1C)
+#define AMI30X_REG_CNTL3 (0x1D)
+
+#define AMI30X_BIT_CNTL1_PC1  (0x80)
+#define AMI30X_BIT_CNTL1_ODR1 (0x10)
+#define AMI30X_BIT_CNTL1_FS1  (0x02)
+
+#define AMI30X_BIT_CNTL2_IEN  (0x10)
+#define AMI30X_BIT_CNTL2_DREN (0x08)
+#define AMI30X_BIT_CNTL2_DRP  (0x04)
+#define AMI30X_BIT_CNTL3_F0RCE (0x40)
+
+int ami30x_suspend(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, AMI30X_REG_CNTL1,
+                          1, &reg);
+       ERROR_CHECK(result);
+
+       reg &= ~(AMI30X_BIT_CNTL1_PC1|AMI30X_BIT_CNTL1_FS1);
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 AMI30X_REG_CNTL1, reg);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+int ami30x_resume(void *mlsl_handle,
+                 struct ext_slave_descr *slave,
+                 struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       /* Set CNTL1 reg to power model active */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 AMI30X_REG_CNTL1,
+                                 AMI30X_BIT_CNTL1_PC1|AMI30X_BIT_CNTL1_FS1);
+       ERROR_CHECK(result);
+       /* Set CNTL2 reg to DRDY active high and enabled */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 AMI30X_REG_CNTL2,
+                                 AMI30X_BIT_CNTL2_DREN |
+                                 AMI30X_BIT_CNTL2_DRP);
+       ERROR_CHECK(result);
+       /* Set CNTL3 reg to forced measurement period */
+       result =
+               MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 AMI30X_REG_CNTL3, AMI30X_BIT_CNTL3_F0RCE);
+
+       return result;
+}
+
+int ami30x_read(void *mlsl_handle,
+               struct ext_slave_descr *slave,
+               struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+       unsigned char stat;
+       int result = ML_SUCCESS;
+
+       /* Read status reg and check if data ready (DRDY) */
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, AMI30X_REG_STAT1,
+                          1, &stat);
+       ERROR_CHECK(result);
+
+       if (stat & 0x40) {
+               result =
+                   MLSLSerialRead(mlsl_handle, pdata->address,
+                                  AMI30X_REG_DATAX, 6,
+                                  (unsigned char *) data);
+               ERROR_CHECK(result);
+               /* start another measurement */
+               result =
+                       MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                             AMI30X_REG_CNTL3,
+                                             AMI30X_BIT_CNTL3_F0RCE);
+               ERROR_CHECK(result);
+
+               return ML_SUCCESS;
+       }
+
+       return ML_ERROR_COMPASS_DATA_NOT_READY;
+}
+
+struct ext_slave_descr ami30x_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ ami30x_suspend,
+       /*.resume           = */ ami30x_resume,
+       /*.read             = */ ami30x_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "ami30x",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_AMI30X,
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {5461, 3333}
+       /* For AMI305,the range field needs to be modified to {9830.4f}*/
+};
+
+struct ext_slave_descr *ami30x_get_slave_descr(void)
+{
+       return &ami30x_descr;
+}
+EXPORT_SYMBOL(ami30x_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/hmc5883.c b/drivers/misc/mpu3050/compass/hmc5883.c
new file mode 100644 (file)
index 0000000..3e67d2e
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @brief      Provides the interface to setup and handle a compass
+ *              connected to the primary I2C interface of the gyroscope.
+ *
+ *  @{
+ *      @file   hmc5883.c
+ *      @brief  Magnetometer setup and handling methods for honeywell hmc5883
+ *              compass.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+/*-----HONEYWELL HMC5883 Registers ------*/
+enum HMC_REG {
+       HMC_REG_CONF_A = 0x0,
+       HMC_REG_CONF_B = 0x1,
+       HMC_REG_MODE = 0x2,
+       HMC_REG_X_M = 0x3,
+       HMC_REG_X_L = 0x4,
+       HMC_REG_Z_M = 0x5,
+       HMC_REG_Z_L = 0x6,
+       HMC_REG_Y_M = 0x7,
+       HMC_REG_Y_L = 0x8,
+       HMC_REG_STATUS = 0x9,
+       HMC_REG_ID_A = 0xA,
+       HMC_REG_ID_B = 0xB,
+       HMC_REG_ID_C = 0xC
+};
+
+enum HMC_CONF_A {
+       HMC_CONF_A_DRATE_MASK = 0x1C,
+       HMC_CONF_A_DRATE_0_75 = 0x00,
+       HMC_CONF_A_DRATE_1_5 = 0x04,
+       HMC_CONF_A_DRATE_3 = 0x08,
+       HMC_CONF_A_DRATE_7_5 = 0x0C,
+       HMC_CONF_A_DRATE_15 = 0x10,
+       HMC_CONF_A_DRATE_30 = 0x14,
+       HMC_CONF_A_DRATE_75 = 0x18,
+       HMC_CONF_A_MEAS_MASK = 0x3,
+       HMC_CONF_A_MEAS_NORM = 0x0,
+       HMC_CONF_A_MEAS_POS = 0x1,
+       HMC_CONF_A_MEAS_NEG = 0x2
+};
+
+enum HMC_CONF_B{
+       HMC_CONF_B_GAIN_MASK = 0xE0,
+       HMC_CONF_B_GAIN_0_9 = 0x00,
+       HMC_CONF_B_GAIN_1_2 = 0x20,
+       HMC_CONF_B_GAIN_1_9 = 0x40,
+       HMC_CONF_B_GAIN_2_5 = 0x60,
+       HMC_CONF_B_GAIN_4_0 = 0x80,
+       HMC_CONF_B_GAIN_4_6 = 0xA0,
+       HMC_CONF_B_GAIN_5_5 = 0xC0,
+       HMC_CONF_B_GAIN_7_9 = 0xE0
+};
+
+enum HMC_MODE {
+       HMC_MODE_MASK = 0x3,
+       HMC_MODE_CONT = 0x0,
+       HMC_MODE_SINGLE = 0x1,
+       HMC_MODE_IDLE = 0x2,
+       HMC_MODE_SLEEP = 0x3
+};
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int hmc5883_suspend(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 HMC_REG_MODE, HMC_MODE_SLEEP);
+       ERROR_CHECK(result);
+       MLOSSleep(3);
+
+       return result;
+}
+
+int hmc5883_resume(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       /* Use single measurement mode. Start at sleep state. */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 HMC_REG_MODE, HMC_MODE_SLEEP);
+       ERROR_CHECK(result);
+       /* Config normal measurement */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 HMC_REG_CONF_A, 0);
+       ERROR_CHECK(result);
+       /* Adjust gain to 307 LSB/Gauss */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 HMC_REG_CONF_B, HMC_CONF_B_GAIN_5_5);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+int hmc5883_read(void *mlsl_handle,
+                struct ext_slave_descr *slave,
+                struct ext_slave_platform_data *pdata,
+                unsigned char *data)
+{
+       unsigned char stat;
+       tMLError result = ML_SUCCESS;
+       unsigned char tmp;
+       short axisFixed;
+
+       /* Read status reg. to check if data is ready */
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, HMC_REG_STATUS, 1,
+                          &stat);
+       ERROR_CHECK(result);
+       if (stat & 0x01) {
+               result =
+                   MLSLSerialRead(mlsl_handle, pdata->address,
+                                  HMC_REG_X_M, 6, (unsigned char *) data);
+               ERROR_CHECK(result);
+
+               /* switch YZ axis to proper position */
+               tmp = data[2];
+               data[2] = data[4];
+               data[4] = tmp;
+               tmp = data[3];
+               data[3] = data[5];
+               data[5] = tmp;
+
+               /*drop data if overflows */
+               if ((data[0] == 0xf0) || (data[2] == 0xf0)
+                   || (data[4] == 0xf0)) {
+                       /* trigger next measurement read */
+                       result =
+                           MLSLSerialWriteSingle(mlsl_handle,
+                                                       pdata->address,
+                                                       HMC_REG_MODE,
+                                                       HMC_MODE_SINGLE);
+                       ERROR_CHECK(result);
+                       return ML_ERROR_COMPASS_DATA_OVERFLOW;
+               }
+               /* convert to fixed point and apply sensitivity correction for
+                  Z-axis */
+               axisFixed =
+                   (short) ((unsigned short) data[5] +
+                            (unsigned short) data[4] * 256);
+               /* scale up by 1.125 (36/32) */
+               axisFixed = (short) (axisFixed * 36);
+               data[4] = axisFixed >> 8;
+               data[5] = axisFixed & 0xFF;
+
+               axisFixed =
+                   (short) ((unsigned short) data[3] +
+                            (unsigned short) data[2] * 256);
+               axisFixed = (short) (axisFixed * 32);
+               data[2] = axisFixed >> 8;
+               data[3] = axisFixed & 0xFF;
+
+               axisFixed =
+                   (short) ((unsigned short) data[1] +
+                            (unsigned short) data[0] * 256);
+               axisFixed = (short) (axisFixed * 32);
+               data[0] = axisFixed >> 8;
+               data[1] = axisFixed & 0xFF;
+
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         HMC_REG_MODE, HMC_MODE_SINGLE);
+               ERROR_CHECK(result);
+
+               return ML_SUCCESS;
+       } else {
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         HMC_REG_MODE, HMC_MODE_SINGLE);
+               ERROR_CHECK(result);
+
+               return ML_ERROR_COMPASS_DATA_NOT_READY;
+       }
+}
+
+struct ext_slave_descr hmc5883_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ hmc5883_suspend,
+       /*.resume           = */ hmc5883_resume,
+       /*.read             = */ hmc5883_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "hmc5883",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_HMC5883,
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {10673, 6156},
+};
+
+struct ext_slave_descr *hmc5883_get_slave_descr(void)
+{
+       return &hmc5883_descr;
+}
+EXPORT_SYMBOL(hmc5883_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/hscdtd00xx.c b/drivers/misc/mpu3050/compass/hscdtd00xx.c
new file mode 100644 (file)
index 0000000..69aa3bb
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @brief      Provides the interface to setup and handle a compass
+ *              connected to the primary I2C interface of the gyroscope.
+ *
+ *  @{
+ *      @file   hscdtd00xx.c
+ *      @brief  Magnetometer setup and handling methods for Alps hscdtd00xx
+ *              compass.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+/*----- ALPS HSCDTD00XX Registers ------*/
+#define COMPASS_HSCDTD00XX_STAT          (0x18)
+#define COMPASS_HSCDTD00XX_CTRL1         (0x1B)
+#define COMPASS_HSCDTD00XX_CTRL2         (0x1C)
+#define COMPASS_HSCDTD00XX_CTRL3         (0x1D)
+#define COMPASS_HSCDTD00XX_DATAX         (0x10)
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Compass Initialization Functions
+*****************************************/
+
+int hscdtd00xx_suspend(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       /* Power mode: stand-by */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 COMPASS_HSCDTD00XX_CTRL1, 0x00);
+       ERROR_CHECK(result);
+       MLOSSleep(1);           /* turn-off time */
+
+       return result;
+}
+
+int hscdtd00xx_resume(void *mlsl_handle,
+                     struct ext_slave_descr *slave,
+                     struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       /* Soft reset */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 COMPASS_HSCDTD00XX_CTRL3, 0x80);
+       ERROR_CHECK(result);
+       /* Force state; Power mode: active */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 COMPASS_HSCDTD00XX_CTRL1, 0x82);
+       ERROR_CHECK(result);
+       /* Data ready enable */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 COMPASS_HSCDTD00XX_CTRL2, 0x08);
+       ERROR_CHECK(result);
+       MLOSSleep(1);           /* turn-on time */
+
+       return result;
+}
+
+int hscdtd00xx_read(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata,
+                   unsigned char *data)
+{
+       unsigned char stat;
+       tMLError result = ML_SUCCESS;
+
+       /* Read status reg. to check if data is ready */
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address,
+                          COMPASS_HSCDTD00XX_STAT, 1, &stat);
+       ERROR_CHECK(result);
+       if (stat & 0x40) {
+               result =
+                   MLSLSerialRead(mlsl_handle, pdata->address,
+                                  COMPASS_HSCDTD00XX_DATAX, 6,
+                                  (unsigned char *) data);
+               ERROR_CHECK(result);
+
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         COMPASS_HSCDTD00XX_CTRL3, 0x40);
+               ERROR_CHECK(result);
+
+               return ML_SUCCESS;
+       } else if (stat & 0x20) {
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         COMPASS_HSCDTD00XX_CTRL3, 0x40);
+               ERROR_CHECK(result);
+               return ML_ERROR_COMPASS_DATA_OVERFLOW;
+       } else {
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         COMPASS_HSCDTD00XX_CTRL3, 0x40);
+               ERROR_CHECK(result);
+               return ML_ERROR_COMPASS_DATA_NOT_READY;
+       }
+}
+
+struct ext_slave_descr hscdtd00xx_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ hscdtd00xx_suspend,
+       /*.resume           = */ hscdtd00xx_resume,
+       /*.read             = */ hscdtd00xx_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "hscdtd00xx",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_HSCDTD00XX,
+       /*.reg              = */ 0x10,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_LITTLE_ENDIAN,
+       /*.range            = */ {9830, 4000},
+};
+
+struct ext_slave_descr *hscdtd00xx_get_slave_descr(void)
+{
+       return &hscdtd00xx_descr;
+}
+EXPORT_SYMBOL(hscdtd00xx_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/lsm303m.c b/drivers/misc/mpu3050/compass/lsm303m.c
new file mode 100644 (file)
index 0000000..082ee45
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @brief      Provides the interface to setup and handle a compass
+ *              connected to the primary I2C interface of the gyroscope.
+ *
+ *  @{
+ *      @file   lsm303m.c
+ *      @brief  Magnetometer setup and handling methods for ST LSM303.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+/*----- ST LSM303 Registers ------*/
+enum LSM_REG {
+       LSM_REG_CONF_A = 0x0,
+       LSM_REG_CONF_B = 0x1,
+       LSM_REG_MODE = 0x2,
+       LSM_REG_X_M = 0x3,
+       LSM_REG_X_L = 0x4,
+       LSM_REG_Z_M = 0x5,
+       LSM_REG_Z_L = 0x6,
+       LSM_REG_Y_M = 0x7,
+       LSM_REG_Y_L = 0x8,
+       LSM_REG_STATUS = 0x9,
+       LSM_REG_ID_A = 0xA,
+       LSM_REG_ID_B = 0xB,
+       LSM_REG_ID_C = 0xC
+};
+
+enum LSM_CONF_A {
+       LSM_CONF_A_DRATE_MASK = 0x1C,
+       LSM_CONF_A_DRATE_0_75 = 0x00,
+       LSM_CONF_A_DRATE_1_5 = 0x04,
+       LSM_CONF_A_DRATE_3 = 0x08,
+       LSM_CONF_A_DRATE_7_5 = 0x0C,
+       LSM_CONF_A_DRATE_15 = 0x10,
+       LSM_CONF_A_DRATE_30 = 0x14,
+       LSM_CONF_A_DRATE_75 = 0x18,
+       LSM_CONF_A_MEAS_MASK = 0x3,
+       LSM_CONF_A_MEAS_NORM = 0x0,
+       LSM_CONF_A_MEAS_POS = 0x1,
+       LSM_CONF_A_MEAS_NEG = 0x2
+};
+
+enum LSM_CONF_B {
+       LSM_CONF_B_GAIN_MASK = 0xE0,
+       LSM_CONF_B_GAIN_0_9 = 0x00,
+       LSM_CONF_B_GAIN_1_2 = 0x20,
+       LSM_CONF_B_GAIN_1_9 = 0x40,
+       LSM_CONF_B_GAIN_2_5 = 0x60,
+       LSM_CONF_B_GAIN_4_0 = 0x80,
+       LSM_CONF_B_GAIN_4_6 = 0xA0,
+       LSM_CONF_B_GAIN_5_5 = 0xC0,
+       LSM_CONF_B_GAIN_7_9 = 0xE0
+};
+
+enum LSM_MODE {
+       LSM_MODE_MASK = 0x3,
+       LSM_MODE_CONT = 0x0,
+       LSM_MODE_SINGLE = 0x1,
+       LSM_MODE_IDLE = 0x2,
+       LSM_MODE_SLEEP = 0x3
+};
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int lsm303dlhm_suspend(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 LSM_REG_MODE, LSM_MODE_SLEEP);
+       ERROR_CHECK(result);
+       MLOSSleep(3);
+
+       return result;
+}
+
+int lsm303dlhm_resume(void *mlsl_handle,
+                     struct ext_slave_descr *slave,
+                     struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       /* Use single measurement mode. Start at sleep state. */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 LSM_REG_MODE, LSM_MODE_SLEEP);
+       ERROR_CHECK(result);
+       /* Config normal measurement */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 LSM_REG_CONF_A, 0);
+       ERROR_CHECK(result);
+       /* Adjust gain to 320 LSB/Gauss */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 LSM_REG_CONF_B, LSM_CONF_B_GAIN_5_5);
+       ERROR_CHECK(result);
+
+       return result;
+}
+
+int lsm303dlhm_read(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata,
+                   unsigned char *data)
+{
+       unsigned char stat;
+       tMLError result = ML_SUCCESS;
+       short axisFixed;
+
+       /* Read status reg. to check if data is ready */
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, LSM_REG_STATUS, 1,
+                          &stat);
+       ERROR_CHECK(result);
+       if (stat & 0x01) {
+               result =
+                   MLSLSerialRead(mlsl_handle, pdata->address,
+                                  LSM_REG_X_M, 6, (unsigned char *) data);
+               ERROR_CHECK(result);
+
+               /*drop data if overflows */
+               if ((data[0] == 0xf0) || (data[2] == 0xf0)
+                   || (data[4] == 0xf0)) {
+                       /* trigger next measurement read */
+                       result =
+                               MLSLSerialWriteSingle(mlsl_handle,
+                                                       pdata->address,
+                                                       LSM_REG_MODE,
+                                                       LSM_MODE_SINGLE);
+                       ERROR_CHECK(result);
+                       return ML_ERROR_COMPASS_DATA_OVERFLOW;
+               }
+               /* convert to fixed point and apply sensitivity correction for
+                  Z-axis */
+               axisFixed =
+                   (short) ((unsigned short) data[5] +
+                            (unsigned short) data[4] * 256);
+               /* scale up by 1.125 (36/32) approximate of 1.122 (320/285) */
+               axisFixed = (short) (axisFixed * 36);
+               data[4] = axisFixed >> 8;
+               data[5] = axisFixed & 0xFF;
+
+               axisFixed =
+                   (short) ((unsigned short) data[3] +
+                            (unsigned short) data[2] * 256);
+               axisFixed = (short) (axisFixed * 32);
+               data[2] = axisFixed >> 8;
+               data[3] = axisFixed & 0xFF;
+
+               axisFixed =
+                   (short) ((unsigned short) data[1] +
+                            (unsigned short) data[0] * 256);
+               axisFixed = (short) (axisFixed * 32);
+               data[0] = axisFixed >> 8;
+               data[1] = axisFixed & 0xFF;
+
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         LSM_REG_MODE, LSM_MODE_SINGLE);
+               ERROR_CHECK(result);
+
+               return ML_SUCCESS;
+       } else {
+               /* trigger next measurement read */
+               result =
+                   MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                         LSM_REG_MODE, LSM_MODE_SINGLE);
+               ERROR_CHECK(result);
+
+               return ML_ERROR_COMPASS_DATA_NOT_READY;
+       }
+}
+
+struct ext_slave_descr lsm303dlhm_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ lsm303dlhm_suspend,
+       /*.resume           = */ lsm303dlhm_resume,
+       /*.read             = */ lsm303dlhm_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "lsm303dlhm",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_LSM303,
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {10240, 0},
+};
+
+struct ext_slave_descr *lsm303dlhm_get_slave_descr(void)
+{
+       return &lsm303dlhm_descr;
+}
+EXPORT_SYMBOL(lsm303dlhm_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/mmc314x.c b/drivers/misc/mpu3050/compass/mmc314x.c
new file mode 100644 (file)
index 0000000..4bff05d
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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   mmc314x.c
+ *      @brief  Magnetometer setup and handling methods for ???? compass.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+static int reset_int = 1000;
+static int read_count = 1;
+static char reset_mode; /* in Z-init section */
+
+#define MMC314X_REG_ST (0x00)
+#define MMC314X_REG_X_MSB (0x01)
+
+#define MMC314X_CNTL_MODE_WAKE_UP (0x01)
+#define MMC314X_CNTL_MODE_SET (0x02)
+#define MMC314X_CNTL_MODE_RESET (0x04)
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int mmc314x_suspend(void *mlsl_handle,
+                   struct ext_slave_descr *slave,
+                   struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       return result;
+}
+
+int mmc314x_resume(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+
+       int result;
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 MMC314X_REG_ST, MMC314X_CNTL_MODE_RESET);
+       ERROR_CHECK(result);
+       MLOSSleep(10);
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 MMC314X_REG_ST, MMC314X_CNTL_MODE_SET);
+       ERROR_CHECK(result);
+       MLOSSleep(10);
+       read_count = 1;
+       return ML_SUCCESS;
+}
+
+int mmc314x_read(void *mlsl_handle,
+                struct ext_slave_descr *slave,
+                struct ext_slave_platform_data *pdata,
+                unsigned char *data)
+{
+       int result, ii;
+       short tmp[3];
+       unsigned char tmpdata[6];
+
+
+       if (read_count > 1000)
+               read_count = 1;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->address, MMC314X_REG_X_MSB,
+                          6, (unsigned char *) data);
+       ERROR_CHECK(result);
+
+       for (ii = 0; ii < 6; ii++)
+               tmpdata[ii] = data[ii];
+
+       for (ii = 0; ii < 3; ii++) {
+               tmp[ii] =
+                   (short) ((tmpdata[2 * ii] << 8) + tmpdata[2 * ii + 1]);
+               tmp[ii] = tmp[ii] - 4096;
+               tmp[ii] = tmp[ii] * 16;
+       }
+
+       for (ii = 0; ii < 3; ii++) {
+               data[2 * ii] = (unsigned char) (tmp[ii] >> 8);
+               data[2 * ii + 1] = (unsigned char) (tmp[ii]);
+       }
+
+       if (read_count % reset_int == 0) {
+               if (reset_mode) {
+                       result =
+                           MLSLSerialWriteSingle(mlsl_handle,
+                                                 pdata->address,
+                                                 MMC314X_REG_ST,
+                                                 MMC314X_CNTL_MODE_RESET);
+                       ERROR_CHECK(result);
+                       reset_mode = 0;
+                       return ML_ERROR_COMPASS_DATA_NOT_READY;
+               } else {
+                       result =
+                           MLSLSerialWriteSingle(mlsl_handle,
+                                                 pdata->address,
+                                                 MMC314X_REG_ST,
+                                                 MMC314X_CNTL_MODE_SET);
+                       ERROR_CHECK(result);
+                       reset_mode = 1;
+                       read_count++;
+                       return ML_ERROR_COMPASS_DATA_NOT_READY;
+               }
+       }
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+                                 MMC314X_REG_ST,
+                                 MMC314X_CNTL_MODE_WAKE_UP);
+       ERROR_CHECK(result);
+       read_count++;
+
+       return ML_SUCCESS;
+}
+
+struct ext_slave_descr mmc314x_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ mmc314x_suspend,
+       /*.resume           = */ mmc314x_resume,
+       /*.read             = */ mmc314x_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "mmc314x",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_MMC314X,
+       /*.reg              = */ 0x01,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {400, 0},
+};
+
+struct ext_slave_descr *mmc314x_get_slave_descr(void)
+{
+       return &mmc314x_descr;
+}
+EXPORT_SYMBOL(mmc314x_get_slave_descr);
+
+/**
+ *  @}
+**/
diff --git a/drivers/misc/mpu3050/compass/yas529-kernel.c b/drivers/misc/mpu3050/compass/yas529-kernel.c
new file mode 100644 (file)
index 0000000..b4be440
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+/**
+ *  @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   yas529.c
+ *      @brief  Magnetometer setup and handling methods for Yamaha yas529
+ *              compass.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/i2c.h>
+#endif
+
+#include "mpu.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+/*----- YAMAHA YAS529 Registers ------*/
+enum YAS_REG {
+       YAS_REG_CMDR            = 0x00, /* 000 < 5 */
+       YAS_REG_XOFFSETR        = 0x20, /* 001 < 5 */
+       YAS_REG_Y1OFFSETR       = 0x40, /* 010 < 5 */
+       YAS_REG_Y2OFFSETR       = 0x60, /* 011 < 5 */
+       YAS_REG_ICOILR          = 0x80, /* 100 < 5 */
+       YAS_REG_CAL             = 0xA0, /* 101 < 5 */
+       YAS_REG_CONFR           = 0xC0, /* 110 < 5 */
+       YAS_REG_DOUTR           = 0xE0  /* 111 < 5 */
+};
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+static long a1;
+static long a2;
+static long a3;
+static long a4;
+static long a5;
+static long a6;
+static long a7;
+static long a8;
+static long a9;
+
+/*****************************************
+    Yamaha I2C access functions
+*****************************************/
+
+static int yas529_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;
+}
+
+static int yas529_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 = I2C_M_RD;
+       msgs[0].buf = data;
+       msgs[0].len = len;
+
+       res = i2c_transfer(i2c_adap, msgs, 1);
+       if (res < 1)
+               return res;
+       else
+               return 0;
+}
+
+/*****************************************
+    Accelerometer Initialization Functions
+*****************************************/
+
+int yas529_suspend(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       return result;
+}
+
+int yas529_resume(void *mlsl_handle,
+                 struct ext_slave_descr *slave,
+                 struct ext_slave_platform_data *pdata)
+{
+       int result = ML_SUCCESS;
+
+       unsigned char dummyData[1] = { 0 };
+       unsigned char dummyRegister = 0;
+       unsigned char rawData[6];
+       unsigned char calData[9];
+
+       short xoffset, y1offset, y2offset;
+       short d2, d3, d4, d5, d6, d7, d8, d9;
+
+       /* YAS529 Application Manual MS-3C - Section 4.4.5 */
+       /* =============================================== */
+       /* Step 1 - register initialization */
+       /* zero initialization coil register - "100 00 000" */
+       dummyData[0] = YAS_REG_ICOILR | 0x00;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       /* zero config register - "110 00 000" */
+       dummyData[0] = YAS_REG_CONFR | 0x00;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+
+       /* Step 2 - initialization coil operation */
+       dummyData[0] = YAS_REG_ICOILR | 0x11;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x01;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x12;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x02;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x13;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x03;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x14;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x04;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x15;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x05;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x16;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x06;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x17;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x07;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x10;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_ICOILR | 0x00;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+
+       /* Step 3 - rough offset measurement */
+       /* Config register - Measurements results - "110 00 000" */
+       dummyData[0] = YAS_REG_CONFR | 0x00;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       /* Measurements command register - Rough offset measurement -
+          "000 00001" */
+       dummyData[0] = YAS_REG_CMDR | 0x01;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       MLOSSleep(2);           /* wait at least 1.5ms */
+
+       /* Measurement data read */
+       result =
+           yas529_sensor_i2c_read(mlsl_handle, pdata->address,
+                                  dummyRegister, 6, rawData);
+       ERROR_CHECK(result);
+       xoffset =
+           (short) ((unsigned short) rawData[5] +
+                    ((unsigned short) rawData[4] & 0x7) * 256) - 5;
+       if (xoffset < 0)
+               xoffset = 0;
+       y1offset =
+           (short) ((unsigned short) rawData[3] +
+                    ((unsigned short) rawData[2] & 0x7) * 256) - 5;
+       if (y1offset < 0)
+               y1offset = 0;
+       y2offset =
+           (short) ((unsigned short) rawData[1] +
+                    ((unsigned short) rawData[0] & 0x7) * 256) - 5;
+       if (y2offset < 0)
+               y2offset = 0;
+
+       /* Step 4 - rough offset setting */
+       /* Set rough offset register values */
+       dummyData[0] = YAS_REG_XOFFSETR | xoffset;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_Y1OFFSETR | y1offset;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       dummyData[0] = YAS_REG_Y2OFFSETR | y2offset;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+
+       /* CAL matrix read (first read is invalid) */
+       /* Config register - CAL register read - "110 01 000" */
+       dummyData[0] = YAS_REG_CONFR | 0x08;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       /* CAL data read */
+       result =
+           yas529_sensor_i2c_read(mlsl_handle, pdata->address,
+                                  dummyRegister, 9, calData);
+       ERROR_CHECK(result);
+       /* Config register - CAL register read - "110 01 000" */
+       dummyData[0] = YAS_REG_CONFR | 0x08;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       /* CAL data read */
+       result =
+           yas529_sensor_i2c_read(mlsl_handle, pdata->address,
+                                  dummyRegister, 9, calData);
+       ERROR_CHECK(result);
+
+       /* Calculate coefficients of the sensitivity corrcetion matrix */
+#if 1                          /* production sensor */
+       a1 = 100;
+       d2 = (calData[0] & 0xFC) >> 2;  /* [71..66] 6bit */
+       a2 = (short) (d2 - 32);
+       /* [65..62] 4bit */
+       d3 = ((calData[0] & 0x03) << 2) | ((calData[1] & 0xC0) >> 6);
+       a3 = (short) (d3 - 8);
+       d4 = (calData[1] & 0x3F);       /* [61..56] 6bit */
+       a4 = (short) (d4 - 32);
+       d5 = (calData[2] & 0xFC) >> 2;  /* [55..50] 6bit */
+       a5 = (short) (d5 - 32) + 70;
+       /* [49..44] 6bit */
+       d6 = ((calData[2] & 0x03) << 4) | ((calData[3] & 0xF0) >> 4);
+       a6 = (short) (d6 - 32);
+       /* [43..38] 6bit */
+       d7 = ((calData[3] & 0x0F) << 2) | ((calData[4] & 0xC0) >> 6);
+       a7 = (short) (d7 - 32);
+       d8 = (calData[4] & 0x3F);       /* [37..32] 6bit */
+       a8 = (short) (d8 - 32);
+       d9 = (calData[5] & 0xFE) >> 1;  /* [31..25] 7bit */
+       a9 = (short) (d9 - 64) + 130;
+#else                          /* evaluation sensor */
+       a1 = 1.0f;
+       /* [71..66] 6bit */
+       d2 = (calData[0] & 0xFC) >> 2;
+       a2 = (short) d2;
+       /* [65..60] 6bit */
+       d3 = ((calData[0] & 0x03) << 4) | ((calData[1] & 0xF0) >> 4);
+       a3 = (short) d3;
+       /* [59..54] 6bit */
+       d4 = ((calData[1] & 0x0F) << 2) | ((calData[2] & 0xC0) >> 6);
+       a4 = (short) d4;
+       /* [53..48] 6bit */
+       d5 = (calData[2] & 0x3F);
+       a5 = (short) (d5 + 70);
+       /* [47..42] 6bit */
+       d6 = ((calData[3] & 0xFC) >> 2);
+       a6 = (short) d6;
+       /* [41..36] 6bit */
+       d7 = ((calData[3] & 0x03) << 4) | ((calData[4] & 0xF0) >> 4);
+       a7 = (short) d7;
+       /* [35..30] 6bit */
+       d8 = ((calData[4] & 0x0F) << 2) | ((calData[5] & 0xC0) >> 6);
+       a8 = (short) d8;
+       /* [29..24] 6bit */
+       d9 = (calData[5] & 0x3F);
+       a9 = (short) (d9 + 150);
+#endif
+
+       return result;
+}
+
+int yas529_read(void *mlsl_handle,
+               struct ext_slave_descr *slave,
+               struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+       unsigned char stat;
+       unsigned char rawData[6];
+       unsigned char dummyData[1] = { 0 };
+       unsigned char dummyRegister = 0;
+       tMLError result = ML_SUCCESS;
+       short SX, SY1, SY2, SY, SZ;
+       short row1fixed, row2fixed, row3fixed;
+
+       /* Config register - Measurements results - "110 00 000" */
+       dummyData[0] = YAS_REG_CONFR | 0x00;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       /* Measurements command register - Normal magnetic field measurement -
+          "000 00000" */
+       dummyData[0] = YAS_REG_CMDR | 0x00;
+       result =
+           yas529_sensor_i2c_write(mlsl_handle, pdata->address, 1,
+                                   dummyData);
+       ERROR_CHECK(result);
+       MLOSSleep(10);
+       /* Measurement data read */
+       result =
+           yas529_sensor_i2c_read(mlsl_handle, pdata->address,
+                                  dummyRegister, 6,
+                                  (unsigned char *) &rawData);
+       ERROR_CHECK(result);
+
+       stat = rawData[0] & 0x80;
+       if (stat == 0x00) {
+               /* Extract raw data */
+               SX = (short) ((unsigned short) rawData[5] +
+                             ((unsigned short) rawData[4] & 0x7) * 256);
+               SY1 =
+                   (short) ((unsigned short) rawData[3] +
+                            ((unsigned short) rawData[2] & 0x7) * 256);
+               SY2 =
+                   (short) ((unsigned short) rawData[1] +
+                            ((unsigned short) rawData[0] & 0x7) * 256);
+               if ((SX <= 1) || (SY1 <= 1) || (SY2 <= 1))
+                       return ML_ERROR_COMPASS_DATA_UNDERFLOW;
+               if ((SX >= 1024) || (SY1 >= 1024) || (SY2 >= 1024))
+                       return ML_ERROR_COMPASS_DATA_OVERFLOW;
+               /* Convert to XYZ axis */
+               SX = -1 * SX;
+               SY = SY2 - SY1;
+               SZ = SY1 + SY2;
+
+               /* Apply sensitivity correction matrix */
+               row1fixed =
+                   (short) ((a1 * SX + a2 * SY + a3 * SZ) >> 7) * 41;
+               row2fixed =
+                   (short) ((a4 * SX + a5 * SY + a6 * SZ) >> 7) * 41;
+               row3fixed =
+                   (short) ((a7 * SX + a8 * SY + a9 * SZ) >> 7) * 41;
+
+               data[0] = row1fixed >> 8;
+               data[1] = row1fixed & 0xFF;
+               data[2] = row2fixed >> 8;
+               data[3] = row2fixed & 0xFF;
+               data[4] = row3fixed >> 8;
+               data[5] = row3fixed & 0xFF;
+
+               return ML_SUCCESS;
+       } else {
+               return ML_ERROR_COMPASS_DATA_NOT_READY;
+       }
+}
+
+struct ext_slave_descr yas529_descr = {
+       /*.init             = */ NULL,
+       /*.exit             = */ NULL,
+       /*.suspend          = */ yas529_suspend,
+       /*.resume           = */ yas529_resume,
+       /*.read             = */ yas529_read,
+       /*.config           = */ NULL,
+       /*.name             = */ "yas529",
+       /*.type             = */ EXT_SLAVE_TYPE_COMPASS,
+       /*.id               = */ COMPASS_ID_YAS529,
+       /*.reg              = */ 0x06,
+       /*.len              = */ 6,
+       /*.endian           = */ EXT_SLAVE_BIG_ENDIAN,
+       /*.range            = */ {19660, 8000},
+};
+
+struct ext_slave_descr *yas529_get_slave_descr(void)
+{
+       return &yas529_descr;
+}
+EXPORT_SYMBOL(yas529_get_slave_descr);
+
+/**
+ *  @}
+ */
diff --git a/drivers/misc/mpu3050/log.h b/drivers/misc/mpu3050/log.h
new file mode 100644 (file)
index 0000000..ceee285
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * 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.
+ */
+#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.
+ */
+#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__)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * 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 100644 (file)
index 0000000..220103b
--- /dev/null
@@ -0,0 +1,1646 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+/*******************************************************************************
+ *
+ * $Id: mldl_cfg.c 4635 2011-01-27 07:49:49Z nroyer $
+ *
+ ******************************************************************************/
+
+/**
+ *  @addtogroup MLDL
+ *
+ *  @{
+ *      @file   mldl_cfg.c
+ *      @brief  The Motion Library Driver Layer.
+ */
+
+/* ------------------ */
+/* - Include Files. - */
+/* ------------------ */
+
+#include <stddef.h>
+
+#include "mldl_cfg.h"
+#include "mpu.h"
+
+#include "mlsl.h"
+#include "mlos.h"
+
+#include "log.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "mldl_cfg:"
+
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+#ifdef M_HW
+#define SLEEP   0
+#define WAKE_UP 7
+#define RESET   1
+#define STANDBY 1
+#else
+/* licteral significance of all parameters used in MLDLPowerMgmtMPU */
+#define SLEEP   1
+#define WAKE_UP 0
+#define RESET   1
+#define STANDBY 1
+#endif
+
+/*---------------------*/
+/*-    Prototypes.    -*/
+/*---------------------*/
+
+/*----------------------*/
+/*-  Static Functions. -*/
+/*----------------------*/
+
+static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle)
+{
+       unsigned char userCtrlReg;
+       int result;
+
+       if (!mldl_cfg->dmp_is_running)
+               return ML_SUCCESS;
+
+       result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+                               MPUREG_USER_CTRL, 1, &userCtrlReg);
+       ERROR_CHECK(result);
+       userCtrlReg = (userCtrlReg & (~BIT_FIFO_EN)) | BIT_FIFO_RST;
+       userCtrlReg = (userCtrlReg & (~BIT_DMP_EN)) | BIT_DMP_RST;
+
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                                      MPUREG_USER_CTRL, userCtrlReg);
+       ERROR_CHECK(result);
+       mldl_cfg->dmp_is_running = 0;
+
+       return result;
+
+}
+/**
+ * @brief Starts the DMP running
+ *
+ * @return ML_SUCCESS or non-zero error code
+ */
+static int dmp_start(struct mldl_cfg *pdata, void *mlsl_handle)
+{
+       unsigned char userCtrlReg;
+       int result;
+
+       if (pdata->dmp_is_running == pdata->dmp_enable)
+               return ML_SUCCESS;
+
+       result = MLSLSerialRead(mlsl_handle, pdata->addr,
+                               MPUREG_USER_CTRL, 1, &userCtrlReg);
+       ERROR_CHECK(result);
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                      MPUREG_USER_CTRL,
+                                      ((userCtrlReg & (~BIT_FIFO_EN))
+                                               |   BIT_FIFO_RST));
+       ERROR_CHECK(result);
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                      MPUREG_USER_CTRL, userCtrlReg);
+       ERROR_CHECK(result);
+
+       result = MLSLSerialRead(mlsl_handle, pdata->addr,
+                               MPUREG_USER_CTRL, 1, &userCtrlReg);
+       ERROR_CHECK(result);
+
+       if (pdata->dmp_enable)
+               userCtrlReg |= BIT_DMP_EN;
+       else
+               userCtrlReg &= ~BIT_DMP_EN;
+
+       if (pdata->fifo_enable)
+               userCtrlReg |= BIT_FIFO_EN;
+       else
+               userCtrlReg &= ~BIT_FIFO_EN;
+
+       userCtrlReg |= BIT_DMP_RST;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                      MPUREG_USER_CTRL, userCtrlReg);
+       ERROR_CHECK(result);
+       pdata->dmp_is_running = pdata->dmp_enable;
+
+       return result;
+}
+
+/**
+ *  @brief  enables/disables the I2C bypass to an external device
+ *          connected to MPU's secondary I2C bus.
+ *  @param  enable
+ *              Non-zero to enable pass through.
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg,
+                           void *mlsl_handle,
+                           unsigned char enable)
+{
+       unsigned char b;
+       int result;
+
+       if ((mldl_cfg->gyro_is_bypassed && enable) ||
+           (!mldl_cfg->gyro_is_bypassed && !enable))
+               return ML_SUCCESS;
+
+       /*---- get current 'USER_CTRL' into b ----*/
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_USER_CTRL, 1, &b);
+       ERROR_CHECK(result);
+
+       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 several erratta.  Do not
+                * modify this algorithm
+                */
+               /*
+                * 1) wait for the right time and send the command to change
+                * the aux i2c slave address to an invalid address that will
+                * get nack'ed
+                *
+                * 0x00 is broadcast.  0x7F is unlikely to be used by any aux.
+                */
+               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(SAMPLING_PERIOD_US(mldl_cfg) / 1000);
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_AUX_SLV_ADDR,
+                                              mldl_cfg->pdata->
+                                              accel.address);
+               ERROR_CHECK(result);
+
+               /*
+                * 4) reset the ime interface
+                */
+#ifdef M_HW
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_USER_CTRL,
+                                              (b | BIT_I2C_MST_RST));
+
+#else
+               result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+                                              MPUREG_USER_CTRL,
+                                              (b | BIT_AUX_IF_RST));
+#endif
+               ERROR_CHECK(result);
+               MLOSSleep(2);
+       }
+       mldl_cfg->gyro_is_bypassed = enable;
+
+       return result;
+}
+
+struct tsProdRevMap {
+       unsigned char siliconRev;
+       unsigned short sensTrim;
+};
+
+#define NUM_OF_PROD_REVS (DIM(prodRevsMap))
+
+/* NOTE : 'npp' is a non production part */
+#ifdef M_HW
+#define OLDEST_PROD_REV_SUPPORTED 1
+static struct tsProdRevMap prodRevsMap[] = {
+       {0, 0},
+       {MPU_SILICON_REV_A1, 131},      /* 1 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 2 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 3 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 4 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 5 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 6 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 7 A1 (npp) */
+       {MPU_SILICON_REV_A1, 131},      /* 8 A1 (npp) */
+};
+
+#else                          /* !M_HW */
+#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 (B6/A9)  */
+       {MPU_SILICON_REV_B4, 115},      /* 22 B4 (B7/A10) */
+       {MPU_SILICON_REV_B6, 0},        /* 23 B6 (npp)    */
+       {MPU_SILICON_REV_B6, 0},        /* 24 |  (npp)    */
+       {MPU_SILICON_REV_B6, 0},        /* 25 V  (npp)    */
+       {MPU_SILICON_REV_B6, 131},      /* 26    (B6/A11) */
+};
+#endif                         /* !M_HW */
+
+/**
+ *  @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,
+                            void *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);
+       ERROR_CHECK(result)
+       if (result)
+               return result;
+       index >>= 2;
+
+       /* clean the prefetch and cfg user bank bits */
+       result =
+           MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                 MPUREG_BANK_SEL, 0);
+       ERROR_CHECK(result)
+       if (result)
+               return result;
+
+       if (index < OLDEST_PROD_REV_SUPPORTED || NUM_OF_PROD_REVS <= index) {
+               pdata->silicon_revision = 0;
+               pdata->trim = 0;
+               MPL_LOGE("Unsupported Product Revision Detected : %d\n", index);
+               return ML_ERROR_INVALID_MODULE;
+       }
+
+       pdata->silicon_revision = prodRevsMap[index].siliconRev;
+       pdata->trim = prodRevsMap[index].sensTrim;
+
+       if (pdata->trim == 0) {
+               MPL_LOGE("sensitivity trim is 0"
+                        " - unsupported non production part.\n");
+               return ML_ERROR_INVALID_MODULE;
+       }
+
+       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,
+                                 void *mlsl_handle,
+                                 unsigned char enable)
+{
+#ifndef M_HW
+       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;
+#else
+       return ML_SUCCESS;
+#endif
+}
+
+
+#ifdef M_HW
+/**
+ *  @internal
+ * @param reset 1 to reset hardware
+ */
+static tMLError mpu60xx_pwr_mgmt(struct mldl_cfg *pdata,
+                                void *mlsl_handle,
+                                unsigned char reset,
+                                unsigned char powerselection)
+{
+       unsigned char b;
+       tMLError result;
+
+       if (powerselection < 0 || powerselection > 7)
+               return ML_ERROR_INVALID_PARAMETER;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_1, 1,
+                          &b);
+       ERROR_CHECK(result);
+
+       b &= ~(BITS_PWRSEL);
+
+       if (reset) {
+               /* Current sillicon has an errata where the reset will get
+                * nacked.  Ignore the error code for now. */
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                              MPUREG_PWR_MGM, b | BIT_H_RESET);
+#define M_HW_RESET_ERRATTA
+#ifndef M_HW_RESET_ERRATTA
+               ERROR_CHECK(result);
+#else
+               MLOSSleep(50);
+#endif
+       }
+
+       b |= (powerselection << 4);
+
+       if (b & BITS_PWRSEL)
+               pdata->gyro_is_suspended = FALSE;
+       else
+               pdata->gyro_is_suspended = TRUE;
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                      MPUREG_PWR_MGM, b);
+       ERROR_CHECK(result);
+
+       return ML_SUCCESS;
+}
+
+/**
+ *  @internal
+ */
+static tMLError MLDLStandByGyros(struct mldl_cfg *pdata,
+                                void *mlsl_handle,
+                                unsigned char disable_gx,
+                                unsigned char disable_gy,
+                                unsigned char disable_gz)
+{
+       unsigned char b;
+       tMLError result;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1,
+                          &b);
+       ERROR_CHECK(result);
+
+       b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
+       b |= (disable_gx << 2 | disable_gy << 1 | disable_gz);
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                      MPUREG_PWR_MGMT_2, b);
+       ERROR_CHECK(result);
+
+       return ML_SUCCESS;
+}
+
+/**
+ *  @internal
+ */
+static tMLError MLDLStandByAccels(struct mldl_cfg *pdata,
+                                 void *mlsl_handle,
+                                 unsigned char disable_ax,
+                                 unsigned char disable_ay,
+                                 unsigned char disable_az)
+{
+       unsigned char b;
+       tMLError result;
+
+       result =
+           MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1,
+                          &b);
+       ERROR_CHECK(result);
+
+       b &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
+       b |= (disable_ax << 2 | disable_ay << 1 | disable_az);
+
+       result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                      MPUREG_PWR_MGMT_2, b);
+       ERROR_CHECK(result);
+
+       return ML_SUCCESS;
+}
+
+#else                          /* ! M_HW */
+
+/**
+ * @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 being applied.
+ * @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,
+                           void *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);
+
+       /* If we are awake, we need stop the dmp sleeping */
+       if ((!(b & BIT_SLEEP)) && sleep)
+               dmp_stop(pdata, mlsl_handle);
+
+       /* Reset if requested */
+       if (reset) {
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                       MPUREG_PWR_MGM, b | BIT_H_RESET);
+               ERROR_CHECK(result);
+               MLOSSleep(5);
+               pdata->gyro_needs_reset = FALSE;
+               /* 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->gyro_is_suspended = TRUE;
+       else
+               pdata->gyro_is_suspended = FALSE;
+
+       /* if power status match requested, nothing else's left to do */
+       if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
+               (((sleep != 0) * BIT_SLEEP) |
+               ((disable_gx != 0) * BIT_STBY_XG) |
+               ((disable_gy != 0) * BIT_STBY_YG) |
+               ((disable_gz != 0) * 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) is (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)
+               && ((!sleep) && disable_gx && disable_gy && disable_gz)) {
+               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 != 0) * 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->gyro_is_suspended = TRUE;
+               } else {
+                       b &= ~BIT_SLEEP;
+                       result =
+                           MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                                 MPUREG_PWR_MGM, b);
+                       ERROR_CHECK(result);
+                       pdata->gyro_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 != 0) * 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 != 0) * 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 != 0) * BIT_STBY_ZG)) {
+               b ^= BIT_STBY_ZG;
+               result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+                                              MPUREG_PWR_MGM, b);
+               ERROR_CHECK(result);
+       }
+
+       return ML_SUCCESS;
+}
+#endif                         /* M_HW */
+
+
+void mpu_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;
+       struct ext_slave_platform_data *pressure =
+           &mldl_cfg->pdata->pressure;
+
+       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);
+       MPL_LOGD("mldl_cfg.requested_sensors= %04lx\n",
+                mldl_cfg->requested_sensors);
+
+       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");
+       }
+
+       if (mldl_cfg->pressure) {
+               MPL_LOGD("slave_pressure->suspend    = %02x\n",
+                        (int) mldl_cfg->pressure->suspend);
+               MPL_LOGD("slave_pressure->resume     = %02x\n",
+                        (int) mldl_cfg->pressure->resume);
+               MPL_LOGD("slave_pressure->read       = %02x\n",
+                        (int) mldl_cfg->pressure->read);
+               MPL_LOGD("slave_pressure->type       = %02x\n",
+                        mldl_cfg->pressure->type);
+               MPL_LOGD("slave_pressure->reg        = %02x\n",
+                        mldl_cfg->pressure->reg);
+               MPL_LOGD("slave_pressure->len        = %02x\n",
+                        mldl_cfg->pressure->len);
+               MPL_LOGD("slave_pressure->endian     = %02x\n",
+                        mldl_cfg->pressure->endian);
+               MPL_LOGD("slave_pressure->range.mantissa= %02lx\n",
+                        mldl_cfg->pressure->range.mantissa);
+               MPL_LOGD("slave_pressure->range.fraction= %02lx\n",
+                        mldl_cfg->pressure->range.fraction);
+
+       } else {
+               MPL_LOGD("slave_pressure             = NULL\n");
+       }
+       MPL_LOGD("accel->get_slave_descr    = %x\n",
+                (unsigned int) accel->get_slave_descr);
+       MPL_LOGD("accel->irq                = %02x\n", accel->irq);
+       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->irq              = %02x\n", compass->irq);
+       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("pressure->get_slave_descr  = %x\n",
+                (unsigned int) pressure->get_slave_descr);
+       MPL_LOGD("pressure->irq             = %02x\n", pressure->irq);
+       MPL_LOGD("pressure->adapt_num       = %02x\n", pressure->adapt_num);
+       MPL_LOGD("pressure->bus             = %02x\n", pressure->bus);
+       MPL_LOGD("pressure->address         = %02x\n", pressure->address);
+       MPL_LOGD("pressure->orientation     =\n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n"
+                "                            %2d %2d %2d\n",
+                pressure->orientation[0], pressure->orientation[1],
+                pressure->orientation[2], pressure->orientation[3],
+                pressure->orientation[4], pressure->orientation[5],
+                pressure->orientation[6], pressure->orientation[7],
+                pressure->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));
+}
+
+int mpu_set_slave(struct mldl_cfg *mldl_cfg,
+               void *gyro_handle,
+               struct ext_slave_descr *slave,
+               struct ext_slave_platform_data *slave_pdata)
+{
+       int result;
+       unsigned char reg;
+       unsigned char slave_reg;
+       unsigned char slave_len;
+       unsigned char slave_endian;
+       unsigned char slave_address;
+
+       result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+
+       if (NULL == slave || NULL == slave_pdata) {
+               slave_reg = 0;
+               slave_len = 0;
+               slave_endian = 0;
+               slave_address = 0;
+       } else {
+               slave_reg = slave->reg;
+               slave_len = slave->len;
+               slave_endian = slave->endian;
+               slave_address = slave_pdata->address;
+       }
+
+       /* Address */
+       result = MLSLSerialWriteSingle(gyro_handle,
+                               mldl_cfg->addr,
+                               MPUREG_AUX_SLV_ADDR,
+                               slave_address);
+       ERROR_CHECK(result);
+       /* Register */
+       result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+                               MPUREG_ACCEL_BURST_ADDR, 1,
+                               &reg);
+       ERROR_CHECK(result);
+       reg = ((reg & 0x80) | slave_reg);
+       result = MLSLSerialWriteSingle(gyro_handle,
+                               mldl_cfg->addr,
+                               MPUREG_ACCEL_BURST_ADDR,
+                               reg);
+       ERROR_CHECK(result);
+
+#ifdef M_HW
+       /* Length, byte swapping, grouping & enable */
+       if (slave_len > BITS_SLV_LENG) {
+               MPL_LOGW("Limiting slave burst read length to "
+                       "the allowed maximum (15B, req. %d)\n",
+                       slave_len);
+               slave_len = BITS_SLV_LENG;
+       }
+       reg = slave_len;
+       if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN)
+               reg |= BIT_SLV_BYTE_SW;
+       reg |= BIT_SLV_GRP;
+       reg |= BIT_SLV_ENABLE;
+
+       result = MLSLSerialWriteSingle(gyro_handle,
+                               mldl_cfg->addr,
+                               MPUREG_I2C_SLV0_CTRL,
+                               reg);
+#else
+       /* Length */
+       result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+                               MPUREG_USER_CTRL, 1, &reg);
+       ERROR_CHECK(result);
+       reg = (reg & ~BIT_AUX_RD_LENG);
+       result = MLSLSerialWriteSingle(gyro_handle,
+                               mldl_cfg->addr,
+                               MPUREG_USER_CTRL, reg);
+       ERROR_CHECK(result);
+#endif
+
+       if (slave_address) {
+               result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, FALSE);
+               ERROR_CHECK(result);
+       }
+       return result;
+}
+
+/**
+ * Check to see if the gyro was reset by testing a couple of registers known
+ * to change on reset.
+ *
+ * @param mldl_cfg mldl configuration structure
+ * @param gyro_handle handle used to communicate with the gyro
+ *
+ * @return ML_SUCCESS or non-zero error code
+ */
+static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle)
+{
+       int result = ML_SUCCESS;
+       unsigned char reg;
+
+       result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+                               MPUREG_DMP_CFG_2, 1, &reg);
+       ERROR_CHECK(result);
+
+       if (mldl_cfg->dmp_cfg2 != reg)
+               return TRUE;
+
+       if (0 != mldl_cfg->dmp_cfg1)
+               return FALSE;
+
+       result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+                               MPUREG_SMPLRT_DIV, 1, &reg);
+       ERROR_CHECK(result);
+       if (reg != mldl_cfg->divider)
+               return TRUE;
+
+       if (0 != mldl_cfg->divider)
+               return FALSE;
+
+       /* Inconclusive assume it was reset */
+       return TRUE;
+}
+
+static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle)
+{
+       int result;
+       int ii;
+       int jj;
+       unsigned char reg;
+       unsigned char regs[7];
+
+       /* Wake up the part */
+#ifdef M_HW
+       result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, RESET,
+                               WAKE_UP);
+       ERROR_CHECK(result);
+
+       /* Configure the MPU */
+       result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1);
+       ERROR_CHECK(result);
+       /* setting int_config with the propert flag BIT_BYPASS_EN
+          should be done by the setup functions */
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_INT_PIN_CFG,
+                               (mldl_cfg->pdata->int_config |
+                                       BIT_BYPASS_EN));
+       ERROR_CHECK(result);
+       /* temporary: masking out higher bits to avoid switching
+          intelligence */
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_INT_ENABLE,
+                               (mldl_cfg->int_config));
+       ERROR_CHECK(result);
+#else
+       result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 0, 0,
+                               mldl_cfg->gyro_power & BIT_STBY_XG,
+                               mldl_cfg->gyro_power & BIT_STBY_YG,
+                               mldl_cfg->gyro_power & BIT_STBY_ZG);
+
+       if (!mldl_cfg->gyro_needs_reset &&
+           !mpu_was_reset(mldl_cfg, gyro_handle)) {
+               return ML_SUCCESS;
+       }
+
+       result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 1, 0,
+                               mldl_cfg->gyro_power & BIT_STBY_XG,
+                               mldl_cfg->gyro_power & BIT_STBY_YG,
+                               mldl_cfg->gyro_power & BIT_STBY_ZG);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_INT_CFG,
+                               (mldl_cfg->int_config |
+                                       mldl_cfg->pdata->int_config));
+       ERROR_CHECK(result);
+#endif
+
+       result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+                               MPUREG_PWR_MGM, 1, &reg);
+       ERROR_CHECK(result);
+       reg &= ~BITS_CLKSEL;
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_PWR_MGM,
+                               mldl_cfg->clk_src | reg);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_SMPLRT_DIV,
+                               mldl_cfg->divider);
+       ERROR_CHECK(result);
+
+#ifdef M_HW
+       reg = DLPF_FS_SYNC_VALUE(0, mldl_cfg->full_scale, 0);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_GYRO_CONFIG, reg);
+       reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, 0, mldl_cfg->lpf);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_CONFIG, reg);
+#else
+       reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync,
+                               mldl_cfg->full_scale, mldl_cfg->lpf);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_DLPF_FS_SYNC, reg);
+#endif
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_DMP_CFG_1,
+                               mldl_cfg->dmp_cfg1);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(gyro_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[MPU_MEM_BANK_SIZE];
+
+               result = MLSLSerialWriteMem(gyro_handle,
+                                       mldl_cfg->addr,
+                                       ((ii << 8) | 0x00),
+                                       MPU_MEM_BANK_SIZE,
+                                       mldl_cfg->ram[ii]);
+               ERROR_CHECK(result);
+               result = MLSLSerialReadMem(gyro_handle, mldl_cfg->addr,
+                                       ((ii << 8) | 0x00),
+                                       MPU_MEM_BANK_SIZE, read);
+               ERROR_CHECK(result);
+
+#ifdef M_HW
+#define ML_SKIP_CHECK 38
+#else
+#define ML_SKIP_CHECK 20
+#endif
+               for (jj = 0; jj < MPU_MEM_BANK_SIZE; jj++) {
+                       /* skip the register memory locations */
+                       if (ii == 0 && jj < ML_SKIP_CHECK)
+                               continue;
+                       if (mldl_cfg->ram[ii][jj] != read[jj]) {
+                               result = ML_ERROR_SERIAL_WRITE;
+                               break;
+                       }
+               }
+               ERROR_CHECK(result);
+       }
+
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_XG_OFFS_TC,
+                               mldl_cfg->offset_tc[0]);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_YG_OFFS_TC,
+                               mldl_cfg->offset_tc[1]);
+       ERROR_CHECK(result);
+       result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+                               MPUREG_ZG_OFFS_TC,
+                               mldl_cfg->offset_tc[2]);
+       ERROR_CHECK(result);
+
+       regs[0] = MPUREG_X_OFFS_USRH;
+       for (ii = 0; ii < DIM(mldl_cfg->offset); ii++) {
+               regs[1 + ii * 2] =
+                       (unsigned char)(mldl_cfg->offset[ii] >> 8)
+                       & 0xff;
+               regs[1 + ii * 2 + 1] =
+                       (unsigned char)(mldl_cfg->offset[ii] & 0xff);
+       }
+       result = MLSLSerialWrite(gyro_handle, mldl_cfg->addr, 7, regs);
+       ERROR_CHECK(result);
+
+       /* Configure slaves */
+       result = MLDLSetLevelShifterBit(mldl_cfg, gyro_handle,
+                                       mldl_cfg->pdata->level_shifter);
+       ERROR_CHECK(result);
+       return result;
+}
+/*******************************************************************************
+ *******************************************************************************
+ * 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,
+                void *mlsl_handle,
+                void *accel_handle,
+                void *compass_handle,
+                void *pressure_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;
+       mldl_cfg->gyro_power = 0;
+       mldl_cfg->gyro_is_bypassed = TRUE;
+       mldl_cfg->dmp_is_running = FALSE;
+       mldl_cfg->gyro_is_suspended = TRUE;
+       mldl_cfg->accel_is_suspended = TRUE;
+       mldl_cfg->compass_is_suspended = TRUE;
+       mldl_cfg->pressure_is_suspended = TRUE;
+       mldl_cfg->gyro_needs_reset = FALSE;
+       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
+        */
+#ifdef M_HW
+       result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle,
+                                 RESET, WAKE_UP);
+#else
+       result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, RESET, 0, 0, 0, 0);
+#endif
+       ERROR_CHECK(result);
+
+       result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle);
+       ERROR_CHECK(result);
+#ifndef M_HW
+       result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+                               MPUREG_PRODUCT_ID, 1,
+                               &mldl_cfg->product_id);
+       ERROR_CHECK(result);
+#endif
+
+       /* 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 */
+#ifdef M_HW
+       result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle,
+                                 FALSE, SLEEP);
+#else
+       result =
+           MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, SLEEP, 0, 0, 0);
+#endif
+       ERROR_CHECK(result);
+
+       if (mldl_cfg->accel && mldl_cfg->accel->init) {
+               result = mldl_cfg->accel->init(accel_handle,
+                                              mldl_cfg->accel,
+                                              &mldl_cfg->pdata->accel);
+               ERROR_CHECK(result);
+       }
+
+       if (mldl_cfg->compass && mldl_cfg->compass->init) {
+               result = mldl_cfg->compass->init(compass_handle,
+                                                mldl_cfg->compass,
+                                                &mldl_cfg->pdata->compass);
+               if (ML_SUCCESS != result) {
+                       MPL_LOGE("mldl_cfg->compass->init returned %d\n",
+                               result);
+                       goto out_accel;
+               }
+       }
+       if (mldl_cfg->pressure && mldl_cfg->pressure->init) {
+               result = mldl_cfg->pressure->init(pressure_handle,
+                                                 mldl_cfg->pressure,
+                                                 &mldl_cfg->pdata->pressure);
+               if (ML_SUCCESS != result) {
+                       MPL_LOGE("mldl_cfg->pressure->init returned %d\n",
+                               result);
+                       goto out_compass;
+               }
+       }
+
+       mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO;
+       if (mldl_cfg->accel && mldl_cfg->accel->resume)
+               mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL;
+
+       if (mldl_cfg->compass && mldl_cfg->compass->resume)
+               mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS;
+
+       if (mldl_cfg->pressure && mldl_cfg->pressure->resume)
+               mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE;
+
+       return result;
+
+out_compass:
+       if (mldl_cfg->compass->init)
+               mldl_cfg->compass->exit(compass_handle,
+                               mldl_cfg->compass,
+                               &mldl_cfg->pdata->compass);
+out_accel:
+       if (mldl_cfg->accel->init)
+               mldl_cfg->accel->exit(accel_handle,
+                               mldl_cfg->accel,
+                               &mldl_cfg->pdata->accel);
+       return result;
+
+}
+
+/**
+ * Close the mpu3050 interface
+ *
+ * @param mldl_cfg pointer to the configuration structure
+ * @param mlsl_handle pointer to the serial layer handle
+ *
+ * @return ML_SUCCESS or non-zero error code
+ */
+int mpu3050_close(struct mldl_cfg *mldl_cfg,
+                 void *mlsl_handle,
+                 void *accel_handle,
+                 void *compass_handle,
+                 void *pressure_handle)
+{
+       int result = ML_SUCCESS;
+       int ret_result = ML_SUCCESS;
+
+       if (mldl_cfg->accel && mldl_cfg->accel->exit) {
+               result = mldl_cfg->accel->exit(accel_handle,
+                                       mldl_cfg->accel,
+                                       &mldl_cfg->pdata->accel);
+               if (ML_SUCCESS != result)
+                       MPL_LOGE("Accel exit failed %d\n", result);
+               ret_result = result;
+       }
+       if (ML_SUCCESS == ret_result)
+               ret_result = result;
+
+       if (mldl_cfg->compass && mldl_cfg->compass->exit) {
+               result = mldl_cfg->compass->exit(compass_handle,
+                                               mldl_cfg->compass,
+                                               &mldl_cfg->pdata->compass);
+               if (ML_SUCCESS != result)
+                       MPL_LOGE("Compass exit failed %d\n", result);
+       }
+       if (ML_SUCCESS == ret_result)
+               ret_result = result;
+
+       if (mldl_cfg->pressure && mldl_cfg->pressure->exit) {
+               result = mldl_cfg->pressure->exit(pressure_handle,
+                                               mldl_cfg->pressure,
+                                               &mldl_cfg->pdata->pressure);
+               if (ML_SUCCESS != result)
+                       MPL_LOGE("Pressure exit failed %d\n", result);
+       }
+       if (ML_SUCCESS == ret_result)
+               ret_result = result;
+
+       return ret_result;
+}
+
+/**
+ *  @brief  resume the MPU3050 device and all the other sensor
+ *          devices from their low power state.
+ *  @param  mlsl_handle
+ *              the main file handle to the MPU3050 device.
+ *  @param  accel_handle
+ *              an handle to the accelerometer device, if sitting
+ *              onto a separate bus. Can match mlsl_handle if
+ *              the accelerometer device operates on the same
+ *              primary bus of MPU.
+ *  @param  compass_handle
+ *              an handle to the compass device, if sitting
+ *              onto a separate bus. Can match mlsl_handle if
+ *              the compass device operates on the same
+ *              primary bus of MPU.
+ *  @param  pressure_handle
+ *              an handle to the pressure sensor device, if sitting
+ *              onto a separate bus. Can match mlsl_handle if
+ *              the pressure sensor device operates on the same
+ *              primary bus of MPU.
+ *  @param  resume_accel
+ *              whether resuming the accelerometer device is
+ *              actually needed (if the device supports low power
+ *              mode of some sort).
+ *  @param  resume_compass
+ *              whether resuming the compass device is
+ *              actually needed (if the device supports low power
+ *              mode of some sort).
+ *  @param  resume_pressure
+ *              whether resuming the pressure sensor device is
+ *              actually needed (if the device supports low power
+ *              mode of some sort).
+ *  @return  ML_SUCCESS or a non-zero error code.
+ */
+int mpu3050_resume(struct mldl_cfg *mldl_cfg,
+                  void *gyro_handle,
+                  void *accel_handle,
+                  void *compass_handle,
+                  void *pressure_handle,
+                  bool resume_gyro,
+                  bool resume_accel,
+                  bool resume_compass,
+                  bool resume_pressure)
+{
+       int result = ML_SUCCESS;
+
+#ifdef CONFIG_SENSORS_MPU_DEBUG
+       mpu_print_cfg(mldl_cfg);
+#endif
+
+       if (resume_accel &&
+           ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume)))
+               return ML_ERROR_INVALID_PARAMETER;
+       if (resume_compass &&
+           ((!mldl_cfg->compass) || (!mldl_cfg->compass->resume)))
+               return ML_ERROR_INVALID_PARAMETER;
+       if (resume_pressure &&
+           ((!mldl_cfg->pressure) || (!mldl_cfg->pressure->resume)))
+               return ML_ERROR_INVALID_PARAMETER;
+
+       if (resume_gyro && mldl_cfg->gyro_is_suspended) {
+               result = gyro_resume(mldl_cfg, gyro_handle);
+               ERROR_CHECK(result);
+       }
+
+       if (resume_accel && mldl_cfg->accel_is_suspended) {
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+                       result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+                       ERROR_CHECK(result);
+               }
+               result = mldl_cfg->accel->resume(accel_handle,
+                                                mldl_cfg->accel,
+                                                &mldl_cfg->pdata->accel);
+               ERROR_CHECK(result);
+               mldl_cfg->accel_is_suspended = FALSE;
+
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+                       result = mpu_set_slave(mldl_cfg,
+                                              gyro_handle,
+                                              mldl_cfg->accel,
+                                              &mldl_cfg->pdata->accel);
+                       ERROR_CHECK(result);
+               }
+       }
+
+       if (resume_compass && mldl_cfg->compass_is_suspended) {
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
+                       result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+                       ERROR_CHECK(result);
+               }
+               result = mldl_cfg->compass->resume(compass_handle,
+                                                  mldl_cfg->compass,
+                                                  &mldl_cfg->pdata->
+                                                  compass);
+               ERROR_CHECK(result);
+               mldl_cfg->compass_is_suspended = FALSE;
+
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
+                       result = mpu_set_slave(mldl_cfg,
+                                              gyro_handle,
+                                              mldl_cfg->compass,
+                                              &mldl_cfg->pdata->compass);
+                       ERROR_CHECK(result);
+               }
+       }
+
+       if (resume_pressure && mldl_cfg->pressure_is_suspended) {
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
+                       result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+                       ERROR_CHECK(result);
+               }
+               result = mldl_cfg->pressure->resume(pressure_handle,
+                                                   mldl_cfg->pressure,
+                                                   &mldl_cfg->pdata->
+                                                   pressure);
+               ERROR_CHECK(result);
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
+                       result = mpu_set_slave(mldl_cfg,
+                                              gyro_handle,
+                                              mldl_cfg->pressure,
+                                              &mldl_cfg->pdata->pressure);
+                       ERROR_CHECK(result);
+               }
+               mldl_cfg->pressure_is_suspended = FALSE;
+       }
+
+       /* Now start */
+       if (resume_gyro) {
+               result = dmp_start(mldl_cfg, gyro_handle);
+               ERROR_CHECK(result);
+       }
+
+       return result;
+}
+
+
+/**
+ *  @brief  suspend the MPU3050 device and all the other sensor
+ *          devices into their low power state.
+ *  @param  gyro_handle
+ *              the main file handle to the MPU3050 device.
+ *  @param  accel_handle
+ *              an handle to the accelerometer device, if sitting
+ *              onto a separate bus. Can match gyro_handle if
+ *              the accelerometer device operates on the same
+ *              primary bus of MPU.
+ *  @param  compass_handle
+ *              an handle to the compass device, if sitting
+ *              onto a separate bus. Can match gyro_handle if
+ *              the compass device operates on the same
+ *              primary bus of MPU.
+ *  @param  pressure_handle
+ *              an handle to the pressure sensor device, if sitting
+ *              onto a separate bus. Can match gyro_handle if
+ *              the pressure sensor device operates on the same
+ *              primary bus of MPU.
+ *  @param  accel
+ *              whether suspending the accelerometer device is
+ *              actually needed (if the device supports low power
+ *              mode of some sort).
+ *  @param  compass
+ *              whether suspending the compass device is
+ *              actually needed (if the device supports low power
+ *              mode of some sort).
+ *  @param  pressure
+ *              whether suspending the pressure sensor device is
+ *              actually needed (if the device supports low power
+ *              mode of some sort).
+ *  @return  ML_SUCCESS or a non-zero error code.
+ */
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg,
+                   void *gyro_handle,
+                   void *accel_handle,
+                   void *compass_handle,
+                   void *pressure_handle,
+                   bool suspend_gyro,
+                   bool suspend_accel,
+                   bool suspend_compass,
+                   bool suspend_pressure)
+{
+       int result = ML_SUCCESS;
+
+       if (suspend_gyro && !mldl_cfg->gyro_is_suspended) {
+#ifdef M_HW
+               /* This puts the bus into bypass mode */
+               result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1);
+               ERROR_CHECK(result);
+               result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP);
+#else
+               result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle,
+                                         0, SLEEP, 0, 0, 0);
+#endif
+               ERROR_CHECK(result);
+       }
+
+       if (!mldl_cfg->accel_is_suspended && suspend_accel &&
+           mldl_cfg->accel && mldl_cfg->accel->suspend) {
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+                       result = mpu_set_slave(mldl_cfg, gyro_handle,
+                                              NULL, NULL);
+                       ERROR_CHECK(result);
+               }
+               result = mldl_cfg->accel->suspend(accel_handle,
+                                                 mldl_cfg->accel,
+                                                 &mldl_cfg->pdata->accel);
+               ERROR_CHECK(result);
+               mldl_cfg->accel_is_suspended = TRUE;
+       }
+
+       if (!mldl_cfg->compass_is_suspended && suspend_compass &&
+           mldl_cfg->compass && mldl_cfg->compass->suspend) {
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
+                       result = mpu_set_slave(mldl_cfg, gyro_handle,
+                                              NULL, NULL);
+                       ERROR_CHECK(result);
+               }
+               result = mldl_cfg->compass->suspend(compass_handle,
+                                                   mldl_cfg->compass,
+                                                   &mldl_cfg->
+                                                   pdata->compass);
+               ERROR_CHECK(result);
+               mldl_cfg->compass_is_suspended = TRUE;
+       }
+
+       if (!mldl_cfg->pressure_is_suspended && suspend_pressure &&
+           mldl_cfg->pressure && mldl_cfg->pressure->suspend) {
+               if (!mldl_cfg->gyro_is_suspended &&
+                   EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
+                       result = mpu_set_slave(mldl_cfg, gyro_handle,
+                                              NULL, NULL);
+                       ERROR_CHECK(result);
+               }
+               result = mldl_cfg->pressure->suspend(pressure_handle,
+                                                   mldl_cfg->pressure,
+                                                   &mldl_cfg->
+                                                   pdata->pressure);
+               ERROR_CHECK(result);
+               mldl_cfg->pressure_is_suspended = TRUE;
+       }
+       return result;
+}
+
+
+/**
+ *  @brief  read raw sensor data from the accelerometer device
+ *          in use.
+ *  @param  data
+ *              a buffer to store the raw sensor data.
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg,
+                      void *accel_handle, unsigned char *data)
+{
+       if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read)
+               return mldl_cfg->accel->read(accel_handle,
+                                            mldl_cfg->accel,
+                                            &mldl_cfg->pdata->accel,
+                                            data);
+       else
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+/**
+ *  @brief  read raw sensor data from the compass device
+ *          in use.
+ *  @param  data
+ *              a buffer to store the raw sensor data.
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg,
+                        void *compass_handle, unsigned char *data)
+{
+       if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read)
+               return mldl_cfg->compass->read(compass_handle,
+                                              mldl_cfg->compass,
+                                              &mldl_cfg->pdata->compass,
+                                              data);
+       else
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+/**
+ *  @brief  read raw sensor data from the pressure device
+ *          in use.
+ *  @param  data
+ *              a buffer to store the raw sensor data.
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg,
+                        void *pressure_handle, unsigned char *data)
+{
+       if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->read)
+               return mldl_cfg->pressure->read(pressure_handle,
+                                               mldl_cfg->pressure,
+                                               &mldl_cfg->pdata->pressure,
+                                               data);
+       else
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+int mpu3050_config_accel(struct mldl_cfg *mldl_cfg,
+                       void *accel_handle,
+                       struct ext_slave_config *data)
+{
+       if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->config)
+               return mldl_cfg->accel->config(accel_handle,
+                                              mldl_cfg->accel,
+                                              &mldl_cfg->pdata->accel,
+                                              data);
+       else
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+}
+
+int mpu3050_config_compass(struct mldl_cfg *mldl_cfg,
+                       void *compass_handle,
+                       struct ext_slave_config *data)
+{
+       if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->config)
+               return mldl_cfg->compass->config(compass_handle,
+                                                mldl_cfg->compass,
+                                                &mldl_cfg->pdata->compass,
+                                                data);
+       else
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+}
+
+int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg,
+                       void *pressure_handle,
+                       struct ext_slave_config *data)
+{
+       if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->config)
+               return mldl_cfg->pressure->config(pressure_handle,
+                                                 mldl_cfg->pressure,
+                                                 &mldl_cfg->pdata->pressure,
+                                                 data);
+       else
+               return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+
+/**
+ *@}
+ */
diff --git a/drivers/misc/mpu3050/mldl_cfg.h b/drivers/misc/mpu3050/mldl_cfg.h
new file mode 100644 (file)
index 0000000..91f349e
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @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 "mpu.h"
+
+/* --------------------- */
+/* -    Defines.       - */
+/* --------------------- */
+
+    /*************************************************************************/
+    /*  Sensors                                                              */
+    /*************************************************************************/
+
+#define ML_X_GYRO                      (0x0001)
+#define ML_Y_GYRO                      (0x0002)
+#define ML_Z_GYRO                      (0x0004)
+#define ML_DMP_PROCESSOR               (0x0008)
+
+#define ML_X_ACCEL                     (0x0010)
+#define ML_Y_ACCEL                     (0x0020)
+#define ML_Z_ACCEL                     (0x0040)
+
+#define ML_X_COMPASS                   (0x0080)
+#define ML_Y_COMPASS                   (0x0100)
+#define ML_Z_COMPASS                   (0x0200)
+
+#define ML_X_PRESSURE                  (0x0300)
+#define ML_Y_PRESSURE                  (0x0800)
+#define ML_Z_PRESSURE                  (0x1000)
+
+#define ML_TEMPERATURE                 (0x2000)
+#define ML_TIME                                (0x4000)
+
+#define ML_THREE_AXIS_GYRO             (0x000F)
+#define ML_THREE_AXIS_ACCEL            (0x0070)
+#define ML_THREE_AXIS_COMPASS          (0x0380)
+#define ML_THREE_AXIS_PRESSURE         (0x1C00)
+
+#define ML_FIVE_AXIS                   (0x007B)
+#define ML_SIX_AXIS_GYRO_ACCEL         (0x007F)
+#define ML_SIX_AXIS_ACCEL_COMPASS      (0x03F0)
+#define ML_NINE_AXIS                   (0x03FF)
+#define ML_ALL_SENSORS                 (0x7FFF)
+
+#define SAMPLING_RATE_HZ(mldl_cfg)                                     \
+       ((((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7))        \
+               ? (8000)                                                \
+               : (1000))                                               \
+               / ((mldl_cfg)->divider + 1))
+
+#define SAMPLING_PERIOD_US(mldl_cfg)                                   \
+       ((1000000L * ((mldl_cfg)->divider + 1)) /                       \
+       (((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7))         \
+               ? (8000)                                                \
+               : (1000)))
+/* --------------------- */
+/* -    Variables.     - */
+/* --------------------- */
+
+/* Platform data for the MPU */
+struct mldl_cfg {
+       /* MPU related configuration */
+       unsigned long requested_sensors;
+       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 gyro_power;
+       unsigned char offset_tc[MPU_NUM_AXES];
+       unsigned short offset[MPU_NUM_AXES];
+       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 gyro_is_bypassed;
+       int dmp_is_running;
+       int gyro_is_suspended;
+       int accel_is_suspended;
+       int compass_is_suspended;
+       int pressure_is_suspended;
+       int gyro_needs_reset;
+
+       /* Slave related information */
+       struct ext_slave_descr *accel;
+       struct ext_slave_descr *compass;
+       struct ext_slave_descr *pressure;
+
+       /* Platform Data */
+       struct mpu3050_platform_data *pdata;
+};
+
+
+int mpu3050_open(struct mldl_cfg *mldl_cfg,
+                void *mlsl_handle,
+                void *accel_handle,
+                void *compass_handle,
+                void *pressure_handle);
+int mpu3050_close(struct mldl_cfg *mldl_cfg,
+                 void *mlsl_handle,
+                 void *accel_handle,
+                 void *compass_handle,
+                 void *pressure_handle);
+int mpu3050_resume(struct mldl_cfg *mldl_cfg,
+                  void *gyro_handle,
+                  void *accel_handle,
+                  void *compass_handle,
+                  void *pressure_handle,
+                  bool resume_gyro,
+                  bool resume_accel,
+                  bool resume_compass,
+                  bool resume_pressure);
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg,
+                   void *gyro_handle,
+                   void *accel_handle,
+                   void *compass_handle,
+                   void *pressure_handle,
+                   bool suspend_gyro,
+                   bool suspend_accel,
+                   bool suspend_compass,
+                   bool suspend_pressure);
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg,
+                      void *accel_handle,
+                      unsigned char *data);
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg,
+                        void *compass_handle,
+                        unsigned char *data);
+int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
+                         unsigned char *data);
+
+int mpu3050_config_accel(struct mldl_cfg *mldl_cfg,
+                        void *accel_handle,
+                        struct ext_slave_config *data);
+int mpu3050_config_compass(struct mldl_cfg *mldl_cfg,
+                          void *compass_handle,
+                          struct ext_slave_config *data);
+int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg,
+                           void *pressure_handle,
+                           struct ext_slave_config *data);
+
+
+#endif                         /* __MLDL_CFG_H__ */
+
+/**
+ *@}
+ */
diff --git a/drivers/misc/mpu3050/mlos-kernel.c b/drivers/misc/mpu3050/mlos-kernel.c
new file mode 100644 (file)
index 0000000..091c0a6
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+/**
+ * @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 100644 (file)
index 0000000..e65dd62
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#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 100644 (file)
index 0000000..d1bcf88
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#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, void **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(void *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(void *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(void *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 write multiple bytes of data from registers.
+ *          This should be sent by I2C.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  registerAddr    Register address to write.
+ *  @param  length          Length of burst of data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return ML_SUCCESS if successful, a non-zero error code otherwise.
+ */
+tMLError MLSLSerialWrite(void *sl_handle,
+                        unsigned char slaveAddr,
+                        unsigned short length, unsigned char const *data)
+{
+       tMLError result;
+       const unsigned short dataLength = length - 1;
+       const unsigned char startRegAddr = data[0];
+       unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1];
+       unsigned short bytesWritten = 0;
+
+       while (bytesWritten < dataLength) {
+               unsigned short thisLen = min(SERIAL_MAX_TRANSFER_SIZE,
+                                            dataLength - bytesWritten);
+               if (bytesWritten == 0) {
+                       result = sensor_i2c_write((struct i2c_adapter *)
+                                                 sl_handle, slaveAddr,
+                                                 1 + thisLen, data);
+               } else {
+                       /* manually increment register addr between chunks */
+                       i2cWrite[0] = startRegAddr + bytesWritten;
+                       memcpy(&i2cWrite[1], &data[1 + bytesWritten],
+                              thisLen);
+                       result = sensor_i2c_write((struct i2c_adapter *)
+                                                 sl_handle, slaveAddr,
+                                                 1 + thisLen, i2cWrite);
+               }
+               if (ML_SUCCESS != result)
+                       return result;
+               bytesWritten += thisLen;
+       }
+       return ML_SUCCESS;
+}
+
+
+/**
+ *  @brief  used to read multiple bytes of data from registers.
+ *          This should be sent by I2C.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  registerAddr    Register address to read.
+ *  @param  length          Length of burst of data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if successful; an error code otherwise
+ */
+tMLError MLSLSerialRead(void *sl_handle,
+                       unsigned char slaveAddr,
+                       unsigned char registerAddr,
+                       unsigned short length, unsigned char *data)
+{
+       tMLError result;
+       unsigned short bytesRead = 0;
+
+       if (registerAddr == MPUREG_FIFO_R_W
+           || registerAddr == MPUREG_MEM_R_W) {
+               return ML_ERROR_INVALID_PARAMETER;
+       }
+       while (bytesRead < length) {
+               unsigned short thisLen =
+                   min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
+               result =
+                   sensor_i2c_read((struct i2c_adapter *) sl_handle,
+                                   slaveAddr, registerAddr + bytesRead,
+                                   thisLen, &data[bytesRead]);
+               if (ML_SUCCESS != result)
+                       return result;
+               bytesRead += thisLen;
+       }
+       return ML_SUCCESS;
+}
+
+
+/**
+ *  @brief  used to write multiple bytes of data to the memory.
+ *          This should be sent by I2C.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  memAddr         The location in the memory to write to.
+ *  @param  length          Length of burst data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if successful; an error code otherwise
+ */
+tMLError MLSLSerialWriteMem(void *sl_handle,
+                           unsigned char slaveAddr,
+                           unsigned short memAddr,
+                           unsigned short length,
+                           unsigned char const *data)
+{
+       tMLError result;
+       unsigned short bytesWritten = 0;
+
+       if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) {
+               printk
+                   ("memory read length (%d B) extends beyond its limits (%d) "
+                    "if started at location %d\n", length,
+                    MPU_MEM_BANK_SIZE, memAddr & 0xFF);
+               return ML_ERROR_INVALID_PARAMETER;
+       }
+       while (bytesWritten < length) {
+               unsigned short thisLen =
+                   min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten);
+               result =
+                   mpu_memory_write((struct i2c_adapter *) sl_handle,
+                                    slaveAddr, memAddr + bytesWritten,
+                                    thisLen, &data[bytesWritten]);
+               if (ML_SUCCESS != result)
+                       return result;
+               bytesWritten += thisLen;
+       }
+       return ML_SUCCESS;
+}
+
+
+/**
+ *  @brief  used to read multiple bytes of data from the memory.
+ *          This should be sent by I2C.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  memAddr         The location in the memory to read from.
+ *  @param  length          Length of burst data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if successful; an error code otherwise
+ */
+tMLError MLSLSerialReadMem(void *sl_handle,
+                          unsigned char slaveAddr,
+                          unsigned short memAddr,
+                          unsigned short length, unsigned char *data)
+{
+       tMLError result;
+       unsigned short bytesRead = 0;
+
+       if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) {
+               printk
+                   ("memory read length (%d B) extends beyond its limits (%d) "
+                    "if started at location %d\n", length,
+                    MPU_MEM_BANK_SIZE, memAddr & 0xFF);
+               return ML_ERROR_INVALID_PARAMETER;
+       }
+       while (bytesRead < length) {
+               unsigned short thisLen =
+                   min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
+               result =
+                   mpu_memory_read((struct i2c_adapter *) sl_handle,
+                                   slaveAddr, memAddr + bytesRead,
+                                   thisLen, &data[bytesRead]);
+               if (ML_SUCCESS != result)
+                       return result;
+               bytesRead += thisLen;
+       }
+       return ML_SUCCESS;
+}
+
+
+/**
+ *  @brief  used to write multiple bytes of data to the fifo.
+ *          This should be sent by I2C.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  length          Length of burst of data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if successful; an error code otherwise
+ */
+tMLError MLSLSerialWriteFifo(void *sl_handle,
+                            unsigned char slaveAddr,
+                            unsigned short length,
+                            unsigned char const *data)
+{
+       tMLError result;
+       unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1];
+       unsigned short bytesWritten = 0;
+
+       if (length > FIFO_HW_SIZE) {
+               printk(KERN_ERR
+                      "maximum fifo write length is %d\n", FIFO_HW_SIZE);
+               return ML_ERROR_INVALID_PARAMETER;
+       }
+       while (bytesWritten < length) {
+               unsigned short thisLen =
+                   min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten);
+               i2cWrite[0] = MPUREG_FIFO_R_W;
+               memcpy(&i2cWrite[1], &data[bytesWritten], thisLen);
+               result = sensor_i2c_write((struct i2c_adapter *) sl_handle,
+                                         slaveAddr, thisLen + 1,
+                                         i2cWrite);
+               if (ML_SUCCESS != result)
+                       return result;
+               bytesWritten += thisLen;
+       }
+       return ML_SUCCESS;
+}
+
+
+/**
+ *  @brief  used to read multiple bytes of data from the fifo.
+ *          This should be sent by I2C.
+ *
+ *  @param  slaveAddr       I2C slave address of device.
+ *  @param  length          Length of burst of data.
+ *  @param  data            Pointer to block of data.
+ *
+ *  @return Zero if successful; an error code otherwise
+ */
+tMLError MLSLSerialReadFifo(void *sl_handle,
+                           unsigned char slaveAddr,
+                           unsigned short length, unsigned char *data)
+{
+       tMLError result;
+       unsigned short bytesRead = 0;
+
+       if (length > FIFO_HW_SIZE) {
+               printk(KERN_ERR
+                      "maximum fifo read length is %d\n", FIFO_HW_SIZE);
+               return ML_ERROR_INVALID_PARAMETER;
+       }
+       while (bytesRead < length) {
+               unsigned short thisLen =
+                   min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
+               result =
+                   sensor_i2c_read((struct i2c_adapter *) sl_handle,
+                                   slaveAddr, MPUREG_FIFO_R_W, thisLen,
+                                   &data[bytesRead]);
+               if (ML_SUCCESS != result)
+                       return result;
+               bytesRead += thisLen;
+       }
+
+       return ML_SUCCESS;
+}
+
+/**
+ *  @}
+ */
diff --git a/drivers/misc/mpu3050/mlsl.h b/drivers/misc/mpu3050/mlsl.h
new file mode 100644 (file)
index 0000000..4f01293
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#ifndef __MSSL_H__
+#define __MSSL_H__
+
+#include "mltypes.h"
+#include "mpu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------ */
+/* - Defines. - */
+/* ------------ */
+
+/*
+ * NOTE : to properly support Yamaha compass reads,
+ * the max transfer size should be at least 9 B.
+ * Length in bytes, typically a power of 2 >= 2
+ */
+#define SERIAL_MAX_TRANSFER_SIZE 128
+
+/* ---------------------- */
+/* - Types definitions. - */
+/* ---------------------- */
+
+/* --------------------- */
+/* - Function p-types. - */
+/* --------------------- */
+
+       tMLError MLSLSerialOpen(char const *port,
+                               void **sl_handle);
+       tMLError MLSLSerialReset(void *sl_handle);
+       tMLError MLSLSerialClose(void *sl_handle);
+
+       tMLError MLSLSerialWriteSingle(void *sl_handle,
+                                      unsigned char slaveAddr,
+                                      unsigned char registerAddr,
+                                      unsigned char data);
+
+       tMLError MLSLSerialRead(void *sl_handle,
+                               unsigned char slaveAddr,
+                               unsigned char registerAddr,
+                               unsigned short length,
+                               unsigned char *data);
+
+       tMLError MLSLSerialWrite(void *sl_handle,
+                                unsigned char slaveAddr,
+                                unsigned short length,
+                                unsigned char const *data);
+
+       tMLError MLSLSerialReadMem(void *sl_handle,
+                                  unsigned char slaveAddr,
+                                  unsigned short memAddr,
+                                  unsigned short length,
+                                  unsigned char *data);
+
+       tMLError MLSLSerialWriteMem(void *sl_handle,
+                                   unsigned char slaveAddr,
+                                   unsigned short memAddr,
+                                   unsigned short length,
+                                   unsigned char const *data);
+
+       tMLError MLSLSerialReadFifo(void *sl_handle,
+                                   unsigned char slaveAddr,
+                                   unsigned short length,
+                                   unsigned char *data);
+
+       tMLError MLSLSerialWriteFifo(void *sl_handle,
+                                    unsigned char slaveAddr,
+                                    unsigned short length,
+                                    unsigned char const *data);
+
+       tMLError MLSLWriteCal(unsigned char *cal, unsigned int len);
+       tMLError MLSLReadCal(unsigned char *cal, unsigned int len);
+       tMLError MLSLGetCalLength(unsigned int *len);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+#endif                         /* MLSL_H */
diff --git a/drivers/misc/mpu3050/mltypes.h b/drivers/misc/mpu3050/mltypes.h
new file mode 100644 (file)
index 0000000..3521c00
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+/******************************************************************************
+ *
+ * $Id: mltypes.h 4598 2011-01-25 19:33:13Z prao $
+ *
+ *****************************************************************************/
+
+/**
+ *  @defgroup MLERROR
+ *  @brief  Motion Library - Error definitions.
+ *          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
+ *          - (73)      ML_ERROR_COMPASS_DATA_ERROR
+ *          - (75)      ML_ERROR_CALIBRATION_LOAD
+ *          - (76)      ML_ERROR_CALIBRATION_STORE
+ *          - (77)      ML_ERROR_CALIBRATION_LEN
+ *          - (78)      ML_ERROR_CALIBRATION_CHECKSUM
+ *
+ *  @{
+ *      @file mltypes.h
+ *  @}
+ */
+
+#ifndef MLTYPES_H
+#define MLTYPES_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include "stdint_invensense.h"
+#endif
+#include "log.h"
+
+/*---------------------------
+    ML Types
+---------------------------*/
+
+/**
+ * @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.  Proprietary 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)
+#define ML_ERROR_INVALID_CONFIGURATION  (17)
+
+/* 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)
+#define ML_ERROR_COMPASS_DATA_ERROR     (73)
+
+/* Load/Store calibration */
+#define ML_ERROR_CALIBRATION_LOAD       (75)
+#define ML_ERROR_CALIBRATION_STORE      (76)
+#define ML_ERROR_CALIBRATION_LEN        (77)
+#define ML_ERROR_CALIBRATION_CHECKSUM   (78)
+
+/* For Linux coding compliance */
+#ifndef __KERNEL__
+#define EXPORT_SYMBOL(x)
+#endif
+
+/*---------------------------
+    p-Types
+---------------------------*/
+
+#endif                         /* MLTYPES_H */
diff --git a/drivers/misc/mpu3050/mpu-dev.c b/drivers/misc/mpu3050/mpu-dev.c
new file mode 100644 (file)
index 0000000..4b1f99e
--- /dev/null
@@ -0,0 +1,1219 @@
+/*
+    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 <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "mpuirq.h"
+#include "slaveirq.h"
+#include "mlsl.h"
+#include "mpu-i2c.h"
+#include "mldl_cfg.h"
+#include "mpu.h"
+
+#define MPU3050_EARLY_SUSPEND_IN_DRIVER 0
+
+/* 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)
+{
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *) i2c_get_clientdata(this_client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+
+       dev_dbg(&this_client->adapter->dev, "mpu_open\n");
+       dev_dbg(&this_client->adapter->dev, "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 */
+
+       /* Reset the sensors to the default */
+       mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO;
+       if (mldl_cfg->accel && mldl_cfg->accel->resume)
+               mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL;
+
+       if (mldl_cfg->compass && mldl_cfg->compass->resume)
+               mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS;
+
+       if (mldl_cfg->pressure && mldl_cfg->pressure->resume)
+               mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE;
+
+       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;
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+       struct i2c_adapter *pressure_adapter;
+       int result = 0;
+
+       pid = 0;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+       result = mpu3050_suspend(mldl_cfg, client->adapter,
+                                accel_adapter, compass_adapter,
+                                pressure_adapter,
+                                TRUE, TRUE, TRUE, TRUE);
+
+       dev_dbg(&this_client->adapter->dev, "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_set_mpu_pdata(struct i2c_client *client, unsigned long arg)
+{
+       int ii;
+       struct mpu_private_data *mpu =
+           (struct mpu_private_data *) i2c_get_clientdata(client);
+       struct mpu3050_platform_data *pdata = mpu->mldl_cfg.pdata;
+       struct mpu3050_platform_data local_pdata;
+
+       if (copy_from_user(&local_pdata, (unsigned char __user *) arg,
+                               sizeof(local_pdata)))
+               return -EFAULT;
+
+       pdata->int_config = local_pdata.int_config;
+       for (ii = 0; ii < DIM(pdata->orientation); ii++)
+               pdata->orientation[ii] = local_pdata.orientation[ii];
+       pdata->level_shifter = local_pdata.level_shifter;
+
+       pdata->accel.address = local_pdata.accel.address;
+       for (ii = 0; ii < DIM(pdata->accel.orientation); ii++)
+               pdata->accel.orientation[ii] =
+                       local_pdata.accel.orientation[ii];
+
+       pdata->compass.address = local_pdata.compass.address;
+       for (ii = 0; ii < DIM(pdata->compass.orientation); ii++)
+               pdata->compass.orientation[ii] =
+                       local_pdata.compass.orientation[ii];
+
+       pdata->pressure.address = local_pdata.pressure.address;
+       for (ii = 0; ii < DIM(pdata->pressure.orientation); ii++)
+               pdata->pressure.orientation[ii] =
+                       local_pdata.pressure.orientation[ii];
+
+       dev_dbg(&client->adapter->dev, "%s\n", __func__);
+
+       return ML_SUCCESS;
+}
+
+static int
+mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg)
+{
+       int ii;
+       int result = ML_SUCCESS;
+       struct mpu_private_data *mpu =
+               (struct mpu_private_data *) i2c_get_clientdata(client);
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct mldl_cfg *temp_mldl_cfg;
+
+       dev_dbg(&this_client->adapter->dev, "%s\n", __func__);
+
+       temp_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
+       if (NULL == temp_mldl_cfg)
+               return -ENOMEM;
+
+       /*
+        * User space is not allowed to modify accel compass pressure or
+        * pdata structs, as well as silicon_revision product_id or trim
+        */
+       if (copy_from_user(temp_mldl_cfg, (struct mldl_cfg __user *) arg,
+                               offsetof(struct mldl_cfg, silicon_revision))) {
+               result = -EFAULT;
+               goto out;
+       }
+
+       if (mldl_cfg->gyro_is_suspended) {
+               if (mldl_cfg->addr != temp_mldl_cfg->addr)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->int_config != temp_mldl_cfg->int_config)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->ext_sync != temp_mldl_cfg->ext_sync)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->full_scale != temp_mldl_cfg->full_scale)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->lpf != temp_mldl_cfg->lpf)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->clk_src != temp_mldl_cfg->clk_src)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->divider != temp_mldl_cfg->divider)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->dmp_enable != temp_mldl_cfg->dmp_enable)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->fifo_enable != temp_mldl_cfg->fifo_enable)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->dmp_cfg1 != temp_mldl_cfg->dmp_cfg1)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->dmp_cfg2 != temp_mldl_cfg->dmp_cfg2)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (mldl_cfg->gyro_power != temp_mldl_cfg->gyro_power)
+                       mldl_cfg->gyro_needs_reset = TRUE;
+
+               for (ii = 0; ii < MPU_NUM_AXES; ii++)
+                       if (mldl_cfg->offset_tc[ii] !=
+                           temp_mldl_cfg->offset_tc[ii])
+                               mldl_cfg->gyro_needs_reset = TRUE;
+
+               for (ii = 0; ii < MPU_NUM_AXES; ii++)
+                       if (mldl_cfg->offset[ii] != temp_mldl_cfg->offset[ii])
+                               mldl_cfg->gyro_needs_reset = TRUE;
+
+               if (memcmp(mldl_cfg->ram, temp_mldl_cfg->ram,
+                               MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE *
+                               sizeof(unsigned char)))
+                       mldl_cfg->gyro_needs_reset = TRUE;
+       }
+
+       memcpy(mldl_cfg, temp_mldl_cfg,
+               offsetof(struct mldl_cfg, silicon_revision));
+
+out:
+       kfree(temp_mldl_cfg);
+       return result;
+}
+
+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 = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
+       if (NULL == local_mldl_cfg)
+               return -ENOMEM;
+
+       retval =
+           copy_from_user(local_mldl_cfg, (struct mldl_cfg __user *) arg,
+                          sizeof(struct mldl_cfg));
+       if (retval)
+               goto out;
+
+       /* Fill in the accel, compass, pressure and pdata pointers */
+       if (mldl_cfg->accel) {
+               retval = copy_to_user((void __user *)local_mldl_cfg->accel,
+                                     mldl_cfg->accel,
+                                     sizeof(*mldl_cfg->accel));
+               if (retval)
+                       goto out;
+       }
+
+       if (mldl_cfg->compass) {
+               retval = copy_to_user((void __user *)local_mldl_cfg->compass,
+                                     mldl_cfg->compass,
+                                     sizeof(*mldl_cfg->compass));
+               if (retval)
+                       goto out;
+       }
+
+       if (mldl_cfg->pressure) {
+               retval = copy_to_user(local_mldl_cfg->pressure,
+                                     mldl_cfg->pressure,
+                                     sizeof(*mldl_cfg->pressure));
+               if (retval)
+                       goto out;
+       }
+
+       if (mldl_cfg->pdata) {
+               retval = copy_to_user((void __user *)local_mldl_cfg->pdata,
+                                     mldl_cfg->pdata,
+                                     sizeof(*mldl_cfg->pdata));
+               if (retval)
+                       goto out;
+       }
+
+       /* Do not modify the accel, compass, pressure and pdata pointers */
+       retval = copy_to_user((struct mldl_cfg __user *) 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;
+       struct i2c_adapter *pressure_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       switch (cmd) {
+       case I2C_RDWR:
+               mpudev_ioctl_rdrw(client, arg);
+               break;
+       case I2C_SLAVE:
+               if ((arg & 0x7E) != (client->addr & 0x7E)) {
+                       dev_err(&this_client->adapter->dev,
+                               "%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 __user *) arg,
+                                       sizeof(mldl_cfg->offset_tc));
+               break;
+       case MPU_SET_RAM:
+               retval = copy_from_user(mldl_cfg->ram,
+                                       (unsigned char __user *) arg,
+                                       sizeof(mldl_cfg->ram));
+               break;
+       case MPU_SET_PLATFORM_DATA:
+               retval = mpu_ioctl_set_mpu_pdata(client, arg);
+               break;
+       case MPU_GET_MPU_CONFIG:
+               retval = mpu_ioctl_get_mpu_config(client, arg);
+               break;
+       case MPU_GET_INT_CONFIG:
+               retval = put_user(mldl_cfg->int_config,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_EXT_SYNC:
+               retval = put_user(mldl_cfg->ext_sync,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_FULL_SCALE:
+               retval = put_user(mldl_cfg->full_scale,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_LPF:
+               retval = put_user(mldl_cfg->lpf,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_CLK_SRC:
+               retval = put_user(mldl_cfg->clk_src,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_DIVIDER:
+               retval = put_user(mldl_cfg->divider,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_LEVEL_SHIFTER:
+               retval = put_user(mldl_cfg->pdata->level_shifter,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_DMP_ENABLE:
+               retval = put_user(mldl_cfg->dmp_enable,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_FIFO_ENABLE:
+               retval = put_user(mldl_cfg->fifo_enable,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_DMP_CFG1:
+               retval = put_user(mldl_cfg->dmp_cfg1,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_DMP_CFG2:
+               retval = put_user(mldl_cfg->dmp_cfg2,
+                                 (unsigned char __user *) arg);
+               break;
+       case MPU_GET_OFFSET_TC:
+               retval = copy_to_user((unsigned char __user *) arg,
+                                     mldl_cfg->offset_tc,
+                                     sizeof(mldl_cfg->offset_tc));
+               break;
+       case MPU_GET_RAM:
+               retval = copy_to_user((unsigned char __user *) arg,
+                                     mldl_cfg->ram,
+                                     sizeof(mldl_cfg->ram));
+               break;
+       case MPU_CONFIG_ACCEL:
+       {
+               if ((mldl_cfg->accel) && (mldl_cfg->accel->config)) {
+                       struct ext_slave_config config;
+                       retval = copy_from_user(
+                               &config,
+                               (struct ext_slave_config *)arg,
+                               sizeof(config));
+                       if (retval)
+                               break;
+
+                       if (config.len && config.data) {
+                               int *data;
+                               data = kzalloc(config.len, GFP_KERNEL);
+                               if (!data) {
+                                       retval = ML_ERROR_MEMORY_EXAUSTED;
+                                       break;
+                               }
+                               retval = copy_from_user(data,
+                                                       (void *)config.data,
+                                                       config.len);
+                               if (retval) {
+                                       kfree(data);
+                                       break;
+                               }
+                               config.data = data;
+                       }
+                       retval = mldl_cfg->accel->config(
+                               accel_adapter,
+                               mldl_cfg->accel,
+                               &mldl_cfg->pdata->accel,
+                               &config);
+                       kfree(config.data);
+               }
+               break;
+       }
+       case MPU_CONFIG_COMPASS:
+       {
+               if ((mldl_cfg->compass) && (mldl_cfg->compass->config)) {
+                       struct ext_slave_config config;
+                       retval = copy_from_user(
+                               &config,
+                               (struct ext_slave_config *)arg,
+                               sizeof(config));
+                       if (retval)
+                               break;
+
+                       if (config.len && config.data) {
+                               int *data;
+                               data = kzalloc(config.len, GFP_KERNEL);
+                               if (!data) {
+                                       retval = ML_ERROR_MEMORY_EXAUSTED;
+                                       break;
+                               }
+                               retval = copy_from_user(data,
+                                                       (void *)config.data,
+                                                       config.len);
+                               if (retval) {
+                                       kfree(data);
+                                       break;
+                               }
+                               config.data = data;
+                       }
+                       retval = mldl_cfg->compass->config(
+                               compass_adapter,
+                               mldl_cfg->compass,
+                               &mldl_cfg->pdata->compass,
+                               &config);
+                       kfree(config.data);
+               }
+               break;
+       }
+       case MPU_CONFIG_PRESSURE:
+       {
+               if ((mldl_cfg->pressure) && (mldl_cfg->pressure->config)) {
+                       struct ext_slave_config config;
+                       retval = copy_from_user(
+                               &config,
+                               (struct ext_slave_config *)arg,
+                               sizeof(config));
+                       if (retval)
+                               break;
+
+                       if (config.len && config.data) {
+                               int *data;
+                               data = kzalloc(config.len, GFP_KERNEL);
+                               if (!data) {
+                                       retval = ML_ERROR_MEMORY_EXAUSTED;
+                                       break;
+                               }
+                               retval = copy_from_user(data,
+                                                       (void *)config.data,
+                                                       config.len);
+                               if (retval) {
+                                       kfree(data);
+                                       break;
+                               }
+                               config.data = data;
+                       }
+                       retval = mldl_cfg->pressure->config(
+                               pressure_adapter,
+                               mldl_cfg->pressure,
+                               &mldl_cfg->pdata->pressure,
+                               &config);
+                       kfree(config.data);
+               }
+               break;
+       }
+       case MPU_READ_MEMORY:
+       case MPU_WRITE_MEMORY:
+       case MPU_SUSPEND:
+       {
+               unsigned long sensors;
+               sensors = ~(mldl_cfg->requested_sensors);
+               retval = mpu3050_suspend(mldl_cfg,
+                                       client->adapter,
+                                       accel_adapter,
+                                       compass_adapter,
+                                       pressure_adapter,
+                                       ((sensors & ML_THREE_AXIS_GYRO)
+                                               == ML_THREE_AXIS_GYRO),
+                                       ((sensors & ML_THREE_AXIS_ACCEL)
+                                               == ML_THREE_AXIS_ACCEL),
+                                       ((sensors & ML_THREE_AXIS_COMPASS)
+                                               == ML_THREE_AXIS_COMPASS),
+                                       ((sensors & ML_THREE_AXIS_PRESSURE)
+                                               == ML_THREE_AXIS_PRESSURE));
+       }
+       break;
+       case MPU_RESUME:
+       {
+               unsigned long sensors;
+               sensors = mldl_cfg->requested_sensors;
+               retval = mpu3050_resume(mldl_cfg,
+                                       client->adapter,
+                                       accel_adapter,
+                                       compass_adapter,
+                                       pressure_adapter,
+                                       sensors & ML_THREE_AXIS_GYRO,
+                                       sensors & ML_THREE_AXIS_ACCEL,
+                                       sensors & ML_THREE_AXIS_COMPASS,
+                                       sensors & ML_THREE_AXIS_PRESSURE);
+       }
+       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 __user *) 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;
+       case MPU_READ_PRESSURE:
+               {
+                       unsigned char data[3];
+                       struct i2c_adapter *pressure_adapt =
+                           i2c_get_adapter(mldl_cfg->pdata->pressure.
+                                           adapt_num);
+                       retval =
+                           mpu3050_read_pressure(mldl_cfg, pressure_adapt,
+                                                data);
+                       if (ML_SUCCESS == retval)
+                               retval =
+                                   copy_to_user((unsigned char __user *) arg,
+                                                data, sizeof(data));
+               }
+               break;
+       default:
+               dev_err(&this_client->adapter->dev,
+                       "%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;
+       struct i2c_adapter *pressure_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       dev_dbg(&this_client->adapter->dev, "%s: %d, %d\n", __func__,
+               h->level, mpu->mldl_cfg.gyro_is_suspended);
+       if (MPU3050_EARLY_SUSPEND_IN_DRIVER)
+               (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
+                               accel_adapter, compass_adapter,
+                               pressure_adapter, TRUE, TRUE, 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;
+       struct i2c_adapter *pressure_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       if (MPU3050_EARLY_SUSPEND_IN_DRIVER) {
+               if (pid) {
+                       unsigned long sensors = mldl_cfg->requested_sensors;
+                       (void) mpu3050_resume(mldl_cfg,
+                                       this_client->adapter,
+                                       accel_adapter,
+                                       compass_adapter,
+                                       pressure_adapter,
+                                       sensors & ML_THREE_AXIS_GYRO,
+                                       sensors & ML_THREE_AXIS_ACCEL,
+                                       sensors & ML_THREE_AXIS_COMPASS,
+                                       sensors & ML_THREE_AXIS_PRESSURE);
+                       dev_dbg(&this_client->adapter->dev,
+                               "%s for pid %d\n", __func__, pid);
+               }
+       }
+       dev_dbg(&this_client->adapter->dev, "%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;
+       struct i2c_adapter *pressure_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
+                              accel_adapter, compass_adapter, pressure_adapter,
+                              TRUE, TRUE, TRUE, TRUE);
+       dev_dbg(&this_client->adapter->dev, "%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;
+       struct i2c_adapter *pressure_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       if (!mpu->mldl_cfg.gyro_is_suspended) {
+               dev_dbg(&this_client->adapter->dev,
+                       "%s: suspending on event %d\n", __func__,
+                       mesg.event);
+               (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
+                                      accel_adapter, compass_adapter,
+                                      pressure_adapter,
+                                      TRUE, TRUE, TRUE, TRUE);
+       } else {
+               dev_dbg(&this_client->adapter->dev,
+                       "%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;
+       struct i2c_adapter *pressure_adapter;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       if (pid) {
+               unsigned long sensors = mldl_cfg->requested_sensors;
+               (void) mpu3050_resume(mldl_cfg, this_client->adapter,
+                                     accel_adapter,
+                                     compass_adapter,
+                                     pressure_adapter,
+                                     sensors & ML_THREE_AXIS_GYRO,
+                                     sensors & ML_THREE_AXIS_ACCEL,
+                                     sensors & ML_THREE_AXIS_COMPASS,
+                                     sensors & ML_THREE_AXIS_PRESSURE);
+               dev_dbg(&this_client->adapter->dev,
+                       "%s for pid %d\n", __func__, pid);
+       }
+       return 0;
+}
+
+/* define which file operations are supported */
+static const 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", /* Same for both 3050 and 6000 */
+       .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;
+       struct mldl_cfg *mldl_cfg;
+       int res = 0;
+       struct i2c_adapter *accel_adapter = NULL;
+       struct i2c_adapter *compass_adapter = NULL;
+       struct i2c_adapter *pressure_adapter = NULL;
+
+       dev_dbg(&client->adapter->dev, "%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;
+       mldl_cfg = &mpu->mldl_cfg;
+       pdata = (struct mpu3050_platform_data *) client->dev.platform_data;
+       if (!pdata) {
+               dev_warn(&this_client->adapter->dev,
+                        "Warning no platform data for mpu3050\n");
+       } else {
+               mldl_cfg->pdata = pdata;
+
+#if defined(CONFIG_SENSORS_MPU3050_MODULE) || \
+    defined(CONFIG_SENSORS_MPU6000_MODULE)
+               pdata->accel.get_slave_descr = get_accel_slave_descr;
+               pdata->compass.get_slave_descr = get_compass_slave_descr;
+               pdata->pressure.get_slave_descr = get_pressure_slave_descr;
+#endif
+
+               if (pdata->accel.get_slave_descr) {
+                       mldl_cfg->accel =
+                           pdata->accel.get_slave_descr();
+                       dev_info(&this_client->adapter->dev,
+                                "%s: +%s\n", MPU_NAME,
+                                mldl_cfg->accel->name);
+                       accel_adapter =
+                               i2c_get_adapter(pdata->accel.adapt_num);
+                       if (pdata->accel.irq > 0) {
+                               dev_info(&this_client->adapter->dev,
+                                       "Installing Accel irq using %d\n",
+                                       pdata->accel.irq);
+                               res = slaveirq_init(accel_adapter,
+                                               &pdata->accel,
+                                               "accelirq");
+                               if (res)
+                                       goto out_accelirq_failed;
+                       } else {
+                               dev_warn(&this_client->adapter->dev,
+                                       "WARNING: Accel irq not assigned\n");
+                       }
+               } else {
+                       dev_warn(&this_client->adapter->dev,
+                                "%s: No Accel Present\n", MPU_NAME);
+               }
+
+               if (pdata->compass.get_slave_descr) {
+                       mldl_cfg->compass =
+                           pdata->compass.get_slave_descr();
+                       dev_info(&this_client->adapter->dev,
+                                "%s: +%s\n", MPU_NAME,
+                                mldl_cfg->compass->name);
+                       compass_adapter =
+                               i2c_get_adapter(pdata->compass.adapt_num);
+                       if (pdata->compass.irq > 0) {
+                               dev_info(&this_client->adapter->dev,
+                                       "Installing Compass irq using %d\n",
+                                       pdata->compass.irq);
+                               res = slaveirq_init(compass_adapter,
+                                               &pdata->compass,
+                                               "compassirq");
+                               if (res)
+                                       goto out_compassirq_failed;
+                       } else {
+                               dev_warn(&this_client->adapter->dev,
+                                       "WARNING: Compass irq not assigned\n");
+                       }
+               } else {
+                       dev_warn(&this_client->adapter->dev,
+                                "%s: No Compass Present\n", MPU_NAME);
+               }
+
+               if (pdata->pressure.get_slave_descr) {
+                       mldl_cfg->pressure =
+                           pdata->pressure.get_slave_descr();
+                       dev_info(&this_client->adapter->dev,
+                                "%s: +%s\n", MPU_NAME,
+                                mldl_cfg->pressure->name);
+                       pressure_adapter =
+                               i2c_get_adapter(pdata->pressure.adapt_num);
+
+                       if (pdata->pressure.irq > 0) {
+                               dev_info(&this_client->adapter->dev,
+                                       "Installing Pressure irq using %d\n",
+                                       pdata->pressure.irq);
+                               res = slaveirq_init(pressure_adapter,
+                                               &pdata->pressure,
+                                               "pressureirq");
+                               if (res)
+                                       goto out_pressureirq_failed;
+                       } else {
+                               dev_warn(&this_client->adapter->dev,
+                                       "WARNING: Pressure irq not assigned\n");
+                       }
+               } else {
+                       dev_warn(&this_client->adapter->dev,
+                                "%s: No Pressure Present\n", MPU_NAME);
+               }
+       }
+
+       mldl_cfg->addr = client->addr;
+       res = mpu3050_open(&mpu->mldl_cfg, client->adapter,
+                       accel_adapter, compass_adapter, pressure_adapter);
+
+       if (res) {
+               dev_err(&this_client->adapter->dev,
+                       "Unable to open %s %d\n", MPU_NAME, res);
+               res = -ENODEV;
+               goto out_whoami_failed;
+       }
+
+       res = misc_register(&i2c_mpu_device);
+       if (res < 0) {
+               dev_err(&this_client->adapter->dev,
+                       "ERROR: misc_register returned %d\n", res);
+               goto out_misc_register_failed;
+       }
+
+       if (this_client->irq > 0) {
+               dev_info(&this_client->adapter->dev,
+                        "Installing irq using %d\n", this_client->irq);
+               res = mpuirq_init(this_client);
+               if (res)
+                       goto out_mpuirq_failed;
+       } else {
+               dev_warn(&this_client->adapter->dev,
+                        "WARNING: %s irq not assigned\n", MPU_NAME);
+       }
+
+
+#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
+       return res;
+
+out_mpuirq_failed:
+       misc_deregister(&i2c_mpu_device);
+out_misc_register_failed:
+       mpu3050_close(&mpu->mldl_cfg, client->adapter,
+               accel_adapter, compass_adapter, pressure_adapter);
+out_whoami_failed:
+       if (pdata &&
+           pdata->pressure.get_slave_descr &&
+           pdata->pressure.irq)
+               slaveirq_exit(&pdata->pressure);
+out_pressureirq_failed:
+       if (pdata &&
+           pdata->compass.get_slave_descr &&
+           pdata->compass.irq)
+               slaveirq_exit(&pdata->compass);
+out_compassirq_failed:
+       if (pdata &&
+           pdata->accel.get_slave_descr &&
+           pdata->accel.irq)
+               slaveirq_exit(&pdata->accel);
+out_accelirq_failed:
+       kfree(mpu);
+out_alloc_data_failed:
+out_check_functionality_failed:
+       dev_err(&this_client->adapter->dev, "%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);
+       struct i2c_adapter *accel_adapter;
+       struct i2c_adapter *compass_adapter;
+       struct i2c_adapter *pressure_adapter;
+       struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+       struct mpu3050_platform_data *pdata = mldl_cfg->pdata;
+
+       accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+       compass_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+       pressure_adapter =
+           i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+       dev_dbg(&client->adapter->dev, "%s\n", __func__);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+       unregister_early_suspend(&mpu->early_suspend);
+#endif
+       mpu3050_close(mldl_cfg, client->adapter,
+               accel_adapter, compass_adapter, pressure_adapter);
+
+       if (client->irq)
+               mpuirq_exit();
+
+       if (pdata &&
+           pdata->pressure.get_slave_descr &&
+           pdata->pressure.irq)
+               slaveirq_exit(&pdata->pressure);
+
+       if (pdata &&
+           pdata->compass.get_slave_descr &&
+           pdata->compass.irq)
+               slaveirq_exit(&pdata->compass);
+
+       if (pdata &&
+           pdata->accel.get_slave_descr &&
+           pdata->accel.irq)
+               slaveirq_exit(&pdata->accel);
+
+       misc_deregister(&i2c_mpu_device);
+       kfree(mpu);
+
+       return 0;
+}
+
+static const struct i2c_device_id mpu3050_id[] = {
+       {MPU_NAME, 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 = MPU_NAME,
+                  },
+#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);
+       pid = 0;
+       printk(KERN_DEBUG "%s\n", __func__);
+       if (res)
+               dev_err(&this_client->adapter->dev, "%s failed\n",
+                       __func__);
+       return res;
+}
+
+static void __exit mpu_exit(void)
+{
+       printk(KERN_DEBUG "%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(MPU_NAME);
diff --git a/drivers/misc/mpu3050/mpu-i2c.c b/drivers/misc/mpu3050/mpu-i2c.c
new file mode 100644 (file)
index 0000000..1f0c346
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ *  @defgroup
+ *  @brief
+ *
+ *  @{
+ *      @file   mpu-i2c.c
+ *      @brief
+ *
+ */
+
+#include <linux/i2c.h>
+#include "mpu.h"
+
+int sensor_i2c_write(struct i2c_adapter *i2c_adap,
+                    unsigned char address,
+                    unsigned int len, unsigned char const *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] = MPUREG_BANK_SEL;
+       bank[1] = mem_addr >> 8;
+
+       addr[0] = MPUREG_MEM_START_ADDR;
+       addr[1] = mem_addr & 0xFF;
+
+       buf = 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 const *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] = MPUREG_BANK_SEL;
+       bank[1] = mem_addr >> 8;
+
+       addr[0] = MPUREG_MEM_START_ADDR;
+       addr[1] = mem_addr & 0xFF;
+
+       buf[0] = 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 100644 (file)
index 0000000..7d58027
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+/**
+ * @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 100644 (file)
index 0000000..1b88cdd
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+#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 <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "mpu.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 irq_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));
+               mpuirq_data.data_type = 0;
+       } 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;
+
+       poll_wait(file, &mpuirq_wait, poll);
+       if (mpuirq_dev_data.data_ready)
+               mask |= POLLIN | POLLRDNORM;
+       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(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 */
+const 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 100644 (file)
index 0000000..374cd33
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#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)
+
+#ifdef __KERNEL__
+
+void mpuirq_exit(void);
+int mpuirq_init(struct i2c_client *mpu_client);
+
+#endif
+
+#endif
diff --git a/drivers/misc/mpu3050/slaveirq.c b/drivers/misc/mpu3050/slaveirq.c
new file mode 100644 (file)
index 0000000..ab5c80a
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+#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/poll.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "mpu.h"
+#include "slaveirq.h"
+#include "mldl_cfg.h"
+#include "mpu-i2c.h"
+#include <linux/wait.h>
+
+/* function which gets slave data and sends it to SLAVE */
+
+struct slaveirq_dev_data {
+       struct miscdevice dev;
+       struct i2c_client *slave_client;
+       struct irq_data data;
+       wait_queue_head_t slaveirq_wait;
+       int irq;
+       int pid;
+       int data_ready;
+       int timeout;
+};
+
+/* The following depends on patch fa1f68db6ca7ebb6fc4487ac215bffba06c01c28
+ * drivers: misc: pass miscdevice pointer via file private data
+ */
+static int slaveirq_open(struct inode *inode, struct file *file)
+{
+       /* Device node is availabe in the file->private_data, this is
+        * exactly what we want so we leave it there */
+       struct slaveirq_dev_data *data =
+               container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+       dev_dbg(data->dev.this_device,
+               "%s current->pid %d\n", __func__, current->pid);
+       data->pid = current->pid;
+       return 0;
+}
+
+static int slaveirq_release(struct inode *inode, struct file *file)
+{
+       struct slaveirq_dev_data *data =
+               container_of(file->private_data, struct slaveirq_dev_data, dev);
+       dev_dbg(data->dev.this_device, "slaveirq_release\n");
+       return 0;
+}
+
+/* read function called when from /dev/slaveirq is read */
+static ssize_t slaveirq_read(struct file *file,
+                          char *buf, size_t count, loff_t *ppos)
+{
+       int len, err;
+       struct slaveirq_dev_data *data =
+               container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+       if (!data->data_ready) {
+               wait_event_interruptible_timeout(data->slaveirq_wait,
+                                                data->data_ready,
+                                                data->timeout);
+       }
+
+       if (data->data_ready && NULL != buf
+           && count >= sizeof(data->data)) {
+               err = copy_to_user(buf, &data->data, sizeof(data->data));
+               data->data.data_type = 0;
+       } else {
+               return 0;
+       }
+       if (err != 0) {
+               dev_err(data->dev.this_device,
+                       "Copy to user returned %d\n", err);
+               return -EFAULT;
+       }
+       data->data_ready = 0;
+       len = sizeof(data->data);
+       return len;
+}
+
+unsigned int slaveirq_poll(struct file *file, struct poll_table_struct *poll)
+{
+       int mask = 0;
+       struct slaveirq_dev_data *data =
+               container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+       poll_wait(file, &data->slaveirq_wait, poll);
+       if (data->data_ready)
+               mask |= POLLIN | POLLRDNORM;
+       return mask;
+}
+
+/* ioctl - I/O control */
+static long slaveirq_ioctl(struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+       int retval = 0;
+       int tmp;
+       struct slaveirq_dev_data *data =
+               container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+       switch (cmd) {
+       case SLAVEIRQ_SET_TIMEOUT:
+               data->timeout = arg;
+               break;
+
+       case SLAVEIRQ_GET_INTERRUPT_CNT:
+               tmp = data->data.interruptcount - 1;
+               if (data->data.interruptcount > 1)
+                       data->data.interruptcount = 1;
+
+               if (copy_to_user((int *) arg, &tmp, sizeof(int)))
+                       return -EFAULT;
+               break;
+       case SLAVEIRQ_GET_IRQ_TIME:
+               if (copy_to_user((int *) arg, &data->data.irqtime,
+                                sizeof(data->data.irqtime)))
+                       return -EFAULT;
+               data->data.irqtime = 0;
+               break;
+       default:
+               retval = -EINVAL;
+       }
+       return retval;
+}
+
+static irqreturn_t slaveirq_handler(int irq, void *dev_id)
+{
+       struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id;
+       static int mycount;
+       struct timeval irqtime;
+       mycount++;
+
+       data->data.interruptcount++;
+
+       /* wake up (unblock) for reading data from userspace */
+       /* and ignore first interrupt generated in module init */
+       if (data->data.interruptcount > 1) {
+               data->data_ready = 1;
+
+               do_gettimeofday(&irqtime);
+               data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
+               data->data.irqtime += irqtime.tv_usec;
+               data->data.data_type |= 1;
+
+               wake_up_interruptible(&data->slaveirq_wait);
+       }
+
+       return IRQ_HANDLED;
+
+}
+
+/* define which file operations are supported */
+static const struct file_operations slaveirq_fops = {
+       .owner = THIS_MODULE,
+       .read = slaveirq_read,
+       .poll = slaveirq_poll,
+
+#if HAVE_COMPAT_IOCTL
+       .compat_ioctl = slaveirq_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+       .unlocked_ioctl = slaveirq_ioctl,
+#endif
+       .open = slaveirq_open,
+       .release = slaveirq_release,
+};
+
+int slaveirq_init(struct i2c_adapter *slave_adapter,
+                 struct ext_slave_platform_data *pdata,
+                 char *name)
+{
+
+       int res;
+       struct slaveirq_dev_data *data;
+
+       if (!pdata->irq)
+               return -EINVAL;
+
+       pdata->irq_data = kzalloc(sizeof(*data),
+                               GFP_KERNEL);
+       data = (struct slaveirq_dev_data *) pdata->irq_data;
+       if (!data)
+               return -ENOMEM;
+
+       data->dev.minor = MISC_DYNAMIC_MINOR;
+       data->dev.name = name;
+       data->dev.fops = &slaveirq_fops;
+       data->irq = pdata->irq;
+       data->pid = 0;
+       data->data_ready = 0;
+       data->timeout = 0;
+
+       res = request_irq(data->irq, slaveirq_handler, IRQF_TRIGGER_RISING,
+                         data->dev.name, data);
+
+       if (res) {
+               dev_err(&slave_adapter->dev,
+                       "myirqtest: cannot register IRQ %d\n",
+                       data->irq);
+               goto out_request_irq;
+       }
+
+       res = misc_register(&data->dev);
+       if (res < 0) {
+               dev_err(&slave_adapter->dev,
+                       "misc_register returned %d\n",
+                       res);
+               goto out_misc_register;
+       }
+
+       init_waitqueue_head(&data->slaveirq_wait);
+       return res;
+
+out_misc_register:
+       free_irq(data->irq, data);
+out_request_irq:
+       kfree(pdata->irq_data);
+       pdata->irq_data = NULL;
+
+       return res;
+}
+
+void slaveirq_exit(struct ext_slave_platform_data *pdata)
+{
+       struct slaveirq_dev_data *data = pdata->irq_data;
+
+       if (!pdata->irq_data || data->irq <= 0)
+               return;
+
+       dev_info(data->dev.this_device, "Unregistering %s\n",
+                data->dev.name);
+
+       free_irq(data->irq, data);
+       misc_deregister(&data->dev);
+       kfree(pdata->irq_data);
+       pdata->irq_data = NULL;
+}
diff --git a/drivers/misc/mpu3050/slaveirq.h b/drivers/misc/mpu3050/slaveirq.h
new file mode 100644 (file)
index 0000000..ac53f1e
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#ifndef __SLAVEIRQ__
+#define __SLAVEIRQ__
+
+#ifdef __KERNEL__
+#include <linux/i2c-dev.h>
+#endif
+
+#include "mpu.h"
+#include "mpuirq.h"
+
+#define SLAVEIRQ_ENABLE_DEBUG          (1)
+#define SLAVEIRQ_GET_INTERRUPT_CNT     (2)
+#define SLAVEIRQ_GET_IRQ_TIME          (3)
+#define SLAVEIRQ_GET_LED_VALUE         (4)
+#define SLAVEIRQ_SET_TIMEOUT           (5)
+#define SLAVEIRQ_SET_SLAVE_INFO        (6)
+
+#ifdef __KERNEL__
+
+void slaveirq_exit(struct ext_slave_platform_data *pdata);
+int slaveirq_init(struct i2c_adapter *slave_adapter,
+               struct ext_slave_platform_data *pdata,
+               char *name);
+
+#endif
+
+#endif
index 973396e1ddfa6c9d4ff92a82b7f32218600ff837..230bb7e3154f5e64b83f31582f9e253022eef418 100644 (file)
@@ -3,15 +3,15 @@
 #
 
 comment "Magnetometer sensors"
-config SENSORS_AK8975
-  tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
-  depends on I2C
-  help
-  Say yes here to build support for Asahi Kasei AK8975 3-Axis
-  Magnetometer.
-
-  To compile this driver as a module, choose M here: the module
-  will be called ak8975.
+#config SENSORS_AK8975
+# tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+#depends on I2C
+#  help
+#  Say yes here to build support for Asahi Kasei AK8975 3-Axis
+#  Magnetometer.
+#
+#  To compile this driver as a module, choose M here: the module
+#  will be called ak8975.
 
 config SENSORS_AK8973
   tristate "Asahi Kasei AK8973 3-Axis Magnetometer"
diff --git a/include/linux/mpu.h b/include/linux/mpu.h
new file mode 100644 (file)
index 0000000..da1c6bc
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#ifndef __MPU_H_
+#define __MPU_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif
+
+#ifdef M_HW
+#include "mpu6000.h"
+#else
+#include "mpu3050.h"
+#endif
+
+/* Number of axes on each sensor */
+#define GYRO_NUM_AXES               (3)
+#define ACCEL_NUM_AXES              (3)
+#define COMPASS_NUM_AXES            (3)
+
+/* 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)
+#define MPU_READ_PRESSURE           (0x48)
+
+#define MPU_CONFIG_ACCEL            (0x20)
+#define MPU_CONFIG_COMPASS          (0x21)
+#define MPU_CONFIG_PRESSURE         (0x22)
+
+/* 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;
+};
+
+struct irq_data {
+       int interruptcount;
+       unsigned long long irqtime;
+       int data_type;
+       int data_size;
+       void *data;
+};
+enum ext_slave_config_key {
+    MPU_SLAVE_CONFIG_ODR_SUSPEND,
+    MPU_SLAVE_CONFIG_ODR_RESUME,
+    MPU_SLAVE_CONFIG_FSR_SUSPEND,
+    MPU_SLAVE_CONFIG_FSR_RESUME,
+    MPU_SLAVE_CONFIG_MOT_THS,
+    MPU_SLAVE_CONFIG_NMOT_THS,
+    MPU_SLAVE_CONFIG_MOT_DUR,
+    MPU_SLAVE_CONFIG_NMOT_DUR,
+    MPU_SLAVE_CONFIG_NUM_CONFIG_KEYS,
+};
+/* Structure for the following IOCTS's
+ * MPU_CONFIG_ACCEL
+ * MPU_CONFIG_COMPASS
+ * MPU_CONFIG_PRESSURE
+ */
+struct ext_slave_config {
+       int key;
+       int len;
+       void *data;
+};
+
+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,
+       ACCEL_ID_MPU6000,
+
+       COMPASS_ID_AKM,
+       COMPASS_ID_AMI30X,
+       COMPASS_ID_YAS529,
+       COMPASS_ID_HMC5883,
+       COMPASS_ID_LSM303,
+       COMPASS_ID_MMC314X,
+       COMPASS_ID_HSCDTD00XX,
+
+       PRESSURE_ID_BMA085,
+};
+
+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_INVALID = -1,
+       EXT_SLAVE_BUS_PRIMARY = 0,
+       EXT_SLAVE_BUS_SECONDARY = 1
+};
+
+
+/**
+ *  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
+ *  @irq: the irq number attached to the slave if any.
+ *  @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.
+ *  @irq_data: private data for the slave irq handler
+ *  @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.
+ */
+struct ext_slave_platform_data {
+       struct ext_slave_descr *(*get_slave_descr) (void);
+       int irq;
+       int adapt_num;
+       int bus;
+       unsigned char address;
+       signed char orientation[9];
+       void *irq_data;
+       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
+ *  @init:     function used to preallocate memory used by the driver
+ *  @exit:     function used to free memory allocated for the driver
+ *  @config:   function used to configure the device
+ *
+ *  @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.
+ */
+struct ext_slave_descr {
+       int (*init) (void *mlsl_handle,
+                    struct ext_slave_descr *slave,
+                    struct ext_slave_platform_data *pdata);
+       int (*exit) (void *mlsl_handle,
+                    struct ext_slave_descr *slave,
+                    struct ext_slave_platform_data *pdata);
+       int (*suspend) (void *mlsl_handle,
+                       struct ext_slave_descr *slave,
+                       struct ext_slave_platform_data *pdata);
+       int (*resume) (void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata);
+       int (*read) (void *mlsl_handle,
+                    struct ext_slave_descr *slave,
+                    struct ext_slave_platform_data *pdata,
+                    unsigned char *data);
+       int (*config) (void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata,
+                      struct ext_slave_config *config);
+
+       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
+ * @pressure:          Pressure 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.
+ */
+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;
+       struct ext_slave_platform_data pressure;
+};
+
+
+/*
+    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    /* 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
+
+/* MPU6000 Accel */
+#if defined(CONFIG_SENSORS_MPU6000) || defined(CONFIG_SENSORS_MPU6000_MODULE)
+struct ext_slave_descr *mantis_get_slave_descr(void);
+#undef get_accel_slave_descr
+#define get_accel_slave_descr mantis_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   /* 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_AMI30X   /* AICHI Steel compass */
+struct ext_slave_descr *ami30x_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr ami30x_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
+
+#ifdef CONFIG_SENSORS_HSCDTD00XX       /* Alps compass */
+struct ext_slave_descr *hscdtd00xx_get_slave_descr(void);
+#undef get_compass_slave_descr
+#define get_compass_slave_descr hscdtd00xx_get_slave_descr
+#endif
+
+/*
+    Pressure
+*/
+#define get_pressure_slave_descr NULL
+
+#ifdef CONFIG_SENSORS_BMA085   /* BMA pressure */
+struct ext_slave_descr *bma085_get_slave_descr(void);
+#undef get_pressure_slave_descr
+#define get_pressure_slave_descr bma085_get_slave_descr
+#endif
+
+#endif                         /* __MPU_H_ */
diff --git a/include/linux/mpu3050.h b/include/linux/mpu3050.h
new file mode 100644 (file)
index 0000000..e257823
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+#ifndef __MPU3050_H_
+#define __MPU3050_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif
+
+#ifdef M_HW
+#error MPU6000 build including MPU3050 header
+#endif
+
+#define MPU_NAME "mpu3050"
+#define DEFAULT_MPU_SLAVEADDR       0x68
+#include "mpu.h"
+/*==== 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)
+
+enum MPU_MEMORY_BANKS {
+       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
+};
+
+#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)
+
+#endif                         /* __MPU3050_H_ */
diff --git a/include/linux/mpu6000.h b/include/linux/mpu6000.h
new file mode 100644 (file)
index 0000000..c02859a
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ $License:
+    Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+ $
+ */
+
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ *      @file     mpu6000.h
+ *      @brief
+ */
+
+#ifndef __MPU6000_H_
+#define __MPU6000_H_
+
+#define MPU_NAME "mpu6000"
+#define DEFAULT_MPU_SLAVEADDR       0x68
+
+/*==== M_HW REGISTER SET ====*/
+enum {
+       MPUREG_XG_OFFS_TC = 0,
+       MPUREG_YG_OFFS_TC,
+       MPUREG_ZG_OFFS_TC,
+       MPUREG_X_FINE_GAIN,
+       MPUREG_Y_FINE_GAIN,
+       MPUREG_Z_FINE_GAIN,
+       MPUREG_XA_OFFS_H,
+       MPUREG_XA_OFFS_L_TC,
+       MPUREG_YA_OFFS_H,
+       MPUREG_YA_OFFS_L_TC,
+       MPUREG_ZA_OFFS_H,
+       MPUREG_ZA_OFFS_L_TC,    /* 0xB */
+       MPUREG_0C_RSVD,
+       MPUREG_0D_RSVD,
+       MPUREG_0E_RSVD,
+       MPUREG_0F_RSVD,
+       MPUREG_10_RSVD,
+       MPUREG_11_RSVD,
+       MPUREG_12_RSVD,
+       MPUREG_XG_OFFS_USRH,
+       MPUREG_XG_OFFS_USRL,
+       MPUREG_YG_OFFS_USRH,
+       MPUREG_YG_OFFS_USRL,
+       MPUREG_ZG_OFFS_USRH,
+       MPUREG_ZG_OFFS_USRL,
+       MPUREG_SMPLRT_DIV,      /* 0x19 */
+       MPUREG_CONFIG,          /* 0x1A ==> DLPF_FS_SYNC */
+       MPUREG_GYRO_CONFIG,
+       MPUREG_ACCEL_CONFIG,
+       MPUREG_ACCEL_FF_THR,
+       MPUREG_ACCEL_FF_DUR,
+       MPUREG_ACCEL_MOT_THR,
+       MPUREG_ACCEL_MOT_DUR,
+       MPUREG_ACCEL_ZRMOT_THR,
+       MPUREG_ACCEL_ZRMOT_DUR,
+       MPUREG_FIFO_EN,         /* 0x23 */
+       MPUREG_I2C_MST_CTRL,
+       MPUREG_I2C_SLV0_ADDR,   /* 0x25 */
+       MPUREG_I2C_SLV0_REG,
+       MPUREG_I2C_SLV0_CTRL,
+       MPUREG_I2C_SLV1_ADDR,   /* 0x28 */
+       MPUREG_I2C_SLV1_REG_PASSWORD,
+       MPUREG_I2C_SLV1_CTRL,
+       MPUREG_I2C_SLV2_ADDR,   /* 0x2B */
+       MPUREG_I2C_SLV2_REG,
+       MPUREG_I2C_SLV2_CTRL,
+       MPUREG_I2C_SLV3_ADDR,   /* 0x2E */
+       MPUREG_I2C_SLV3_REG,
+       MPUREG_I2C_SLV3_CTRL,
+       MPUREG_I2C_SLV4_ADDR,   /* 0x31 */
+       MPUREG_I2C_SLV4_REG,
+       MPUREG_I2C_SLV4_DO,
+       MPUREG_I2C_SLV4_CTRL,
+       MPUREG_I2C_SLV4_DI,
+       MPUREG_I2C_MST_STATUS,  /* 0x36 */
+       MPUREG_INT_PIN_CFG,     /* 0x37 ==> -* INT_CFG */
+       MPUREG_INT_ENABLE,      /* 0x38 ==> / */
+       MPUREG_DMP_INT_STATUS,  /* 0x39 */
+       MPUREG_INT_STATUS,      /* 0x3A */
+       MPUREG_ACCEL_XOUT_H,    /* 0x3B */
+       MPUREG_ACCEL_XOUT_L,
+       MPUREG_ACCEL_YOUT_H,
+       MPUREG_ACCEL_YOUT_L,
+       MPUREG_ACCEL_ZOUT_H,
+       MPUREG_ACCEL_ZOUT_L,
+       MPUREG_TEMP_OUT_H,      /* 0x41 */
+       MPUREG_TEMP_OUT_L,
+       MPUREG_GYRO_XOUT_H,     /* 0x43 */
+       MPUREG_GYRO_XOUT_L,
+       MPUREG_GYRO_YOUT_H,
+       MPUREG_GYRO_YOUT_L,
+       MPUREG_GYRO_ZOUT_H,
+       MPUREG_GYRO_ZOUT_L,
+       MPUREG_EXT_SLV_SENS_DATA_00,    /* 0x49 */
+       MPUREG_EXT_SLV_SENS_DATA_01,
+       MPUREG_EXT_SLV_SENS_DATA_02,
+       MPUREG_EXT_SLV_SENS_DATA_03,
+       MPUREG_EXT_SLV_SENS_DATA_04,
+       MPUREG_EXT_SLV_SENS_DATA_05,
+       MPUREG_EXT_SLV_SENS_DATA_06,    /* 0x4F */
+       MPUREG_EXT_SLV_SENS_DATA_07,
+       MPUREG_EXT_SLV_SENS_DATA_08,
+       MPUREG_EXT_SLV_SENS_DATA_09,
+       MPUREG_EXT_SLV_SENS_DATA_10,
+       MPUREG_EXT_SLV_SENS_DATA_11,
+       MPUREG_EXT_SLV_SENS_DATA_12,    /* 0x55 */
+       MPUREG_EXT_SLV_SENS_DATA_13,
+       MPUREG_EXT_SLV_SENS_DATA_14,
+       MPUREG_EXT_SLV_SENS_DATA_15,
+       MPUREG_EXT_SLV_SENS_DATA_16,
+       MPUREG_EXT_SLV_SENS_DATA_17,
+       MPUREG_EXT_SLV_SENS_DATA_18,    /* 0x5B */
+       MPUREG_EXT_SLV_SENS_DATA_19,
+       MPUREG_EXT_SLV_SENS_DATA_20,
+       MPUREG_EXT_SLV_SENS_DATA_21,
+       MPUREG_EXT_SLV_SENS_DATA_22,
+       MPUREG_EXT_SLV_SENS_DATA_23,
+       ACCEL_INTEL_STATUS,     /* 0x61 */
+       MPUREG_62_RSVD,
+       MPUREG_63_RSVD,
+       MPUREG_64_RSVD,
+       MPUREG_65_RSVD,
+       MPUREG_66_RSVD,
+       MPUREG_67_RSVD,
+       SIGNAL_PATH_RESET,      /* 0x68 */
+       ACCEL_INTEL_CTRL,       /* 0x69 */
+       MPUREG_USER_CTRL,       /* 0x6A */
+       MPUREG_PWR_MGMT_1,      /* 0x6B */
+       MPUREG_PWR_MGMT_2,
+       MPUREG_BANK_SEL,        /* 0x6D */
+       MPUREG_MEM_START_ADDR,  /* 0x6E */
+       MPUREG_MEM_R_W,         /* 0x6F */
+       MPUREG_PRGM_STRT_ADDRH,
+       MPUREG_PRGM_STRT_ADDRL,
+       MPUREG_FIFO_COUNTH,     /* 0x72 */
+       MPUREG_FIFO_COUNTL,
+       MPUREG_FIFO_R_W,        /* 0x74 */
+       MPUREG_WHOAMI,          /* 0x75,117 */
+
+       NUM_OF_MPU_REGISTERS    /* = 0x76,118 */
+};
+
+/*==== M_HW MEMORY ====*/
+enum MPU_MEMORY_BANKS {
+       MEM_RAM_BANK_0 = 0,
+       MEM_RAM_BANK_1,
+       MEM_RAM_BANK_2,
+       MEM_RAM_BANK_3,
+       MEM_RAM_BANK_4,
+       MEM_RAM_BANK_5,
+       MEM_RAM_BANK_6,
+       MEM_RAM_BANK_7,
+       MEM_RAM_BANK_8,
+       MEM_RAM_BANK_9,
+       MEM_RAM_BANK_10,
+       MEM_RAM_BANK_11,
+       MPU_MEM_NUM_RAM_BANKS,
+       MPU_MEM_OTP_BANK_0 = 16
+};
+
+
+/*==== M_HW parameters ====*/
+
+#define NUM_REGS            (NUM_OF_MPU_REGISTERS)
+#define START_SENS_REGS     (0x3B)
+#define NUM_SENS_REGS       (0x60-START_SENS_REGS+1)
+
+/*---- MPU Memory ----*/
+#define NUM_BANKS           (MPU_MEM_NUM_RAM_BANKS)
+#define BANK_SIZE           (256)
+#define MEM_SIZE            (NUM_BANKS*BANK_SIZE)
+#define MPU_MEM_BANK_SIZE   (BANK_SIZE)        /*alternative name */
+
+#define FIFO_HW_SIZE        (1024)
+
+#define NUM_EXT_SLAVES      (4)
+
+
+/*==== BITS FOR M_HW ====*/
+
+/*---- M_HW 'FIFO_EN' register (23) ----*/
+#define        BIT_TEMP_OUT                            0x80
+#define        BIT_GYRO_XOUT                           0x40
+#define        BIT_GYRO_YOUT                           0x20
+#define        BIT_GYRO_ZOUT                           0x10
+#define        BIT_ACCEL                               0x08
+#define        BIT_SLV_2                               0x04
+#define        BIT_SLV_1                               0x02
+#define        BIT_SLV_0                               0x01
+/*---- M_HW 'CONFIG' register (1A) ----*/
+/*NONE                                         0xC0 */
+#define        BITS_EXT_SYNC_SET                       0x38
+#define        BITS_DLPF_CFG                           0x07
+/*---- M_HW 'GYRO_CONFIG' register (1B) ----*/
+/* voluntarily modified label from BITS_FS_SEL to
+ * BITS_GYRO_FS_SEL to avoid confusion with MPU
+ */
+#define BITS_GYRO_FS_SEL                       0x18
+/*NONE                                         0x07 */
+/*---- M_HW 'ACCEL_CONFIG' register (1C) ----*/
+#define BITS_ACCEL_FS_SEL                      0x18
+#define BITS_ACCEL_HPF                         0x07
+/*---- M_HW 'I2C_MST_CTRL' register (24) ----*/
+#define BIT_MULT_MST_DIS                       0x80
+#define BIT_WAIT_FOR_ES                        0x40
+#define BIT_I2C_MST_VDDIO                      0x20
+/*NONE                                         0x10 */
+#define BITS_I2C_MST_CLK                       0x0F
+/*---- M_HW 'I2C_SLV?_CTRL' register (27,2A,2D,30) ----*/
+#define BIT_SLV_ENABLE                         0x80
+#define BIT_SLV_BYTE_SW                        0x40
+/*NONE                                         0x20 */
+#define BIT_SLV_GRP                            0x10
+#define BITS_SLV_LENG                          0x0F
+/*---- M_HW 'I2C_SLV4_ADDR' register (31) ----*/
+#define BIT_I2C_SLV4_RNW                       0x80
+/*---- M_HW 'I2C_SLV4_CTRL' register (34) ----*/
+#define BIT_I2C_SLV4_EN                        0x80
+#define BIT_SLV4_DONE_INT_EN                   0x40
+/*NONE                                         0x3F */
+/*---- M_HW 'I2C_MST_STATUS' register (36) ----*/
+#define BIT_PASSTHROUGH                        0x80
+#define BIT_I2C_SLV4_DONE                      0x40
+#define BIT_I2C_LOST_ARB                       0x20
+#define BIT_I2C_SLV4_NACK                      0x10
+#define BIT_I2C_SLV3_NACK                      0x08
+#define BIT_I2C_SLV2_NACK                      0x04
+#define BIT_I2C_SLV1_NACK                      0x02
+#define BIT_I2C_SLV0_NACK                      0x01
+/*---- M_HW 'INT_PIN_CFG' register (37) ----*/
+#define        BIT_ACTL                                0x80
+#define BIT_ACTL_LOW                           0x80
+#define BIT_ACTL_HIGH                          0x00
+#define        BIT_OPEN                                0x40
+#define        BIT_LATCH_INT_EN                        0x20
+#define        BIT_INT_ANYRD_2CLEAR                    0x10
+#define        BIT_ACTL_FSYNC                          0x08
+#define        BIT_FSYNC_INT_EN                        0x04
+#define        BIT_BYPASS_EN                           0x02
+#define        BIT_CLKOUT_EN                           0x01
+/*---- M_HW 'INT_ENABLE' register (38) ----*/
+#define        BIT_FF_EN                               0x80
+#define        BIT_MOT_EN                              0x40
+#define        BIT_ZMOT_EN                             0x20
+#define        BIT_FIFO_OVERFLOW_EN                    0x10
+#define BIT_I2C_MST_INT_EN                     0x08
+#define        BIT_PLL_RDY_EN                          0x04
+#define BIT_DMP_INT_EN                         0x02
+#define        BIT_RAW_RDY_EN                          0x01
+/*---- M_HW 'DMP_INT_STATUS' register (39) ----*/
+/*NONE                                          0x80 */
+/*NONE                                          0x40 */
+#define        BIT_DMP_INT_5                           0x20
+#define        BIT_DMP_INT_4                           0x10
+#define        BIT_DMP_INT_3                           0x08
+#define        BIT_DMP_INT_2                           0x04
+#define        BIT_DMP_INT_1                           0x02
+#define        BIT_DMP_INT_0                           0x01
+/*---- M_HW 'INT_STATUS' register (3A) ----*/
+#define        BIT_FF_INT                              0x80
+#define        BIT_MOT_INT                             0x40
+#define        BIT_ZMOT_INT                            0x20
+#define        BIT_FIFO_OVERFLOW_INT                   0x10
+#define        BIT_I2C_MST_INT                         0x08
+#define        BIT_PLL_RDY_INT                         0x04
+#define BIT_DMP_INT                            0x02
+#define        BIT_RAW_DATA_RDY_INT                    0x01
+/*---- M_HW 'BANK_SEL' register (6D) ----*/
+#define        BIT_PRFTCH_EN                           0x40
+#define        BIT_CFG_USER_BANK                       0x20
+#define        BITS_MEM_SEL                            0x1f
+/*---- M_HW 'USER_CTRL' register (6A) ----*/
+#define        BIT_DMP_EN                              0x80
+#define        BIT_FIFO_EN                             0x40
+#define        BIT_I2C_MST_EN                          0x20
+#define        BIT_I2C_IF_DIS                          0x10
+#define        BIT_DMP_RST                             0x08
+#define        BIT_FIFO_RST                            0x04
+#define        BIT_I2C_MST_RST                         0x02
+#define        BIT_SIG_COND_RST                        0x01
+/*---- M_HW 'PWR_MGMT_1' register (6B) ----*/
+#define        BIT_H_RESET                             0x80
+#define BITS_PWRSEL                            0x70
+#define BIT_WKUP_INT                           0x08
+#define BITS_CLKSEL                            0x07
+/*---- M_HW 'PWR_MGMT_2' register (6C) ----*/
+#define BITS_LPA_WAKE_CTRL                     0xC0
+#define        BIT_STBY_XA                             0x20
+#define        BIT_STBY_YA                             0x10
+#define        BIT_STBY_ZA                             0x08
+#define        BIT_STBY_XG                             0x04
+#define        BIT_STBY_YG                             0x02
+#define        BIT_STBY_ZG                             0x01
+
+/* although it has 6, this refers to the gyros */
+#define MPU_NUM_AXES (3)
+
+/*----------------------------------------------------------------------------*/
+/*---- Alternative names to take care of conflicts with current mpu3050.h ----*/
+/*----------------------------------------------------------------------------*/
+
+/*-- registers --*/
+#define MPUREG_DLPF_FS_SYNC        MPUREG_CONFIG               /* 0x1A */
+
+#define MPUREG_PRODUCT_ID          MPUREG_WHOAMI               /* 0x75  HACK!*/
+#define MPUREG_PWR_MGM             MPUREG_PWR_MGMT_1           /* 0x6B */
+#define MPUREG_FIFO_EN1            MPUREG_FIFO_EN              /* 0x23 */
+#define MPUREG_DMP_CFG_1           MPUREG_PRGM_STRT_ADDRH      /* 0x70 */
+#define MPUREG_DMP_CFG_2           MPUREG_PRGM_STRT_ADDRL      /* 0x71 */
+#define MPUREG_INT_CFG             MPUREG_INT_ENABLE           /* 0x38 */
+#define MPUREG_X_OFFS_USRH         MPUREG_XG_OFFS_USRH         /* 0x13 */
+#define MPUREG_WHO_AM_I            MPUREG_WHOAMI               /* 0x75 */
+#define MPUREG_23_RSVD             MPUREG_EXT_SLV_SENS_DATA_00 /* 0x49 */
+#define MPUREG_AUX_SLV_ADDR        MPUREG_I2C_SLV0_ADDR                /* 0x25 */
+#define MPUREG_ACCEL_BURST_ADDR    MPUREG_I2C_SLV0_REG         /* 0x26 */
+
+/*-- bits --*/
+/* 'USER_CTRL' register */
+#define BIT_AUX_IF_EN               BIT_I2C_MST_EN
+#define BIT_AUX_RD_LENG             BIT_I2C_MST_EN
+#define BIT_IME_IF_RST              BIT_I2C_MST_RST
+#define BIT_GYRO_RST                BIT_SIG_COND_RST
+/* 'INT_ENABLE' register */
+#define BIT_RAW_RDY                 BIT_RAW_DATA_RDY_INT
+#define BIT_MPU_RDY_EN              BIT_PLL_RDY_EN
+/* 'INT_STATUS' register */
+#define BIT_INT_STATUS_FIFO_OVERLOW BIT_FIFO_OVERFLOW_INT
+
+
+
+/*---- M_HW Silicon Revisions ----*/
+#define MPU_SILICON_REV_A1           1 /* M_HW A1 Device */
+#define MPU_SILICON_REV_B1           2 /* M_HW B1 Device */
+
+/*---- 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)
+
+#endif                         /* __IMU6000_H_ */