on 977 add mpu config and update mpu code
authorywj <ywj@rock-chips.com>
Fri, 4 Apr 2014 02:52:17 +0000 (10:52 +0800)
committerywj <ywj@rock-chips.com>
Fri, 4 Apr 2014 02:52:48 +0000 (10:52 +0800)
58 files changed:
arch/arm/boot/dts/rk3288-p977.dts
drivers/misc/Kconfig [changed mode: 0644->0755]
drivers/misc/Makefile [changed mode: 0644->0755]
drivers/misc/inv_mpu/Kconfig [changed mode: 0644->0755]
drivers/misc/inv_mpu/Makefile [changed mode: 0644->0755]
drivers/misc/inv_mpu/README [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/Kconfig [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/Makefile [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/adxl34x.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/bma150.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/bma222.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/bma250.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/cma3000.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/kxsd9.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/lis331.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/lis3dh.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/lsm303dlx_a.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/mma8450.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/mma845x.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/accel/mpu6050.c [new file with mode: 0755]
drivers/misc/inv_mpu/accel/mpu6050.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/Kconfig [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/Makefile [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/ak8963.c [new file with mode: 0755]
drivers/misc/inv_mpu/compass/ak8972.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/ak8975.c
drivers/misc/inv_mpu/compass/ami306.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/ami30x.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/ami_hw.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/ami_sensor_def.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/hmc5883.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/hscdtd002b.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/hscdtd004a.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/lsm303dlx_m.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/mmc314x.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/yas529-kernel.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/compass/yas530.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/log.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mldl_cfg.c
drivers/misc/inv_mpu/mldl_cfg.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mldl_print_cfg.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/mldl_print_cfg.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mlsl-kernel.c
drivers/misc/inv_mpu/mlsl.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mltypes.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mpu-dev.c
drivers/misc/inv_mpu/mpu-dev.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mpu3050.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/mpu6050b1.h [new file with mode: 0755]
drivers/misc/inv_mpu/mpuirq.c
drivers/misc/inv_mpu/mpuirq.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/pressure/Kconfig [changed mode: 0644->0755]
drivers/misc/inv_mpu/pressure/Makefile [changed mode: 0644->0755]
drivers/misc/inv_mpu/pressure/bma085.c [changed mode: 0644->0755]
drivers/misc/inv_mpu/slaveirq.h [changed mode: 0644->0755]
drivers/misc/inv_mpu/timerirq.c
drivers/misc/inv_mpu/timerirq.h [changed mode: 0644->0755]
include/linux/mpu.h

index eb9a2627e7818db6a4ed91497e96b7941b446ec3..871c5de0b476b75908036a4f1c0abbb147905887 100755 (executable)
                compatible = "nxp,pcf8563";
                reg = <0x51>;
        };
-       
+/*
        sensor@1d {
                compatible = "gs_mma8452";
                reg = <0x1d>;
                irq_enable = <1>;
                poll_delay_ms = <30>;
                layout = <8>;
+               status = "disabled";
        };
+
        sensor@0d {
                compatible = "ak8975";
                reg = <0x0d>;
                irq_enable = <1>;
                poll_delay_ms = <30>;
                layout = <1>;
+               status = "disabled";
        };
+*/
        sensor@10 {
               compatible = "ls_cm3218";
               reg = <0x10>;
               poll_delay_ms = <30>;
               layout = <1>;
        };
-       
+             
+       mpu6050:mpu@68{
+       compatible = "mpu6050";
+       reg = <0x68>;
+       mpu-int_config = <0x10>;
+       mpu-level_shifter = <0>;
+       mpu-orientation = <1 0 0 0 1 0 0 0 1>;  
+       orientation-x= <1>;
+       orientation-y= <0>;
+       orientation-z= <1>;
+       irq-gpio = <&gpio8 GPIO_A0 IRQ_TYPE_LEVEL_LOW>;                 
+       mpu-debug = <1>;
+       };
+/*
+       ak8963:compass@0d{
+       compatible = "ak8963";
+       reg = <0x0d>;
+       compass-bus = <0>;
+       compass-adapt_num = <0>;
+       compass-orientation = <1 0 0 0 1 0 0 0 1>;
+       orientation-x= <0>;
+       orientation-y= <0>;
+       orientation-z= <1>;     
+       compass-debug = <1>;
+       status = "disabled";
+       };
+*/
+       ak8975:compass@0d{
+       compatible = "ak8975";
+       reg = <0x0d>;
+       compass-bus = <0>;
+       compass-adapt_num = <0>;
+       compass-orientation = <1 0 0 0 1 0 0 0 1>;
+       orientation-x= <1>;
+       orientation-y= <0>;
+       orientation-z= <1>;     
+       compass-debug = <1>;
+       };
+
 };
 
 &i2c2 {
old mode 100644 (file)
new mode 100755 (executable)
index 3f57434..b3bf720
@@ -534,6 +534,7 @@ config SRAM
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
+source "drivers/misc/inv_mpu/Kconfig"
 source "drivers/misc/ti-st/Kconfig"
 source "drivers/misc/lis3lv02d/Kconfig"
 source "drivers/misc/carma/Kconfig"
old mode 100644 (file)
new mode 100755 (executable)
index a57666c..2e082e3
@@ -53,4 +53,5 @@ obj-$(CONFIG_ALTERA_STAPL)    +=altera-stapl/
 obj-$(CONFIG_INTEL_MEI)                += mei/
 obj-$(CONFIG_VMWARE_VMCI)      += vmw_vmci/
 obj-$(CONFIG_LATTICE_ECP3_CONFIG)      += lattice-ecp3-config.o
+obj-y += inv_mpu/
 obj-$(CONFIG_SRAM)             += sram.o
old mode 100644 (file)
new mode 100755 (executable)
index 43f8881..8643630
@@ -9,6 +9,7 @@ config MPU_SENSORS_TIMERIRQ
 menuconfig: INV_SENSORS
        tristate "Motion Processing Unit"
        depends on I2C
+       default n
 
 if INV_SENSORS
 
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index fd2d7b5..745d90a
@@ -25,7 +25,7 @@
  *      @file   bma150.c
  *      @brief  Accelerometer setup and handling methods for Bosch BMA150.
  */
-#define DEBUG
+
 /* -------------------------------------------------------------------------- */
 #include <linux/i2c.h>
 #include <linux/module.h>
@@ -671,7 +671,7 @@ static int bma150_mod_probe(struct i2c_client *client,
        struct bma150_mod_private_data *private_data;
        int result = 0;
 
-       dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client);
+       dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                result = -ENODEV;
old mode 100644 (file)
new mode 100755 (executable)
index e9cfb67..a8e14bd
@@ -51,8 +51,6 @@
 #define BMA222_PWR_REG         (0x11)
 #define BMA222_SOFTRESET_REG   (0x14)
 
-#define BMA222_INTTERUPTSET_REG (0x17)
-
 #define BMA222_STATUS_RDY_MASK (0x80)
 #define BMA222_FSR_MASK                (0x0F)
 #define BMA222_ODR_MASK                (0x1F)
@@ -337,8 +335,6 @@ static int bma222_get_config(void *mlsl_handle,
                break;
        case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
        case MPU_SLAVE_CONFIG_IRQ_RESUME:
-               //zwp,TODO,need to add irq config???
-               return INV_SUCCESS;
        default:
                return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
        };
@@ -394,8 +390,6 @@ static int bma222_config(void *mlsl_handle,
                                      *((long *)data->data));
        case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
        case MPU_SLAVE_CONFIG_IRQ_RESUME:
-               //zwp,TODO,need to add irq config???
-               return INV_SUCCESS;
        default:
                return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
        };
@@ -512,18 +506,14 @@ static int bma222_read(void *mlsl_handle,
                       unsigned char *data)
 {
        int result = INV_SUCCESS;
-/*     result = inv_serial_read(mlsl_handle, pdata->address,
+       result = inv_serial_read(mlsl_handle, pdata->address,
                                BMA222_STATUS_REG, 1, data);
        if (data[0] & BMA222_STATUS_RDY_MASK) {
-*/
                result = inv_serial_read(mlsl_handle, pdata->address,
                                 slave->read_reg, slave->read_len, data);
-
        return result;
-/*     } else{
+       } else
                return INV_ERROR_ACCEL_DATA_NOT_READY;
-       }
-*/
 }
 
 static struct ext_slave_descr bma222_descr = {
@@ -565,7 +555,7 @@ static int bma222_mod_probe(struct i2c_client *client,
        struct ext_slave_platform_data *pdata;
        struct bma222_mod_private_data *private_data;
        int result = 0;
-       printk("%s,++++++++++++++++++++\n",__FUNCTION__);
+
        dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/drivers/misc/inv_mpu/accel/mpu6050.c b/drivers/misc/inv_mpu/accel/mpu6050.c
new file mode 100755 (executable)
index 0000000..efb6627
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+       $License:
+       Copyright (C) 2011 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/>.
+       $
+ */
+
+/**
+ *  @addtogroup ACCELDL
+ *  @brief      Provides the interface to setup and handle an accelerometer.
+ *
+ *  @{
+ *      @file   mpu6050.c
+ *      @brief  Accelerometer setup and handling methods for Invensense MPU6050
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include "mpu-dev.h"
+
+#include <log.h>
+#include <linux/mpu.h>
+#include "mpu6050b1.h"
+#include "mlsl.h"
+#include "mldl_cfg.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+/* -------------------------------------------------------------------------- */
+
+struct mpu6050_config {
+       unsigned int odr;               /**< output data rate 1/1000 Hz */
+       unsigned int fsr;               /**< full scale range mg */
+       unsigned int ths;               /**< mot/no-mot thseshold mg */
+       unsigned int dur;               /**< mot/no-mot duration ms */
+       unsigned int irq_type;          /**< irq type */
+};
+
+struct mpu6050_private_data {
+       struct mpu6050_config suspend;
+       struct mpu6050_config resume;
+       struct mldl_cfg *mldl_cfg_ref;
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int mpu6050_set_mldl_cfg_ref(void *mlsl_handle,
+                       struct ext_slave_platform_data *pdata,
+                       struct mldl_cfg *mldl_cfg_ref)
+{
+       struct mpu6050_private_data *private_data =
+                       (struct mpu6050_private_data *)pdata->private_data;
+       private_data->mldl_cfg_ref = mldl_cfg_ref;
+       return 0;
+}
+static int mpu6050_set_lp_mode(void *mlsl_handle,
+                       struct ext_slave_platform_data *pdata,
+                       unsigned char lpa_freq)
+{
+       unsigned char b = 0;
+       /* Reducing the duration setting for lp mode */
+       b = 1;
+       inv_serial_single_write(mlsl_handle, pdata->address,
+                               MPUREG_ACCEL_MOT_DUR, b);
+       /* Setting the cycle bit and LPA wake up freq */
+       inv_serial_read(mlsl_handle, pdata->address, MPUREG_PWR_MGMT_1, 1,
+                       &b);
+       b |= BIT_CYCLE | BIT_PD_PTAT;
+       inv_serial_single_write(mlsl_handle, pdata->address,
+                               MPUREG_PWR_MGMT_1,
+                               b);
+       inv_serial_read(mlsl_handle, pdata->address,
+                       MPUREG_PWR_MGMT_2, 1, &b);
+       b |= lpa_freq & BITS_LPA_WAKE_CTRL;
+       inv_serial_single_write(mlsl_handle, pdata->address,
+                               MPUREG_PWR_MGMT_2, b);
+
+       return INV_SUCCESS;
+}
+
+static int mpu6050_set_fp_mode(void *mlsl_handle,
+                               struct ext_slave_platform_data *pdata)
+{
+       unsigned char b;
+       struct mpu6050_private_data *private_data =
+                       (struct mpu6050_private_data *)pdata->private_data;
+       /* Resetting the cycle bit and LPA wake up freq */
+       inv_serial_read(mlsl_handle, pdata->address,
+                       MPUREG_PWR_MGMT_1, 1, &b);
+       b &= ~BIT_CYCLE & ~BIT_PD_PTAT;
+       inv_serial_single_write(mlsl_handle, pdata->address,
+                               MPUREG_PWR_MGMT_1, b);
+       inv_serial_read(mlsl_handle, pdata->address,
+                       MPUREG_PWR_MGMT_2, 1, &b);
+       b &= ~BITS_LPA_WAKE_CTRL;
+       inv_serial_single_write(mlsl_handle, pdata->address,
+                               MPUREG_PWR_MGMT_2, b);
+       /* Resetting the duration setting for fp mode */
+       b = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB;
+       inv_serial_single_write(mlsl_handle, pdata->address,
+                               MPUREG_ACCEL_MOT_DUR, b);
+
+       return INV_SUCCESS;
+}
+/**
+ * Record the odr for use in computing duration values.
+ *
+ * @param config Config to set, suspend or resume structure
+ * @param odr output data rate in 1/1000 hz
+ */
+static int mpu6050_set_odr(void *mlsl_handle,
+                         struct ext_slave_platform_data *pdata,
+                         struct mpu6050_config *config, long apply, long odr)
+{
+       int result;
+       unsigned char b;
+       unsigned char lpa_freq = 1; /* Default value */
+       long base;
+       int total_divider;
+       struct mpu6050_private_data *private_data =
+                       (struct mpu6050_private_data *)pdata->private_data;
+       struct mldl_cfg *mldl_cfg_ref =
+                       (struct mldl_cfg *)private_data->mldl_cfg_ref;
+
+       if (mldl_cfg_ref) {
+               base = 1000 *
+                       inv_mpu_get_sampling_rate_hz(mldl_cfg_ref->mpu_gyro_cfg)
+                       * (mldl_cfg_ref->mpu_gyro_cfg->divider + 1);
+       } else {
+               /* have no reference to mldl_cfg => assume base rate is 1000 */
+               base = 1000000L;
+       }
+
+       if (odr != 0) {
+               total_divider = (base / odr) - 1;
+               /* final odr MAY be different from requested odr due to
+                  integer truncation */
+               config->odr = base / (total_divider + 1);
+       } else {
+               config->odr = 0;
+               return 0;
+       }
+
+       /* if the DMP and/or gyros are on, don't set the ODR =>
+          the DMP/gyro mldl_cfg->divider setting will handle it */
+       if (apply
+           && (mldl_cfg_ref &&
+           !(mldl_cfg_ref->inv_mpu_cfg->requested_sensors &
+                   INV_DMP_PROCESSOR))) {
+               result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                       MPUREG_SMPLRT_DIV,
+                                       (unsigned char)total_divider);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               MPL_LOGI("ODR : %d mHz\n", config->odr);
+       }
+       /* Decide whether to put accel in LP mode or pull out of LP mode
+          based on the odr. */
+       switch (odr) {
+       case 1000:
+               lpa_freq = BITS_LPA_WAKE_1HZ;
+               break;
+       case 2000:
+               lpa_freq = BITS_LPA_WAKE_2HZ;
+               break;
+       case 10000:
+               lpa_freq = BITS_LPA_WAKE_10HZ;
+               break;
+       case 40000:
+               lpa_freq = BITS_LPA_WAKE_40HZ;
+               break;
+       default:
+               inv_serial_read(mlsl_handle, pdata->address,
+                               MPUREG_PWR_MGMT_1, 1, &b);
+               b &= BIT_CYCLE;
+               if (b == BIT_CYCLE) {
+                       MPL_LOGI(" Accel LP - > FP mode. \n ");
+                       mpu6050_set_fp_mode(mlsl_handle, pdata);
+               }
+       }
+       /* If lpa_freq default value was changed, set into LP mode */
+       if (lpa_freq != 1) {
+               MPL_LOGI(" Accel FP - > LP mode. \n ");
+               mpu6050_set_lp_mode(mlsl_handle, pdata, lpa_freq);
+       }
+       return 0;
+}
+
+static int mpu6050_set_fsr(void *mlsl_handle,
+                         struct ext_slave_platform_data *pdata,
+                         struct mpu6050_config *config, long apply, long fsr)
+{
+       unsigned char fsr_mask;
+       int result;
+
+       if (fsr <= 2000) {
+               config->fsr = 2000;
+               fsr_mask = 0x00;
+       } else if (fsr <= 4000) {
+               config->fsr = 4000;
+               fsr_mask = 0x08;
+       } else if (fsr <= 8000) {
+               config->fsr = 8000;
+               fsr_mask = 0x10;
+       } else { /* fsr = [8001, oo) */
+               config->fsr = 16000;
+               fsr_mask = 0x18;
+       }
+
+       if (apply) {
+               unsigned char reg;
+               result = inv_serial_read(mlsl_handle, pdata->address,
+                                        MPUREG_ACCEL_CONFIG, 1, &reg);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                                MPUREG_ACCEL_CONFIG,
+                                                reg | fsr_mask);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               MPL_LOGV("FSR: %d\n", config->fsr);
+       }
+       return 0;
+}
+
+static int mpu6050_set_irq(void *mlsl_handle,
+                         struct ext_slave_platform_data *pdata,
+                         struct mpu6050_config *config, long apply,
+                         long irq_type)
+{
+       int result;
+       unsigned char reg_int_cfg;
+
+       /* HACK, no need for interrupts for MPU6050 accel
+               - use of soft interrupt is required */
+#if 0
+       switch (irq_type) {
+       case MPU_SLAVE_IRQ_TYPE_DATA_READY:
+               config->irq_type = irq_type;
+               reg_int_cfg = BIT_RAW_RDY_EN;
+               break;
+       /* todo: add MOTION, NO_MOTION, and FREEFALL */
+       case MPU_SLAVE_IRQ_TYPE_NONE:
+               /* Do nothing, not even set the interrupt because it is
+                  shared with the gyro */
+               config->irq_type = irq_type;
+               return 0;
+       default:
+               return INV_ERROR_INVALID_PARAMETER;
+       }
+
+       if (apply) {
+               result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                                MPUREG_INT_ENABLE,
+                                                reg_int_cfg);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               MPL_LOGV("irq_type: %d\n", config->irq_type);
+       }
+#endif
+
+       return 0;
+}
+
+static int mpu6050_set_ths(void *mlsl_handle,
+                         struct ext_slave_platform_data *slave,
+                         struct mpu6050_config *config, long apply, long ths)
+{
+       if (ths < 0)
+               ths = 0;
+
+       config->ths = ths;
+       MPL_LOGV("THS: %d\n", config->ths);
+       return 0;
+}
+
+static int mpu6050_set_dur(void *mlsl_handle,
+                         struct ext_slave_platform_data *slave,
+                         struct mpu6050_config *config, long apply, long dur)
+{
+       if (dur < 0)
+               dur = 0;
+
+       config->dur = dur;
+       MPL_LOGV("DUR: %d\n", config->dur);
+       return 0;
+}
+
+
+static int mpu6050_init(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       int result;
+       struct mpu6050_private_data *private_data;
+
+
+       private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
+
+       if (!private_data)
+               return INV_ERROR_MEMORY_EXAUSTED;
+
+       pdata->private_data = private_data;
+
+       result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend,
+                                false, 0);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume,
+                                false, 200000);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->suspend,
+                                false, 2000);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume,
+                                false, 2000);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend,
+                                false, MPU_SLAVE_IRQ_TYPE_NONE);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume,
+                                false, MPU_SLAVE_IRQ_TYPE_NONE);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->suspend,
+                                false, 80);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_ths(mlsl_handle, pdata, &private_data->resume,
+                                false, 40);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->suspend,
+                                false, 1000);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_dur(mlsl_handle, pdata, &private_data->resume,
+                                false, 2540);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       return 0;
+}
+
+static int mpu6050_exit(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       kfree(pdata->private_data);
+       pdata->private_data = NULL;
+       return 0;
+}
+
+static int mpu6050_suspend(void *mlsl_handle,
+                          struct ext_slave_descr *slave,
+                          struct ext_slave_platform_data *pdata)
+{
+       unsigned char reg;
+       int result;
+       struct mpu6050_private_data *private_data =
+                       (struct mpu6050_private_data *)pdata->private_data;
+
+       result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->suspend,
+                               true, private_data->suspend.odr);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->suspend,
+                               true, private_data->suspend.irq_type);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       result = inv_serial_read(mlsl_handle, pdata->address,
+                                MPUREG_PWR_MGMT_2, 1, &reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       reg |= (BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
+
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        MPUREG_PWR_MGMT_2, reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       return 0;
+}
+
+static int mpu6050_resume(void *mlsl_handle,
+                         struct ext_slave_descr *slave,
+                         struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char reg;
+       struct mpu6050_private_data *private_data =
+               (struct mpu6050_private_data *)pdata->private_data;
+
+       result = inv_serial_read(mlsl_handle, pdata->address,
+                                MPUREG_PWR_MGMT_1, 1, &reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       if (reg & BIT_SLEEP) {
+               result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                       MPUREG_PWR_MGMT_1, reg & ~BIT_SLEEP);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+       }
+       msleep(2);
+
+       result = inv_serial_read(mlsl_handle, pdata->address,
+                       MPUREG_PWR_MGMT_2, 1, &reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       reg &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                      MPUREG_PWR_MGMT_2, reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       /* settings */
+
+       result = mpu6050_set_fsr(mlsl_handle, pdata, &private_data->resume,
+                                true, private_data->resume.fsr);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_odr(mlsl_handle, pdata, &private_data->resume,
+                                true, private_data->resume.odr);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       result = mpu6050_set_irq(mlsl_handle, pdata, &private_data->resume,
+                                true, private_data->resume.irq_type);
+
+       /* motion, no_motion */
+       /* TODO : port these in their respective _set_thrs and _set_dur
+                 functions and use the APPLY paremeter to apply just like
+                 _set_odr, _set_irq, and _set_fsr. */
+       reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_THR_LSB;
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        MPUREG_ACCEL_MOT_THR, reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       reg = (unsigned char)
+           ACCEL_ZRMOT_THR_LSB_CONVERSION(private_data->resume.ths);
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        MPUREG_ACCEL_ZRMOT_THR, reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       reg = (unsigned char)private_data->suspend.ths / ACCEL_MOT_DUR_LSB;
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        MPUREG_ACCEL_MOT_DUR, reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       reg = (unsigned char)private_data->resume.ths / ACCEL_ZRMOT_DUR_LSB;
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        MPUREG_ACCEL_ZRMOT_DUR, reg);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       return 0;
+}
+
+static int mpu6050_read(void *mlsl_handle,
+                       struct ext_slave_descr *slave,
+                       struct ext_slave_platform_data *pdata,
+                       unsigned char *data)
+{
+       int result;
+       result = inv_serial_read(mlsl_handle, pdata->address,
+                                slave->read_reg, slave->read_len, data);
+       return result;
+}
+
+static int mpu6050_config(void *mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata,
+                        struct ext_slave_config *data)
+{
+       struct mpu6050_private_data *private_data =
+               (struct mpu6050_private_data *)pdata->private_data;
+       if (!data->data)
+               return INV_ERROR_INVALID_PARAMETER;
+
+       switch (data->key) {
+       case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+               return mpu6050_set_odr(mlsl_handle, pdata,
+                                     &private_data->suspend,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_ODR_RESUME:
+               return mpu6050_set_odr(mlsl_handle, pdata,
+                                     &private_data->resume,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+               return mpu6050_set_fsr(mlsl_handle, pdata,
+                                     &private_data->suspend,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_FSR_RESUME:
+               return mpu6050_set_fsr(mlsl_handle, pdata,
+                                     &private_data->resume,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_MOT_THS:
+               return mpu6050_set_ths(mlsl_handle, pdata,
+                                     &private_data->suspend,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_NMOT_THS:
+               return mpu6050_set_ths(mlsl_handle, pdata,
+                                     &private_data->resume,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_MOT_DUR:
+               return mpu6050_set_dur(mlsl_handle, pdata,
+                                     &private_data->suspend,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_NMOT_DUR:
+               return mpu6050_set_dur(mlsl_handle, pdata,
+                                     &private_data->resume,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+               return mpu6050_set_irq(mlsl_handle, pdata,
+                                     &private_data->suspend,
+                                     data->apply, *((long *)data->data));
+               break;
+       case MPU_SLAVE_CONFIG_IRQ_RESUME:
+               return mpu6050_set_irq(mlsl_handle, pdata,
+                                     &private_data->resume,
+                                     data->apply, *((long *)data->data));
+       case MPU_SLAVE_CONFIG_INTERNAL_REFERENCE:
+               return mpu6050_set_mldl_cfg_ref(mlsl_handle, pdata,
+                                              (struct mldl_cfg *)data->data);
+               break;
+
+       default:
+               return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+       };
+
+       return 0;
+}
+
+static int mpu6050_get_config(void *mlsl_handle,
+                            struct ext_slave_descr *slave,
+                            struct ext_slave_platform_data *pdata,
+                            struct ext_slave_config *data)
+{
+       struct mpu6050_private_data *private_data =
+               (struct mpu6050_private_data *)pdata->private_data;
+       if (!data->data)
+               return INV_ERROR_INVALID_PARAMETER;
+
+       switch (data->key) {
+       case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->suspend.odr;
+               break;
+       case MPU_SLAVE_CONFIG_ODR_RESUME:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->resume.odr;
+               break;
+       case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->suspend.fsr;
+               break;
+       case MPU_SLAVE_CONFIG_FSR_RESUME:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->resume.fsr;
+               break;
+       case MPU_SLAVE_CONFIG_MOT_THS:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->suspend.ths;
+               break;
+       case MPU_SLAVE_CONFIG_NMOT_THS:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->resume.ths;
+               break;
+       case MPU_SLAVE_CONFIG_MOT_DUR:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->suspend.dur;
+               break;
+       case MPU_SLAVE_CONFIG_NMOT_DUR:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->resume.dur;
+               break;
+       case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->suspend.irq_type;
+               break;
+       case MPU_SLAVE_CONFIG_IRQ_RESUME:
+               (*(unsigned long *)data->data) =
+                   (unsigned long)private_data->resume.irq_type;
+               break;
+       default:
+               return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+       };
+
+       return 0;
+}
+
+static struct ext_slave_descr mpu6050_descr = {
+       .init             = mpu6050_init,
+       .exit             = mpu6050_exit,
+       .suspend          = mpu6050_suspend,
+       .resume           = mpu6050_resume,
+       .read             = mpu6050_read,
+       .config           = mpu6050_config,
+       .get_config       = mpu6050_get_config,
+       .name             = "mpu6050",
+       .type             = EXT_SLAVE_TYPE_ACCEL,
+       .id               = ACCEL_ID_MPU6050,
+       .read_reg         = 0x3B,
+       .read_len         = 6,
+       .endian           = EXT_SLAVE_BIG_ENDIAN,
+       .range            = {2, 0},
+       .trigger          = NULL,
+};
+
+struct ext_slave_descr *mpu6050_get_slave_descr(void)
+{
+       return &mpu6050_descr;
+}
+
+/**
+ *  @}
+ */
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 6c4c13a..2830d32
@@ -18,6 +18,15 @@ config MPU_SENSORS_AK8975
          Specifying more that one compass in the board file will result
          in runtime errors.
 
+config MPU_SENSORS_AK8963
+       tristate "AKM ak8963"
+       help
+         This enables support for the AKM ak8963 compass
+         This support is for integration with the MPU3050 or MPU6050 gyroscope
+         device driver.  Only one compass can be registered at a time.
+         Specifying more that one compass in the board file will result
+         in runtime errors.
+
 config MPU_SENSORS_AK8972
        tristate "AKM ak8972"
        help
old mode 100644 (file)
new mode 100755 (executable)
index aa8aa6a..08d3548
@@ -31,6 +31,8 @@ inv_mpu_hscdtd004a-objs +=    hscdtd004a.o
 obj-$(CONFIG_MPU_SENSORS_AK8975) += inv_mpu_ak8975.o
 inv_mpu_ak8975-objs += ak8975.o
 
+obj-$(CONFIG_MPU_SENSORS_AK8963) += inv_mpu_ak8963.o
+inv_mpu_ak8963-objs += ak8963.o
 obj-$(CONFIG_MPU_SENSORS_AK8972) += inv_mpu_ak8972.o
 inv_mpu_ak8972-objs += ak8972.o
 
diff --git a/drivers/misc/inv_mpu/compass/ak8963.c b/drivers/misc/inv_mpu/compass/ak8963.c
new file mode 100755 (executable)
index 0000000..ced3789
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+       $License:
+       Copyright (C) 2011 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/>.
+       $
+ */
+
+/**
+ *  @addtogroup COMPASSDL
+ *
+ *  @{
+ *      @file   ak8963.c
+ *      @brief  Magnetometer setup and handling methods for the AKM AK8963,
+ *              AKM AK8963B, and AKM AK8963C compass devices.
+ */
+
+/* -------------------------------------------------------------------------- */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "mpu-dev.h"
+
+#include <log.h>
+#include <linux/mpu.h>
+#include "mlsl.h"
+#include "mldl_cfg.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+#include <linux/of_gpio.h>
+#include <linux/iio/consumer.h>
+
+//#include <linux/gpio.h>
+//#include <mach/gpio.h>
+//#include <plat/gpio-cfg.h>
+
+/* -------------------------------------------------------------------------- */
+#define AK8963_REG_ST1  (0x02)
+#define AK8963_REG_HXL  (0x03)
+#define AK8963_REG_ST2  (0x09)
+
+#define AK8963_REG_CNTL (0x0A)
+#define AK8963_REG_ASAX (0x10)
+#define AK8963_REG_ASAY (0x11)
+#define AK8963_REG_ASAZ (0x12)
+
+//define output bit is 16bit
+#define AK8963_CNTL_MODE_POWER_DOWN         (0x10)
+#define AK8963_CNTL_MODE_SINGLE_MEASUREMENT (0x11)
+#define AK8963_CNTL_MODE_FUSE_ROM_ACCESS    (0x1f)
+
+/* -------------------------------------------------------------------------- */
+struct ak8963_config {
+       char asa[COMPASS_NUM_AXES];     /* axis sensitivity adjustment */
+};
+
+struct ak8963_private_data {
+       struct ak8963_config init;
+};
+
+struct ext_slave_platform_data ak8963_data;
+
+/* -------------------------------------------------------------------------- */
+static int ak8963_init(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       int result;
+       unsigned char serial_data[COMPASS_NUM_AXES];
+       printk("yemk:ak8963_init\n");
+       struct ak8963_private_data *private_data;
+       private_data = (struct ak8963_private_data *)
+           kzalloc(sizeof(struct ak8963_private_data), GFP_KERNEL);
+
+       if (!private_data)
+               return INV_ERROR_MEMORY_EXAUSTED;
+
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        AK8963_REG_CNTL,
+                                        AK8963_CNTL_MODE_POWER_DOWN);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       /* Wait at least 100us */
+       udelay(100);
+
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        AK8963_REG_CNTL,
+                                        AK8963_CNTL_MODE_FUSE_ROM_ACCESS);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       /* Wait at least 200us */
+       udelay(200);
+
+       result = inv_serial_read(mlsl_handle, pdata->address,
+                                AK8963_REG_ASAX,
+                                COMPASS_NUM_AXES, serial_data);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       pdata->private_data = private_data;
+
+       private_data->init.asa[0] = serial_data[0];
+       private_data->init.asa[1] = serial_data[1];
+       private_data->init.asa[2] = serial_data[2];
+
+       result = inv_serial_single_write(mlsl_handle, pdata->address,
+                                        AK8963_REG_CNTL,
+                                        AK8963_CNTL_MODE_POWER_DOWN);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       printk("yemk:ak8963_init end\n");
+       udelay(100);
+       printk(KERN_ERR "invensense: %s ok\n", __func__);
+       return INV_SUCCESS;
+}
+
+static int ak8963_exit(void *mlsl_handle,
+                      struct ext_slave_descr *slave,
+                      struct ext_slave_platform_data *pdata)
+{
+       kfree(pdata->private_data);
+       return INV_SUCCESS;
+}
+
+static int ak8963_suspend(void *mlsl_handle,
+                  struct ext_slave_descr *slave,
+                  struct ext_slave_platform_data *pdata)
+{
+       int result = INV_SUCCESS;
+       result =
+           inv_serial_single_write(mlsl_handle, pdata->address,
+                                   AK8963_REG_CNTL,
+                                   AK8963_CNTL_MODE_POWER_DOWN);
+       msleep(1);              /* wait at least 100us */
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       return result;
+}
+
+static int ak8963_resume(void *mlsl_handle,
+                 struct ext_slave_descr *slave,
+                 struct ext_slave_platform_data *pdata)
+{
+       int result = INV_SUCCESS;
+       result =
+           inv_serial_single_write(mlsl_handle, pdata->address,
+                                   AK8963_REG_CNTL,
+                                   AK8963_CNTL_MODE_SINGLE_MEASUREMENT);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+       return result;
+}
+
+static int ak8963_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 = INV_SUCCESS;
+       int status = INV_SUCCESS;
+
+       result =
+           inv_serial_read(mlsl_handle, pdata->address, AK8963_REG_ST1,
+                           8, regs);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
+
+       /* Always return the data and the status registers */
+       memcpy(data, &regs[1], 6);
+       data[6] = regs[0];
+       data[7] = regs[7];
+
+       /*
+        * ST : data ready -
+        * Measurement has been completed and data is ready to be read.
+        */
+       if (*stat & 0x01)
+               status = INV_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 = INV_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 = INV_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 = INV_ERROR_COMPASS_DATA_UNDERFLOW; */
+               status = INV_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 & 0x08) != 0x00 ) {
+               result = inv_serial_single_write(
+                   mlsl_handle, pdata->address,
+                   AK8963_REG_CNTL, AK8963_CNTL_MODE_SINGLE_MEASUREMENT);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+       }
+
+       return status;
+}
+
+static int ak8963_config(void *mlsl_handle,
+                        struct ext_slave_descr *slave,
+                        struct ext_slave_platform_data *pdata,
+                        struct ext_slave_config *data)
+{
+       int result;
+       if (!data->data)
+               return INV_ERROR_INVALID_PARAMETER;
+
+       switch (data->key) {
+       case MPU_SLAVE_WRITE_REGISTERS:
+               result = inv_serial_write(mlsl_handle, pdata->address,
+                                         data->len,
+                                         (unsigned char *)data->data);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               break;
+       case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+       case MPU_SLAVE_CONFIG_ODR_RESUME:
+       case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+       case MPU_SLAVE_CONFIG_FSR_RESUME:
+       case MPU_SLAVE_CONFIG_MOT_THS:
+       case MPU_SLAVE_CONFIG_NMOT_THS:
+       case MPU_SLAVE_CONFIG_MOT_DUR:
+       case MPU_SLAVE_CONFIG_NMOT_DUR:
+       case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+       case MPU_SLAVE_CONFIG_IRQ_RESUME:
+       default:
+               return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+       };
+
+       return INV_SUCCESS;
+}
+
+static int ak8963_get_config(void *mlsl_handle,
+                            struct ext_slave_descr *slave,
+                            struct ext_slave_platform_data *pdata,
+                            struct ext_slave_config *data)
+{
+       struct ak8963_private_data *private_data = pdata->private_data;
+       int result;
+       if (!data->data)
+               return INV_ERROR_INVALID_PARAMETER;
+
+       switch (data->key) {
+       case MPU_SLAVE_READ_REGISTERS:
+               {
+                       unsigned char *serial_data =
+                           (unsigned char *)data->data;
+                       result =
+                           inv_serial_read(mlsl_handle, pdata->address,
+                                           serial_data[0], data->len - 1,
+                                           &serial_data[1]);
+                       if (result) {
+                               LOG_RESULT_LOCATION(result);
+                               return result;
+                       }
+                       break;
+               }
+       case MPU_SLAVE_READ_SCALE:
+               {
+                       unsigned char *serial_data =
+                           (unsigned char *)data->data;
+                       serial_data[0] = private_data->init.asa[0];
+                       serial_data[1] = private_data->init.asa[1];
+                       serial_data[2] = private_data->init.asa[2];
+                       result = INV_SUCCESS;
+                       if (result) {
+                               LOG_RESULT_LOCATION(result);
+                               return result;
+                       }
+                       break;
+               }
+       case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+               (*(unsigned long *)data->data) = 0;
+               break;
+       case MPU_SLAVE_CONFIG_ODR_RESUME:
+               (*(unsigned long *)data->data) = 8000;
+               break;
+       case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+       case MPU_SLAVE_CONFIG_FSR_RESUME:
+       case MPU_SLAVE_CONFIG_MOT_THS:
+       case MPU_SLAVE_CONFIG_NMOT_THS:
+       case MPU_SLAVE_CONFIG_MOT_DUR:
+       case MPU_SLAVE_CONFIG_NMOT_DUR:
+       case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+       case MPU_SLAVE_CONFIG_IRQ_RESUME:
+       default:
+               return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
+       };
+
+       return INV_SUCCESS;
+}
+
+static struct ext_slave_read_trigger ak8963_read_trigger = {
+       /*.reg              = */ 0x0A,
+       /*.value            = */ 0x11
+};
+
+static struct ext_slave_descr ak8963_descr = {
+       .init             = ak8963_init,
+       .exit             = ak8963_exit,
+       .suspend          = ak8963_suspend,
+       .resume           = ak8963_resume,
+       .read             = ak8963_read,
+       .config           = ak8963_config,
+       .get_config       = ak8963_get_config,
+       .name             = "ak8963",
+       .type             = EXT_SLAVE_TYPE_COMPASS,
+       .id               = COMPASS_ID_AK8963,
+       .read_reg         = 0x01,
+       .read_len         = 10,
+       .endian           = EXT_SLAVE_LITTLE_ENDIAN,
+       .range            = {9830, 4000},
+       .trigger          = &ak8963_read_trigger,
+};
+
+static
+struct ext_slave_descr *ak8963_get_slave_descr(void)
+{
+       return &ak8963_descr;
+}
+
+/* -------------------------------------------------------------------------- */
+struct ak8963_mod_private_data {
+       struct i2c_client *client;
+       struct ext_slave_platform_data *pdata;
+};
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+static int ak8963_parse_dt(struct i2c_client *client,
+                                 struct ext_slave_platform_data *data)
+{
+       int ret;
+       struct device_node *np = client->dev.of_node;
+       //enum of_gpio_flags gpioflags;
+       int length = 0,size = 0;
+       struct property *prop;
+       int debug = 1;
+       int i;
+       int orig_x,orig_y,orig_z;
+       u32 orientation[9];
+
+       ret = of_property_read_u32(np,"compass-bus",&data->bus);
+       if(ret!=0){
+               dev_err(&client->dev, "get compass-bus error\n");
+               return -EIO;
+               }
+
+       ret = of_property_read_u32(np,"compass-adapt_num",&data->adapt_num);
+       if(ret!=0){
+               dev_err(&client->dev, "get compass-adapt_num error\n");
+               return -EIO;
+               }
+
+       prop = of_find_property(np, "compass-orientation", &length);
+       if (!prop){
+               dev_err(&client->dev, "get compass-orientation length error\n");
+               return -EINVAL;
+       }
+
+       size = length / sizeof(int);
+
+       if((size > 0)&&(size <10)){
+               ret = of_property_read_u32_array(np, "compass-orientation",
+                                        orientation,
+                                        size);
+               if(ret<0){
+                       dev_err(&client->dev, "get compass-orientation data error\n");
+                       return -EINVAL;
+               }
+       }
+       else{
+               printk(" use default orientation\n");
+       }
+
+       for(i=0;i<9;i++)
+               data->orientation[i]= orientation[i];
+
+
+       ret = of_property_read_u32(np,"orientation-x",&orig_x);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-x error\n");
+               return -EIO;
+       }
+
+       if(orig_x>0){
+               for(i=0;i<3;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+
+       ret = of_property_read_u32(np,"orientation-y",&orig_y);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-y error\n");
+               return -EIO;
+       }
+
+       if(orig_y>0){
+               for(i=3;i<6;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+
+       ret = of_property_read_u32(np,"orientation-z",&orig_z);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-z error\n");
+               return -EIO;
+       }
+
+       if(orig_z>0){
+               for(i=6;i<9;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+       
+
+       ret = of_property_read_u32(np,"compass-debug",&debug);
+       if(ret!=0){
+               dev_err(&client->dev, "get compass-debug error\n");
+               return -EINVAL;
+       }
+
+       if(client->addr)
+               data->address=client->addr;
+       else
+               dev_err(&client->dev, "compass-addr error\n");
+
+       if(debug){
+               printk("bus=%d,adapt_num=%d,addr=%x\n",data->bus, \
+                       data->adapt_num,data->address);
+
+               for(i=0;i<size;i++)
+                       printk("%d ",data->orientation[i]);     
+               
+               printk("\n");   
+
+       }
+       return 0;
+}
+static int ak8963_mod_probe(struct i2c_client *client,
+                          const struct i2c_device_id *devid)
+{
+       int ret=0;
+       struct ext_slave_platform_data *pdata;
+       struct ak8963_mod_private_data *private_data;
+       int result = 0;
+
+       ret = ak8963_parse_dt(client,&ak8963_data);
+       if(ret< 0)
+               printk("parse ak8963 dts failed\n");
+
+       dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
+       printk("yemk:ak8963_mod_probe\n");
+       //request gpio for COMPASS_RST
+#if 0
+       if (gpio_request(COMPASS_RST_PIN, "COMPASS_RST")) {
+               pr_err("%s: failed to request gpio for COMPASS_RST\n", __func__);
+               //return -ENODEV;
+       }
+       gpio_direction_output(COMPASS_RST_PIN, 1);
+#else
+       //if (gpio_request_one(COMPASS_RST_PIN, GPIOF_OUT_INIT_HIGH, "COMPASS_RST")) {
+       //      pr_err("%s: failed to request gpio for COMPASS_RST\n", __func__);
+               //return -ENODEV;
+       //}
+#endif
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               result = -ENODEV;
+               goto out_no_free;
+       }
+
+       pdata = &ak8963_data;
+       if (!pdata) {
+               dev_err(&client->adapter->dev,
+                       "Missing platform data for slave %s\n", devid->name);
+               result = -EFAULT;
+               goto out_no_free;
+       }
+
+       private_data = kzalloc(sizeof(*private_data), GFP_KERNEL);
+       if (!private_data) {
+               result = -ENOMEM;
+               goto out_no_free;
+       }
+
+       i2c_set_clientdata(client, private_data);
+       private_data->client = client;
+       private_data->pdata = pdata;
+
+       result = inv_mpu_register_slave(THIS_MODULE, client, pdata,
+                                       ak8963_get_slave_descr);
+       printk(KERN_ERR "invensense: in %s, result is %d\n", __func__, result);
+       if (result) {
+               dev_err(&client->adapter->dev,
+                       "Slave registration failed: %s, %d\n",
+                       devid->name, result);
+               goto out_free_memory;
+       }
+       printk("yemk:ak8963_mod_probe end\n");
+       return result;
+
+out_free_memory:
+       kfree(private_data);
+out_no_free:
+       dev_err(&client->adapter->dev, "%s failed %d\n", __func__, result);
+       return result;
+
+}
+
+static int ak8963_mod_remove(struct i2c_client *client)
+{
+       struct ak8963_mod_private_data *private_data =
+               i2c_get_clientdata(client);
+
+       dev_dbg(&client->adapter->dev, "%s\n", __func__);
+       inv_mpu_unregister_slave(client, private_data->pdata,
+                               ak8963_get_slave_descr);
+
+       kfree(private_data);
+       return 0;
+}
+
+static const struct i2c_device_id ak8963_mod_id[] = {
+       { "ak8963", COMPASS_ID_AK8963 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ak8963_mod_id);
+
+static const struct of_device_id of_mpu_ak8963_match[] = {
+       { .compatible = "ak8963" },
+       { /* Sentinel */ }
+};
+
+static struct i2c_driver ak8963_mod_driver = {
+       .class = I2C_CLASS_HWMON,
+       .probe = ak8963_mod_probe,
+       .remove = ak8963_mod_remove,
+       .id_table = ak8963_mod_id,
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = "ak8963_mod",
+                  .of_match_table      = of_mpu_ak8963_match,
+                  },
+       .address_list = normal_i2c,
+};
+
+static int __init ak8963_mod_init(void)
+{
+       int res = i2c_add_driver(&ak8963_mod_driver);
+       pr_info("%s: Probe name %s\n", __func__, "ak8963_mod");
+       if (res)
+               pr_err("%s failed\n", __func__);
+       return res;
+}
+
+static void __exit ak8963_mod_exit(void)
+{
+       pr_info("%s\n", __func__);
+       i2c_del_driver(&ak8963_mod_driver);
+}
+
+module_init(ak8963_mod_init);
+module_exit(ak8963_mod_exit);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("Driver to integrate AK8963 sensor with the MPU");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ak8963_mod");
+
+/**
+ *  @}
+ */
old mode 100644 (file)
new mode 100755 (executable)
index 9a67d7c1e397f813c5be79f6308dff708cdc9585..e6f5b4a344dad4b19852217855394931cb4b6190 100755 (executable)
@@ -27,7 +27,6 @@
  */
 
 /* -------------------------------------------------------------------------- */
-#define DEBUG
 
 #include <linux/i2c.h>
 #include <linux/module.h>
@@ -68,6 +67,8 @@ struct ak8975_private_data {
        struct ak8975_config init;
 };
 
+struct ext_slave_platform_data ak8975_data;
+
 /* -------------------------------------------------------------------------- */
 static int ak8975_init(void *mlsl_handle,
                       struct ext_slave_descr *slave,
@@ -82,7 +83,7 @@ static int ak8975_init(void *mlsl_handle,
 
        if (!private_data)
                return INV_ERROR_MEMORY_EXAUSTED;
-#if 0
+
        result = inv_serial_single_write(mlsl_handle, pdata->address,
                                         AK8975_REG_CNTL,
                                         AK8975_CNTL_MODE_POWER_DOWN);
@@ -100,7 +101,7 @@ static int ak8975_init(void *mlsl_handle,
                LOG_RESULT_LOCATION(result);
                return result;
        }
-#endif
+
        /* Wait at least 200us */
        udelay(200);
 
@@ -117,7 +118,7 @@ static int ak8975_init(void *mlsl_handle,
        private_data->init.asa[0] = serial_data[0];
        private_data->init.asa[1] = serial_data[1];
        private_data->init.asa[2] = serial_data[2];
-#if 0
+
        result = inv_serial_single_write(mlsl_handle, pdata->address,
                                         AK8975_REG_CNTL,
                                         AK8975_CNTL_MODE_POWER_DOWN);
@@ -125,7 +126,7 @@ static int ak8975_init(void *mlsl_handle,
                LOG_RESULT_LOCATION(result);
                return result;
        }
-#endif
+
        udelay(100);
        return INV_SUCCESS;
 }
@@ -390,21 +391,139 @@ struct ak8975_mod_private_data {
 
 static unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
+static int ak8975_parse_dt(struct i2c_client *client,
+                                 struct ext_slave_platform_data *data)
+{
+       int ret;
+       struct device_node *np = client->dev.of_node;
+       //enum of_gpio_flags gpioflags;
+       int length = 0,size = 0;
+       struct property *prop;
+       int debug = 1;
+       int i;
+       int orig_x,orig_y,orig_z;
+       u32 orientation[9];
+
+       ret = of_property_read_u32(np,"compass-bus",&data->bus);
+       if(ret!=0){
+               dev_err(&client->dev, "get compass-bus error\n");
+               return -EIO;
+               }
+
+       ret = of_property_read_u32(np,"compass-adapt_num",&data->adapt_num);
+       if(ret!=0){
+               dev_err(&client->dev, "get compass-adapt_num error\n");
+               return -EIO;
+               }
+
+       prop = of_find_property(np, "compass-orientation", &length);
+       if (!prop){
+               dev_err(&client->dev, "get compass-orientation length error\n");
+               return -EINVAL;
+       }
+
+       size = length / sizeof(int);
+
+       if((size > 0)&&(size <10)){
+               ret = of_property_read_u32_array(np, "compass-orientation",
+                                        orientation,
+                                        size);
+               if(ret<0){
+                       dev_err(&client->dev, "get compass-orientation data error\n");
+                       return -EINVAL;
+               }
+       }
+       else{
+               printk(" use default orientation\n");
+       }
+
+       for(i=0;i<9;i++)
+               data->orientation[i]= orientation[i];
+
+
+       ret = of_property_read_u32(np,"orientation-x",&orig_x);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-x error\n");
+               return -EIO;
+       }
+
+       if(orig_x>0){
+               for(i=0;i<3;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+
+       ret = of_property_read_u32(np,"orientation-y",&orig_y);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-y error\n");
+               return -EIO;
+       }
+
+       if(orig_y>0){
+               for(i=3;i<6;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+
+       ret = of_property_read_u32(np,"orientation-z",&orig_z);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-z error\n");
+               return -EIO;
+       }
+
+       if(orig_z>0){
+               for(i=6;i<9;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+       
+
+       ret = of_property_read_u32(np,"compass-debug",&debug);
+       if(ret!=0){
+               dev_err(&client->dev, "get compass-debug error\n");
+               return -EINVAL;
+       }
+
+       if(client->addr)
+               data->address=client->addr;
+       else
+               dev_err(&client->dev, "compass-addr error\n");
+
+       if(debug){
+               printk("bus=%d,adapt_num=%d,addr=%x\n",data->bus, \
+                       data->adapt_num,data->address);
+
+               for(i=0;i<size;i++)
+                       printk("%d ",data->orientation[i]);     
+               
+               printk("\n");   
+
+       }
+       return 0;
+}
+
 static int ak8975_mod_probe(struct i2c_client *client,
                           const struct i2c_device_id *devid)
 {
        struct ext_slave_platform_data *pdata;
        struct ak8975_mod_private_data *private_data;
        int result = 0;
+       int ret;
 
-       dev_info(&client->adapter->dev, "%s: %s,0x%x\n", __func__, devid->name,(unsigned int)client);
+       
+       ret = ak8975_parse_dt(client,&ak8975_data);
+       if(ret< 0)
+               printk("parse ak8975 dts failed\n");
+       dev_info(&client->adapter->dev, "%s: %s\n", __func__, devid->name);
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
                result = -ENODEV;
                goto out_no_free;
        }
 
-       pdata = client->dev.platform_data;
+       pdata = &ak8975_data;;
        if (!pdata) {
                dev_err(&client->adapter->dev,
                        "Missing platform data for slave %s\n", devid->name);
@@ -461,6 +580,11 @@ static const struct i2c_device_id ak8975_mod_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, ak8975_mod_id);
 
+static const struct of_device_id of_mpu_ak8975_match[] = {
+       { .compatible = "ak8975" },
+       { /* Sentinel */ }
+};
+
 static struct i2c_driver ak8975_mod_driver = {
        .class = I2C_CLASS_HWMON,
        .probe = ak8975_mod_probe,
@@ -469,6 +593,7 @@ static struct i2c_driver ak8975_mod_driver = {
        .driver = {
                   .owner = THIS_MODULE,
                   .name = "ak8975_mod",
+                  .of_match_table      = of_mpu_ak8975_match,     
                   },
        .address_list = normal_i2c,
 };
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 155f4a980b2545c22bd1120f48b0b5f74e9341ff..e49305cb058660ea0309eab9af5a00f97de370af 100755 (executable)
@@ -33,7 +33,7 @@
 
 #include "mldl_cfg.h"
 #include <linux/mpu.h>
-#include "mpu3050.h"
+#include "mpu6050b1.h"
 
 #include "mlsl.h"
 #include "mldl_print_cfg.h"
@@ -43,8 +43,8 @@
 
 /* -------------------------------------------------------------------------- */
 
-#define SLEEP   1
-#define WAKE_UP 0
+#define SLEEP   0
+#define WAKE_UP 7
 #define RESET   1
 #define STANDBY 1
 
@@ -154,98 +154,84 @@ static int dmp_start(struct mldl_cfg *mldl_cfg, void *mlsl_handle)
        return result;
 }
 
-
-
-static int mpu3050_set_i2c_bypass(struct mldl_cfg *mldl_cfg,
-                                 void *mlsl_handle, unsigned char enable)
+/**
+ *  @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 INV_SUCCESS if successful, a non-zero error code otherwise.
+ */
+static int mpu6050b1_set_i2c_bypass(struct mldl_cfg *mldl_cfg,
+                                   void *mlsl_handle, unsigned char enable)
 {
-       unsigned char b;
+       unsigned char reg;
        int result;
        unsigned char status = mldl_cfg->inv_mpu_state->status;
-
        if ((status & MPU_GYRO_IS_BYPASSED && enable) ||
            (!(status & MPU_GYRO_IS_BYPASSED) && !enable))
                return INV_SUCCESS;
 
        /*---- get current 'USER_CTRL' into b ----*/
-       result = inv_serial_read(
-               mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_USER_CTRL, 1, &b);
+       result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+                                MPUREG_USER_CTRL, 1, &reg);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
 
-       b &= ~BIT_AUX_IF_EN;
-
        if (!enable) {
+               /* setting int_config with the property flag BIT_BYPASS_EN
+                  should be done by the setup functions */
                result = inv_serial_single_write(
                        mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_USER_CTRL,
-                       (b | BIT_AUX_IF_EN));
-               if (result) {
-                       LOG_RESULT_LOCATION(result);
-                       return 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 = inv_serial_single_write(
-                       mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_AUX_SLV_ADDR, 0x7F);
-               if (result) {
-                       LOG_RESULT_LOCATION(result);
-                       return result;
-               }
-               /*
-                * 2) wait enough time for a nack to occur, then go into
-                *    bypass mode:
-                */
-               msleep(2);
-               result = inv_serial_single_write(
-                       mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_USER_CTRL, (b));
-               if (result) {
-                       LOG_RESULT_LOCATION(result);
-                       return result;
+                       MPUREG_INT_PIN_CFG,
+                       (mldl_cfg->pdata->int_config & ~(BIT_BYPASS_EN)));
+               if (!(reg & BIT_I2C_MST_EN)) {
+                       result =
+                           inv_serial_single_write(
+                                   mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+                                   MPUREG_USER_CTRL,
+                                   (reg | BIT_I2C_MST_EN));
+                       if (result) {
+                               LOG_RESULT_LOCATION(result);
+                               return result;
+                       }
                }
-               /*
-                * 3) wait for up to one MPU cycle then restore the slave
-                *    address
-                */
-               msleep(inv_mpu_get_sampling_period_us(mldl_cfg->mpu_gyro_cfg)
-                       / 1000);
-               result = inv_serial_single_write(
-                       mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_AUX_SLV_ADDR,
-                       mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL]
-                               ->address);
-               if (result) {
-                       LOG_RESULT_LOCATION(result);
-                       return result;
+       } else if (enable) {
+               if (reg & BIT_AUX_IF_EN) {
+                       result =
+                           inv_serial_single_write(
+                                   mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+                                   MPUREG_USER_CTRL,
+                                   (reg & (~BIT_I2C_MST_EN)));
+                       if (result) {
+                               LOG_RESULT_LOCATION(result);
+                               return result;
+                       }
+                       /*****************************************
+                        * To avoid hanging the bus we must sleep until all
+                        * slave transactions have been completed.
+                        *  24 bytes max slave reads
+                        *  +1 byte possible extra write
+                        *  +4 max slave address
+                        * ---
+                        *  33 Maximum bytes
+                        *  x9 Approximate bits per byte
+                        * ---
+                        * 297 bits.
+                        * 2.97 ms minimum @ 100kbps
+                        * 0.75 ms minimum @ 400kbps.
+                        *****************************************/
+                       msleep(3);
                }
-
-               /*
-                * 4) reset the ime interface
-                */
-
                result = inv_serial_single_write(
                        mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_USER_CTRL,
-                       (b | BIT_AUX_IF_RST));
+                       MPUREG_INT_PIN_CFG,
+                       (mldl_cfg->pdata->int_config | BIT_BYPASS_EN));
                if (result) {
                        LOG_RESULT_LOCATION(result);
                        return result;
                }
-               msleep(2);
        }
        if (enable)
                mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED;
@@ -256,6 +242,8 @@ static int mpu3050_set_i2c_bypass(struct mldl_cfg *mldl_cfg,
 }
 
 
+
+
 /**
  *  @brief  enables/disables the I2C bypass to an external device
  *          connected to MPU's secondary I2C bus.
@@ -266,7 +254,7 @@ static int mpu3050_set_i2c_bypass(struct mldl_cfg *mldl_cfg,
 static int mpu_set_i2c_bypass(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
                              unsigned char enable)
 {
-       return mpu3050_set_i2c_bypass(mldl_cfg, mlsl_handle, enable);
+       return mpu6050b1_set_i2c_bypass(mldl_cfg, mlsl_handle, enable);
 }
 
 
@@ -275,54 +263,117 @@ static int mpu_set_i2c_bypass(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
 /* NOTE : when not indicated, product revision
          is considered an 'npp'; non production part */
 
+/* produces an unique identifier for each device based on the
+   combination of product version and product revision */
 struct prod_rev_map_t {
+       unsigned short mpl_product_key;
        unsigned char silicon_rev;
        unsigned short gyro_trim;
+       unsigned short accel_trim;
 };
 
-#define OLDEST_PROD_REV_SUPPORTED      11
+/* NOTE: product entries are in chronological order */
 static struct prod_rev_map_t prod_rev_map[] = {
-       {0, 0},
-       {MPU_SILICON_REV_A4, 131},      /* 1  A? OBSOLETED */
-       {MPU_SILICON_REV_A4, 131},      /* 2  |  */
-       {MPU_SILICON_REV_A4, 131},      /* 3  |  */
-       {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 V  */
-       {MPU_SILICON_REV_B1, 131},      /* 11 B1 */
-       {MPU_SILICON_REV_B1, 131},      /* 12 |  */
-       {MPU_SILICON_REV_B1, 131},      /* 13 |  */
-       {MPU_SILICON_REV_B1, 131},      /* 14 V  */
-       {MPU_SILICON_REV_B4, 131},      /* 15 B4 */
-       {MPU_SILICON_REV_B4, 131},      /* 16 |  */
-       {MPU_SILICON_REV_B4, 131},      /* 17 |  */
-       {MPU_SILICON_REV_B4, 131},      /* 18 |  */
-       {MPU_SILICON_REV_B4, 115},      /* 19 |  */
-       {MPU_SILICON_REV_B4, 115},      /* 20 V  */
-       {MPU_SILICON_REV_B6, 131},      /* 21 B6 (B6/A9)  */
-       {MPU_SILICON_REV_B4, 115},      /* 22 B4 (B7/A10) */
-       {MPU_SILICON_REV_B6, 131},      /* 23 B6 (npp)    */
-       {MPU_SILICON_REV_B6, 131},      /* 24 |  (npp)    */
-       {MPU_SILICON_REV_B6, 131},      /* 25 V  (npp)    */    
-       {MPU_SILICON_REV_B6, 131},      /* 26    (B6/A11) */    
-       {MPU_SILICON_REV_B6, 131},      /* 27    (B6/A11) */
-       {MPU_SILICON_REV_B6, 131},      /* 28    (B6/A11) */
-       {MPU_SILICON_REV_B6, 131},      /* 29    (B6/A11) */
-       {MPU_SILICON_REV_B6, 131},      /* 30    (B6/A11) */
-       {MPU_SILICON_REV_B6, 131},      /* 31    (B6/A11) */
-       {MPU_SILICON_REV_B6, 131},      /* 32    (B6/A11) */
+       /* prod_ver = 0 */
+       {MPL_PROD_KEY(0,   1), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   2), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   3), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   4), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   5), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   6), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/C2-1) */
+       /* prod_ver = 1, forced to 0 for MPU6050 A2 */
+       {MPL_PROD_KEY(0,   7), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   8), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,   9), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,  10), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,  11), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/D2-1) */
+       {MPL_PROD_KEY(0,  12), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,  13), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,  14), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,  15), MPU_SILICON_REV_A2, 131, 16384},
+       {MPL_PROD_KEY(0,  27), MPU_SILICON_REV_A2, 131, 16384}, /* (A2/D4)       */
+       /* prod_ver = 1 */
+       {MPL_PROD_KEY(1,  16), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-1) */
+       {MPL_PROD_KEY(1,  17), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-2) */
+       {MPL_PROD_KEY(1,  18), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-3) */
+       {MPL_PROD_KEY(1,  19), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-4) */
+       {MPL_PROD_KEY(1,  20), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D2-5) */
+       {MPL_PROD_KEY(1,  28), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/D4)       */
+       {MPL_PROD_KEY(1,   1), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-1) */
+       {MPL_PROD_KEY(1,   2), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-2) */
+       {MPL_PROD_KEY(1,   3), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-3) */
+       {MPL_PROD_KEY(1,   4), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-4) */
+       {MPL_PROD_KEY(1,   5), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-5) */
+       {MPL_PROD_KEY(1,   6), MPU_SILICON_REV_B1, 131, 16384}, /* (B1/E1-6) */
+       /* prod_ver = 2 */
+       {MPL_PROD_KEY(2,   7), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-1) */
+       {MPL_PROD_KEY(2,   8), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-2) */
+       {MPL_PROD_KEY(2,   9), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-3) */
+       {MPL_PROD_KEY(2,  10), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-4) */
+       {MPL_PROD_KEY(2,  11), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-5) */
+       {MPL_PROD_KEY(2,  12), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E1-6) */
+       {MPL_PROD_KEY(2,  29), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/D4)       */
+       /* prod_ver = 3 */
+       {MPL_PROD_KEY(3,  30), MPU_SILICON_REV_B1, 131, 16384}, /* (B2/E2)       */
+       /* prod_ver = 4 */
+       {MPL_PROD_KEY(4,  31), MPU_SILICON_REV_B1, 131,  8192}, /* (B2/F1)       */
+       {MPL_PROD_KEY(4,   1), MPU_SILICON_REV_B1, 131,  8192}, /* (B3/F1)       */
+       {MPL_PROD_KEY(4,   3), MPU_SILICON_REV_B1, 131,  8192}, /* (B4/F1)       */
+       /* prod_ver = 5 */
+       {MPL_PROD_KEY(5,   3), MPU_SILICON_REV_B1, 131, 16384}, /* (B4/F1)       */
+       /* prod_ver = 6 */
+       {MPL_PROD_KEY(6,  19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2)       */
+       /* prod_ver = 7 */
+       {MPL_PROD_KEY(7,  19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2)       */
+       /* prod_ver = 8 */
+       {MPL_PROD_KEY(8,  19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2)       */
+       /* prod_ver = 9 */
+       {MPL_PROD_KEY(9,  19), MPU_SILICON_REV_B1, 131, 16384}, /* (B5/E2)       */
+       /* prod_ver = 10 */
+       {MPL_PROD_KEY(10, 19), MPU_SILICON_REV_B1, 131, 16384}  /* (B5/E2)       */
+
 };
 
+/*
+   List of product software revisions
+
+   NOTE :
+   software revision 0 falls back to the old detection method
+   based off the product version and product revision per the
+   table above
+*/
+static struct prod_rev_map_t sw_rev_map[] = {
+       {0,                  0,   0,     0},
+       {1, MPU_SILICON_REV_B1, 131,  8192},    /* rev C */
+       {2, MPU_SILICON_REV_B1, 131, 16384}     /* rev D */
+ };
+
 /**
  *  @internal
- *  @brief  Get the silicon revision ID from OTP for MPU3050.
- *          The silicon revision number is in read from OTP bank 0,
- *          ADDR6[7:2].  The corresponding ID is retrieved by lookup
- *          in a map.
+ *  @brief  Inverse lookup of the index of an MPL product key .
+ *  @param  key
+ *              the MPL product indentifier also referred to as 'key'.
+ *  @return the index position of the key in the array, -1 if not found.
+ */
+short index_of_key(unsigned short key)
+{
+       int i;
+       for (i = 0; i < NUM_OF_PROD_REVS; i++)
+               if (prod_rev_map[i].mpl_product_key == key)
+                       return (short)i;
+       return -1;
+}
+
+/**
+ *  @internal
+ *  @brief  Get the product revision and version for MPU6050 and
+ *          extract all per-part specific information.
+ *          The product version number is read from the PRODUCT_ID register in
+ *          user space register map.
+ *          The product revision number is in read from OTP bank 0, ADDR6[7:2].
+ *          These 2 numbers, combined, provide an unique key to be used to
+ *          retrieve some per-device information such as the silicon revision
+ *          and the gyro and accel sensitivity trim values.
  *
  *  @param  mldl_cfg
  *              a pointer to the mldl config data structure.
@@ -332,32 +383,39 @@ static struct prod_rev_map_t prod_rev_map[] = {
  *
  *  @return 0 on success, a non-zero error code otherwise.
  */
-static int inv_get_silicon_rev_mpu3050(
+static int inv_get_silicon_rev_mpu6050(
                struct mldl_cfg *mldl_cfg, void *mlsl_handle)
 {
-       int result;
-       unsigned char index = 0x00;
+       unsigned char prod_ver, prod_rev;
+       struct prod_rev_map_t *p_rev;
+       unsigned sw_rev;
+       unsigned short key;
        unsigned char bank =
            (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0);
        unsigned short mem_addr = ((bank << 8) | 0x06);
+       short index;
+       unsigned char regs[5];
+       int result;
        struct mpu_chip_info *mpu_chip_info = mldl_cfg->mpu_chip_info;
 
+       /* get the product version */
        result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                                MPUREG_PRODUCT_ID, 1,
-                                &mpu_chip_info->product_id);
+                                MPUREG_PRODUCT_ID, 1, &prod_ver);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
+       prod_ver &= 0xF;
 
-       result = inv_serial_read_mem(
-               mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-               mem_addr, 1, &index);
+       /* get the product revision */
+       result = inv_serial_read_mem(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+                                    mem_addr, 1, &prod_rev);
+       MPL_LOGE("prod_ver %d ,  prod_rev   %d\n", prod_ver, prod_rev);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
-       index >>= 2;
+       prod_rev >>= 2;
 
        /* clean the prefetch and cfg user bank bits */
        result = inv_serial_single_write(
@@ -368,26 +426,58 @@ static int inv_get_silicon_rev_mpu3050(
                return result;
        }
 
-       if (OLDEST_PROD_REV_SUPPORTED <= index && NUM_OF_PROD_REVS >= index) {
-               mpu_chip_info->silicon_revision = prod_rev_map[index].silicon_rev;
-               mpu_chip_info->gyro_sens_trim = prod_rev_map[index].gyro_trim;
-       }
-       else
-       {
-               mpu_chip_info->silicon_revision = MPU_SILICON_REV_B6;
-               mpu_chip_info->gyro_sens_trim = 131;
+       /* get the software-product version */
+       result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+                                MPUREG_XA_OFFS_L, 5, regs);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
        }
+       sw_rev = (regs[4] & 0x01) << 2 |        /* 0x0b, bit 0 */
+                (regs[2] & 0x01) << 1 |        /* 0x09, bit 0 */
+                (regs[0] & 0x01);              /* 0x07, bit 0 */
+
+       /* if 0, use the product key to determine the type of part */
+       if (sw_rev == 0) {
+               key = MPL_PROD_KEY(prod_ver, prod_rev);
+               if (key == 0) {
+                       MPL_LOGE("Product id read as 0 "
+                                "indicates device is either "
+                                "incompatible or an MPU3050\n");
+                       return INV_ERROR_INVALID_MODULE;
+               }
+               index = index_of_key(key);
+               if (index == -1 || index >= NUM_OF_PROD_REVS) {
+                       MPL_LOGE("Unsupported product key %d in MPL\n", key);
+                       return INV_ERROR_INVALID_MODULE;
+               }
+               /* check MPL is compiled for this device */
+               if (prod_rev_map[index].silicon_rev != MPU_SILICON_REV_B1) {
+                       MPL_LOGE("MPL compiled for MPU6050B1 support "
+                                "but device is not MPU6050B1 (%d)\n", key);
+                       return INV_ERROR_INVALID_MODULE;
+               }
+               p_rev = &prod_rev_map[index];
+
+       /* if valid, use the software product key */
+       } else if (sw_rev < ARRAY_SIZE(sw_rev_map)) {
+               p_rev = &sw_rev_map[sw_rev];
 
-       mpu_chip_info->product_revision = index;
-       if (mpu_chip_info->gyro_sens_trim == 0) {
-               MPL_LOGE("gyro sensitivity trim is 0"
-                        " - unsupported non production part.\n");
+       } else {
+               MPL_LOGE("Software revision key is outside of known "
+                        "range [0..%d] : %d\n", ARRAY_SIZE(sw_rev_map));
                return INV_ERROR_INVALID_MODULE;
        }
 
+       mpu_chip_info->product_id = prod_ver;
+       mpu_chip_info->product_revision = prod_rev;
+       mpu_chip_info->silicon_revision = p_rev->silicon_rev;
+       mpu_chip_info->gyro_sens_trim = p_rev->gyro_trim;
+       mpu_chip_info->accel_sens_trim = p_rev->accel_trim;
+
        return result;
 }
-#define inv_get_silicon_rev inv_get_silicon_rev_mpu3050
+#define inv_get_silicon_rev inv_get_silicon_rev_mpu6050
 
 
 /**
@@ -419,237 +509,116 @@ static int inv_mpu_set_level_shifter_bit(struct mldl_cfg *mldl_cfg,
        int result;
        unsigned char regval;
 
-       unsigned char reg;
-       unsigned char mask;
-
-       if (0 == mldl_cfg->mpu_chip_info->silicon_revision)
-               return INV_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 ((mldl_cfg->mpu_chip_info->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 = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                                reg, 1, &regval);
+                                MPUREG_YG_OFFS_TC, 1, &regval);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
-
        if (enable)
-               regval |= mask;
-       else
-               regval &= ~mask;
+               regval |= BIT_I2C_MST_VDDIO;
 
        result = inv_serial_single_write(
-               mlsl_handle, mldl_cfg->mpu_chip_info->addr, reg, regval);
+               mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+               MPUREG_YG_OFFS_TC, regval);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
-       return result;
        return INV_SUCCESS;
 }
 
 
 /**
  * @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.
+ * @brief MPU6050 B1 power management functions.
+ * @param mldl_cfg
+ *          a pointer to the internal mldl_cfg data structure.
+ * @param mlsl_handle
+ *          a file handle to the serial device used to communicate
+ *          with the MPU6050 B1 device.
+ * @param reset
+ *          1 to reset hardware.
+ * @param sensors
+ *          Bitfield of sensors to leave on
  *
- *          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  INV_SUCCESS if successfull; a non-zero error code otherwise.
+ * @return 0 on success, a non-zero error code on error.
  */
-static int mpu3050_pwr_mgmt(struct mldl_cfg *mldl_cfg,
-                           void *mlsl_handle,
-                           unsigned char reset,
-                           unsigned char sleep,
-                           unsigned char disable_gx,
-                           unsigned char disable_gy,
-                           unsigned char disable_gz)
+static int mpu60xx_pwr_mgmt(struct mldl_cfg *mldl_cfg,
+                                   void *mlsl_handle,
+                                   unsigned int reset, unsigned long sensors)
 {
-       unsigned char b;
+       unsigned char pwr_mgmt[2];
+       unsigned char pwr_mgmt_prev[2];
        int result;
+       int sleep = !(sensors & (INV_THREE_AXIS_GYRO | INV_THREE_AXIS_ACCEL
+                               | INV_DMP_PROCESSOR));
 
-       result =
-           inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                           MPUREG_PWR_MGM, 1, &b);
-       if (result) {
-               LOG_RESULT_LOCATION(result);
-               return result;
-       }
-
-       /* If we are awake, we need to put it in bypass before resetting */
-       if ((!(b & BIT_SLEEP)) && reset)
-               result = mpu_set_i2c_bypass(mldl_cfg, mlsl_handle, 1);
-
-       /* Reset if requested */
        if (reset) {
-               MPL_LOGV("Reset MPU3050\n");
+               MPL_LOGI("Reset MPU6050 B1\n");
                result = inv_serial_single_write(
                        mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_PWR_MGM, b | BIT_H_RESET);
-               if (result) {
-                       LOG_RESULT_LOCATION(result);
-                       return result;
-               }
-               msleep(5);
-               /* Some chips are awake after reset and some are asleep,
-                * check the status */
-               result = inv_serial_read(
-                       mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_PWR_MGM, 1, &b);
+                       MPUREG_PWR_MGMT_1, BIT_H_RESET);
                if (result) {
                        LOG_RESULT_LOCATION(result);
                        return result;
                }
+               mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED;
+               msleep(15);
        }
 
-       /* Update the suspended state just in case we return early */
-       if (b & BIT_SLEEP) {
-               mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_SUSPENDED;
-               mldl_cfg->inv_mpu_state->status |= MPU_DEVICE_IS_SUSPENDED;
-       } else {
-               mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_SUSPENDED;
-               mldl_cfg->inv_mpu_state->status &= ~MPU_DEVICE_IS_SUSPENDED;
-       }
-
-       /* 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 INV_SUCCESS;
+       /* NOTE : reading both PWR_MGMT_1 and PWR_MGMT_2 for efficiency because
+                 they are accessible even when the device is powered off */
+       result = inv_serial_read(mlsl_handle, mldl_cfg->mpu_chip_info->addr,
+                                MPUREG_PWR_MGMT_1, 2, pwr_mgmt_prev);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
        }
 
-       /*
-        * 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 = mpu3050_pwr_mgmt(mldl_cfg, mlsl_handle, 0, 1, 0, 0, 0);
-               if (result)
-                       return result;
-               b |= BIT_SLEEP;
-               b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
-       }
+       pwr_mgmt[0] = pwr_mgmt_prev[0];
+       pwr_mgmt[1] = pwr_mgmt_prev[1];
 
-       if ((b & BIT_SLEEP) != ((sleep != 0) * BIT_SLEEP)) {
-               if (sleep) {
-                       result = mpu_set_i2c_bypass(mldl_cfg, mlsl_handle, 1);
-                       if (result) {
-                               LOG_RESULT_LOCATION(result);
-                               return result;
-                       }
-                       b |= BIT_SLEEP;
-                       result =
-                           inv_serial_single_write(
-                                   mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                                   MPUREG_PWR_MGM, b);
-                       if (result) {
-                               LOG_RESULT_LOCATION(result);
-                               return result;
-                       }
-                       mldl_cfg->inv_mpu_state->status |=
-                               MPU_GYRO_IS_SUSPENDED;
-                       mldl_cfg->inv_mpu_state->status |=
-                               MPU_DEVICE_IS_SUSPENDED;
-               } else {
-                       b &= ~BIT_SLEEP;
-                       result =
-                           inv_serial_single_write(
-                                   mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                                   MPUREG_PWR_MGM, b);
-                       if (result) {
-                               LOG_RESULT_LOCATION(result);
-                               return result;
-                       }
-                       mldl_cfg->inv_mpu_state->status &=
-                               ~MPU_GYRO_IS_SUSPENDED;
-                       mldl_cfg->inv_mpu_state->status &=
-                               ~MPU_DEVICE_IS_SUSPENDED;
-                       msleep(5);
-               }
+       if (sleep) {
+               mldl_cfg->inv_mpu_state->status |= MPU_DEVICE_IS_SUSPENDED;
+               pwr_mgmt[0] |= BIT_SLEEP;
+       } else {
+               mldl_cfg->inv_mpu_state->status &= ~MPU_DEVICE_IS_SUSPENDED;
+               pwr_mgmt[0] &= ~BIT_SLEEP;
        }
-       /*---
-         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;
+       if (pwr_mgmt[0] != pwr_mgmt_prev[0]) {
                result = inv_serial_single_write(
                        mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_PWR_MGM, b);
+                       MPUREG_PWR_MGMT_1, pwr_mgmt[0]);
                if (result) {
                        LOG_RESULT_LOCATION(result);
                        return result;
                }
        }
-       if ((b & BIT_STBY_YG) != ((disable_gy != 0) * BIT_STBY_YG)) {
-               b ^= BIT_STBY_YG;
+
+       pwr_mgmt[1] &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
+       if (!(sensors & INV_X_GYRO))
+               pwr_mgmt[1] |= BIT_STBY_XG;
+       if (!(sensors & INV_Y_GYRO))
+               pwr_mgmt[1] |= BIT_STBY_YG;
+       if (!(sensors & INV_Z_GYRO))
+               pwr_mgmt[1] |= BIT_STBY_ZG;
+
+       if (pwr_mgmt[1] != pwr_mgmt_prev[1]) {
                result = inv_serial_single_write(
                        mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_PWR_MGM, b);
+                       MPUREG_PWR_MGMT_2, pwr_mgmt[1]);
                if (result) {
                        LOG_RESULT_LOCATION(result);
                        return result;
                }
        }
-       if ((b & BIT_STBY_ZG) != ((disable_gz != 0) * BIT_STBY_ZG)) {
-               b ^= BIT_STBY_ZG;
-               result = inv_serial_single_write(
-                       mlsl_handle, mldl_cfg->mpu_chip_info->addr,
-                       MPUREG_PWR_MGM, b);
-               if (result) {
-                       LOG_RESULT_LOCATION(result);
-                       return result;
-               }
+
+       if ((pwr_mgmt[1] & (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
+           (BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) {
+               mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_SUSPENDED;
+       } else {
+               mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_SUSPENDED;
        }
 
        return INV_SUCCESS;
@@ -688,8 +657,32 @@ static int mpu_set_clock_source(void *gyro_handle, struct mldl_cfg *mldl_cfg)
                LOG_RESULT_LOCATION(result);
                return result;
        }
-       /* TODO : workarounds to be determined and implemented */
 
+       /* ERRATA:
+          workaroud to switch from any MPU_CLK_SEL_PLLGYROx to
+          MPU_CLK_SEL_INTERNAL and XGyro is powered up:
+          1) Select INT_OSC
+          2) PD XGyro
+          3) PU XGyro
+        */
+       if ((cur_clk_src == MPU_CLK_SEL_PLLGYROX
+                || cur_clk_src == MPU_CLK_SEL_PLLGYROY
+                || cur_clk_src == MPU_CLK_SEL_PLLGYROZ)
+           && mldl_cfg->mpu_gyro_cfg->clk_src == MPU_CLK_SEL_INTERNAL
+           && mldl_cfg->inv_mpu_cfg->requested_sensors & INV_X_GYRO) {
+               unsigned char first_result = INV_SUCCESS;
+               mldl_cfg->inv_mpu_cfg->requested_sensors &= ~INV_X_GYRO;
+               result = mpu60xx_pwr_mgmt(
+                       mldl_cfg, gyro_handle,
+                       false, mldl_cfg->inv_mpu_cfg->requested_sensors);
+               ERROR_CHECK_FIRST(first_result, result);
+               mldl_cfg->inv_mpu_cfg->requested_sensors |= INV_X_GYRO;
+               result = mpu60xx_pwr_mgmt(
+                       mldl_cfg, gyro_handle,
+                       false, mldl_cfg->inv_mpu_cfg->requested_sensors);
+               ERROR_CHECK_FIRST(first_result, result);
+               result = first_result;
+       }
        return result;
 }
 
@@ -715,7 +708,8 @@ static int mpu_set_clock_source(void *gyro_handle, struct mldl_cfg *mldl_cfg)
  *
  * returns INV_SUCCESS or non-zero error code
  */
-static int mpu_set_slave_mpu3050(struct mldl_cfg *mldl_cfg,
+
+static int mpu_set_slave_mpu60xx(struct mldl_cfg *mldl_cfg,
                                 void *gyro_handle,
                                 struct ext_slave_descr *slave,
                                 struct ext_slave_platform_data *slave_pdata,
@@ -723,81 +717,266 @@ static int mpu_set_slave_mpu3050(struct mldl_cfg *mldl_cfg,
 {
        int result;
        unsigned char reg;
+       /* Slave values */
        unsigned char slave_reg;
        unsigned char slave_len;
        unsigned char slave_endian;
        unsigned char slave_address;
-
-       if (slave_id != EXT_SLAVE_TYPE_ACCEL)
-               return 0;
-
-       result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true);
+       /* Which MPU6050 registers to use */
+       unsigned char addr_reg;
+       unsigned char reg_reg;
+       unsigned char ctrl_reg;
+       /* Which MPU6050 registers to use for the trigger */
+       unsigned char addr_trig_reg;
+       unsigned char reg_trig_reg;
+       unsigned char ctrl_trig_reg;
+
+       unsigned char bits_slave_delay = 0;
+       /* Divide down rate for the Slave, from the mpu rate */
+       unsigned char d0_trig_reg;
+       unsigned char delay_ctrl_orig;
+       unsigned char delay_ctrl;
+       long divider;
 
        if (NULL == slave || NULL == slave_pdata) {
                slave_reg = 0;
                slave_len = 0;
                slave_endian = 0;
                slave_address = 0;
-               mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 0;
        } else {
                slave_reg = slave->read_reg;
                slave_len = slave->read_len;
                slave_endian = slave->endian;
                slave_address = slave_pdata->address;
-               mldl_cfg->inv_mpu_state->i2c_slaves_enabled = 1;
-       }
+               slave_address |= BIT_I2C_READ;
+       }
+
+       switch (slave_id) {
+       case EXT_SLAVE_TYPE_ACCEL:
+               addr_reg = MPUREG_I2C_SLV1_ADDR;
+               reg_reg  = MPUREG_I2C_SLV1_REG;
+               ctrl_reg = MPUREG_I2C_SLV1_CTRL;
+               addr_trig_reg = 0;
+               reg_trig_reg  = 0;
+               ctrl_trig_reg = 0;
+               bits_slave_delay = BIT_SLV1_DLY_EN;
+               break;
+       case EXT_SLAVE_TYPE_COMPASS:
+               addr_reg = MPUREG_I2C_SLV0_ADDR;
+               reg_reg  = MPUREG_I2C_SLV0_REG;
+               ctrl_reg = MPUREG_I2C_SLV0_CTRL;
+               addr_trig_reg = MPUREG_I2C_SLV2_ADDR;
+               reg_trig_reg  = MPUREG_I2C_SLV2_REG;
+               ctrl_trig_reg = MPUREG_I2C_SLV2_CTRL;
+               d0_trig_reg   = MPUREG_I2C_SLV2_DO;
+               bits_slave_delay = BIT_SLV2_DLY_EN | BIT_SLV0_DLY_EN;
+               break;
+       case EXT_SLAVE_TYPE_PRESSURE:
+               addr_reg = MPUREG_I2C_SLV3_ADDR;
+               reg_reg  = MPUREG_I2C_SLV3_REG;
+               ctrl_reg = MPUREG_I2C_SLV3_CTRL;
+               addr_trig_reg = MPUREG_I2C_SLV4_ADDR;
+               reg_trig_reg  = MPUREG_I2C_SLV4_REG;
+               ctrl_trig_reg = MPUREG_I2C_SLV4_CTRL;
+               bits_slave_delay = BIT_SLV4_DLY_EN | BIT_SLV3_DLY_EN;
+               break;
+       default:
+               LOG_RESULT_LOCATION(INV_ERROR_INVALID_PARAMETER);
+               return INV_ERROR_INVALID_PARAMETER;
+       };
+
+       /* return if this slave has already been set */
+       if ((slave_address &&
+            ((mldl_cfg->inv_mpu_state->i2c_slaves_enabled & bits_slave_delay)
+                   == bits_slave_delay)) ||
+           (!slave_address &&
+            (mldl_cfg->inv_mpu_state->i2c_slaves_enabled & bits_slave_delay) ==
+                   0))
+               return 0;
+
+       result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, true);
 
        /* Address */
        result = inv_serial_single_write(gyro_handle,
                                         mldl_cfg->mpu_chip_info->addr,
-                                        MPUREG_AUX_SLV_ADDR, slave_address);
+                                        addr_reg, slave_address);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
        /* Register */
-       result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr,
-                                MPUREG_ACCEL_BURST_ADDR, 1, &reg);
+       result = inv_serial_single_write(gyro_handle,
+                                        mldl_cfg->mpu_chip_info->addr,
+                                        reg_reg, slave_reg);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
-       reg = ((reg & 0x80) | slave_reg);
+
+       /* 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;
+               return INV_ERROR_INVALID_CONFIGURATION;
+       }
+       reg = slave_len;
+       if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN) {
+               reg |= BIT_SLV_BYTE_SW;
+               if (slave_reg & 1)
+                       reg |= BIT_SLV_GRP;
+       }
+       if (slave_address)
+               reg |= BIT_SLV_ENABLE;
+
        result = inv_serial_single_write(gyro_handle,
                                         mldl_cfg->mpu_chip_info->addr,
-                                        MPUREG_ACCEL_BURST_ADDR, reg);
+                                        ctrl_reg, reg);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
 
-       /* Length */
-       result = inv_serial_read(gyro_handle, mldl_cfg->mpu_chip_info->addr,
-                                MPUREG_USER_CTRL, 1, &reg);
-       if (result) {
-               LOG_RESULT_LOCATION(result);
-               return result;
+       /* Trigger */
+       if (addr_trig_reg) {
+               /* If slave address is 0 this clears the trigger */
+               result = inv_serial_single_write(gyro_handle,
+                                                mldl_cfg->mpu_chip_info->addr,
+                                                addr_trig_reg,
+                                                slave_address & ~BIT_I2C_READ);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
        }
-       reg = (reg & ~BIT_AUX_RD_LENG);
-       result = inv_serial_single_write(
-               gyro_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_USER_CTRL, reg);
+
+       if (slave && slave->trigger && reg_trig_reg) {
+               result = inv_serial_single_write(gyro_handle,
+                                                mldl_cfg->mpu_chip_info->addr,
+                                                reg_trig_reg,
+                                                slave->trigger->reg);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               result = inv_serial_single_write(gyro_handle,
+                                                mldl_cfg->mpu_chip_info->addr,
+                                                ctrl_trig_reg,
+                                                BIT_SLV_ENABLE | 0x01);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               result = inv_serial_single_write(gyro_handle,
+                                                mldl_cfg->mpu_chip_info->addr,
+                                                d0_trig_reg,
+                                                slave->trigger->value);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+       } else if (ctrl_trig_reg) {
+               result = inv_serial_single_write(gyro_handle,
+                                                mldl_cfg->mpu_chip_info->addr,
+                                                ctrl_trig_reg, 0x00);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+       }
+
+       /* Data rate */
+       if (slave) {
+               struct ext_slave_config config;
+               long data;
+               config.key = MPU_SLAVE_CONFIG_ODR_RESUME;
+               config.len = sizeof(long);
+               config.apply = false;
+               config.data = &data;
+               if (!(slave->get_config))
+                       return INV_ERROR_INVALID_CONFIGURATION;
+
+               result = slave->get_config(NULL, slave, slave_pdata, &config);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               MPL_LOGI("Slave %d ODR: %ld Hz\n", slave_id, data / 1000);
+               divider = ((1000 * inv_mpu_get_sampling_rate_hz(
+                                   mldl_cfg->mpu_gyro_cfg))
+                       / data) - 1;
+       } else {
+               divider = 0;
+       }
+
+       result = inv_serial_read(gyro_handle,
+                               mldl_cfg->mpu_chip_info->addr,
+                               MPUREG_I2C_MST_DELAY_CTRL,
+                               1, &delay_ctrl_orig);
+       delay_ctrl = delay_ctrl_orig;
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
 
+       if (divider > 0 && divider <= MASK_I2C_MST_DLY) {
+               result = inv_serial_read(gyro_handle,
+                                        mldl_cfg->mpu_chip_info->addr,
+                                        MPUREG_I2C_SLV4_CTRL, 1, &reg);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+               if ((reg & MASK_I2C_MST_DLY) &&
+                       ((long)(reg & MASK_I2C_MST_DLY) !=
+                               (divider & MASK_I2C_MST_DLY))) {
+                       MPL_LOGW("Changing slave divider: %ld to %ld\n",
+                                (long)(reg & MASK_I2C_MST_DLY),
+                                (divider & MASK_I2C_MST_DLY));
+
+               }
+               reg |= (unsigned char)(divider & MASK_I2C_MST_DLY);
+               result = inv_serial_single_write(gyro_handle,
+                                                mldl_cfg->mpu_chip_info->addr,
+                                                MPUREG_I2C_SLV4_CTRL,
+                                                reg);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+
+               delay_ctrl |= bits_slave_delay;
+       } else {
+               delay_ctrl &= ~(bits_slave_delay);
+       }
+       if (delay_ctrl != delay_ctrl_orig) {
+               result = inv_serial_single_write(
+                       gyro_handle, mldl_cfg->mpu_chip_info->addr,
+                       MPUREG_I2C_MST_DELAY_CTRL,
+                       delay_ctrl);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);
+                       return result;
+               }
+       }
+
+       if (slave_address)
+               mldl_cfg->inv_mpu_state->i2c_slaves_enabled |=
+                       bits_slave_delay;
+       else
+               mldl_cfg->inv_mpu_state->i2c_slaves_enabled &=
+                       ~bits_slave_delay;
+
        return result;
 }
 
-
 static 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 slave_id)
 {
-       return mpu_set_slave_mpu3050(mldl_cfg, gyro_handle, slave,
+       return mpu_set_slave_mpu60xx(mldl_cfg, gyro_handle, slave,
                                     slave_pdata, slave_id);
 }
 /**
@@ -883,7 +1062,7 @@ int inv_mpu_set_firmware(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
                        return result;
                }
 
-#define ML_SKIP_CHECK 20
+#define ML_SKIP_CHECK 38
                for (offset = 0; offset < write_size; offset++) {
                        /* skip the register memory locations */
                        if (bank == 0 && offset < ML_SKIP_CHECK)
@@ -912,25 +1091,17 @@ static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle,
        unsigned char regs[7];
 
        /* Wake up the part */
-       result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, false, false,
-                                 !(sensors & INV_X_GYRO),
-                                 !(sensors & INV_Y_GYRO),
-                                 !(sensors & INV_Z_GYRO));
-
-       if (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG) &&
-           !mpu_was_reset(mldl_cfg, gyro_handle)) {
-               return INV_SUCCESS;
-       }
-
+       result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, sensors);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
+
+       /* Always set the INT_ENABLE and DIVIDER as the Accel Only mode for 6050
+          can set these too */
        result = inv_serial_single_write(
                gyro_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_INT_CFG,
-               (mldl_cfg->mpu_gyro_cfg->int_config |
-                       mldl_cfg->pdata->int_config));
+               MPUREG_INT_ENABLE, (mldl_cfg->mpu_gyro_cfg->int_config));
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
@@ -942,18 +1113,34 @@ static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle,
                LOG_RESULT_LOCATION(result);
                return result;
        }
+
+       if (!(mldl_cfg->inv_mpu_state->status & MPU_GYRO_NEEDS_CONFIG) &&
+           !mpu_was_reset(mldl_cfg, gyro_handle)) {
+               return INV_SUCCESS;
+       }
+
+       /* Configure the MPU */
+       result = mpu_set_i2c_bypass(mldl_cfg, gyro_handle, 1);
+       if (result) {
+               LOG_RESULT_LOCATION(result);
+               return result;
+       }
        result = mpu_set_clock_source(gyro_handle, mldl_cfg);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
 
-       reg = DLPF_FS_SYNC_VALUE(mldl_cfg->mpu_gyro_cfg->ext_sync,
-                                mldl_cfg->mpu_gyro_cfg->full_scale,
-                                mldl_cfg->mpu_gyro_cfg->lpf);
+       reg = MPUREG_GYRO_CONFIG_VALUE(0, 0, 0,
+                                      mldl_cfg->mpu_gyro_cfg->full_scale);
+       result = inv_serial_single_write(
+               gyro_handle, mldl_cfg->mpu_chip_info->addr,
+               MPUREG_GYRO_CONFIG, reg);
+       reg = MPUREG_CONFIG_VALUE(mldl_cfg->mpu_gyro_cfg->ext_sync,
+                                 mldl_cfg->mpu_gyro_cfg->lpf);
        result = inv_serial_single_write(
                gyro_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_DLPF_FS_SYNC, reg);
+               MPUREG_CONFIG, reg);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
@@ -981,21 +1168,24 @@ static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle,
 
        result = inv_serial_single_write(
                gyro_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_XG_OFFS_TC, mldl_cfg->mpu_offsets->tc[0]);
+               MPUREG_XG_OFFS_TC,
+               ((mldl_cfg->mpu_offsets->tc[0] << 1) & BITS_XG_OFFS_TC));
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
+       regs[0] = ((mldl_cfg->mpu_offsets->tc[1] << 1) & BITS_YG_OFFS_TC);
        result = inv_serial_single_write(
                gyro_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_YG_OFFS_TC, mldl_cfg->mpu_offsets->tc[1]);
+               MPUREG_YG_OFFS_TC, regs[0]);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
        }
        result = inv_serial_single_write(
                gyro_handle, mldl_cfg->mpu_chip_info->addr,
-               MPUREG_ZG_OFFS_TC, mldl_cfg->mpu_offsets->tc[2]);
+               MPUREG_ZG_OFFS_TC,
+               ((mldl_cfg->mpu_offsets->tc[2] << 1) & BITS_ZG_OFFS_TC));
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
@@ -1119,8 +1309,10 @@ int gyro_get_config(void *mlsl_handle,
        struct mpu_offsets *mpu_offsets = mldl_cfg->mpu_offsets;
        int ii;
 
-       if (!data->data)
+       if (!data->data){
+               printk("gyro_get_config----------------------1\n");
                return INV_ERROR_INVALID_PARAMETER;
+       }
 
        switch (data->key) {
        case MPU_SLAVE_INT_CONFIG:
@@ -1180,12 +1372,15 @@ int gyro_get_config(void *mlsl_handle,
                *((__u16 *)data->data) = mpu_chip_info->accel_sens_trim;
                break;
        case MPU_SLAVE_RAM:
-               if (data->len != mldl_cfg->mpu_ram->length)
+               if (data->len != mldl_cfg->mpu_ram->length){
+                       printk("gyro_get_config----------------------2\n");
                        return INV_ERROR_INVALID_PARAMETER;
+               }
 
                memcpy(data->data, mldl_cfg->mpu_ram->ram, data->len);
                break;
        default:
+               printk("gyro_get_config----------------------3\n");
                LOG_RESULT_LOCATION(INV_ERROR_FEATURE_NOT_IMPLEMENTED);
                return INV_ERROR_FEATURE_NOT_IMPLEMENTED;
        };
@@ -1259,8 +1454,9 @@ int inv_mpu_open(struct mldl_cfg *mldl_cfg,
         * Take the DMP out of sleep, and
         * read the product_id, sillicon rev and whoami
         */
-       mldl_cfg->inv_mpu_state->status |= MPU_GYRO_IS_BYPASSED;
-       result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, RESET, 0, 0, 0, 0);
+       mldl_cfg->inv_mpu_state->status &= ~MPU_GYRO_IS_BYPASSED;
+       result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, true,
+                                 INV_THREE_AXIS_GYRO);
        if (result) {
                LOG_RESULT_LOCATION(result);
                return result;
@@ -1308,9 +1504,13 @@ int inv_mpu_open(struct mldl_cfg *mldl_cfg,
                return result;
        }
 
+       for (ii = 0; ii < GYRO_NUM_AXES; ii++) {
+               mldl_cfg->mpu_offsets->tc[ii] =
+                   (mldl_cfg->mpu_offsets->tc[ii] & BITS_XG_OFFS_TC) >> 1;
+       }
 
 #if INV_CACHE_DMP != 0
-       result = mpu3050_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP, 0, 0, 0);
+       result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false, 0);
 #endif
        if (result) {
                LOG_RESULT_LOCATION(result);
@@ -1588,12 +1788,8 @@ int inv_mpu_suspend(struct mldl_cfg *mldl_cfg,
        /* Gyro */
        if (suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE] &&
            !(mldl_cfg->inv_mpu_state->status & MPU_GYRO_IS_SUSPENDED)) {
-               result = mpu3050_pwr_mgmt(
-                       mldl_cfg, gyro_handle, 0,
-                       suspend_dmp && suspend_slave[EXT_SLAVE_TYPE_GYROSCOPE],
-                       (unsigned char)(sensors & INV_X_GYRO),
-                       (unsigned char)(sensors & INV_Y_GYRO),
-                       (unsigned char)(sensors & INV_Z_GYRO));
+               result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, false,
+                                       ((~sensors) & INV_ALL_SENSORS));
                if (result) {
                        LOG_RESULT_LOCATION(result);
                        return result;
old mode 100644 (file)
new mode 100755 (executable)
index 1c23878..a12fcc5
@@ -31,7 +31,7 @@
 #include "mltypes.h"
 #include "mlsl.h"
 #include <linux/mpu.h>
-#include "mpu3050.h"
+#include "mpu6050b1.h"
 
 #include "log.h"
 
old mode 100644 (file)
new mode 100755 (executable)
index 5c6951b..79f8f45
@@ -50,16 +50,16 @@ void mldl_print_cfg(struct mldl_cfg *mldl_cfg)
        int ii;
 
        /* mpu_gyro_cfg */
-       MPL_LOGI("int_config     = %02x\n", mpu_gyro_cfg->int_config);
-       MPL_LOGI("ext_sync       = %02x\n", mpu_gyro_cfg->ext_sync);
-       MPL_LOGI("full_scale     = %02x\n", mpu_gyro_cfg->full_scale);
-       MPL_LOGI("lpf            = %02x\n", mpu_gyro_cfg->lpf);
-       MPL_LOGI("clk_src        = %02x\n", mpu_gyro_cfg->clk_src);
-       MPL_LOGI("divider        = %02x\n", mpu_gyro_cfg->divider);
-       MPL_LOGI("dmp_enable     = %02x\n", mpu_gyro_cfg->dmp_enable);
-       MPL_LOGI("fifo_enable    = %02x\n", mpu_gyro_cfg->fifo_enable);
-       MPL_LOGI("dmp_cfg1       = %02x\n", mpu_gyro_cfg->dmp_cfg1);
-       MPL_LOGI("dmp_cfg2       = %02x\n", mpu_gyro_cfg->dmp_cfg2);
+       MPL_LOGV("int_config     = %02x\n", mpu_gyro_cfg->int_config);
+       MPL_LOGV("ext_sync       = %02x\n", mpu_gyro_cfg->ext_sync);
+       MPL_LOGV("full_scale     = %02x\n", mpu_gyro_cfg->full_scale);
+       MPL_LOGV("lpf            = %02x\n", mpu_gyro_cfg->lpf);
+       MPL_LOGV("clk_src        = %02x\n", mpu_gyro_cfg->clk_src);
+       MPL_LOGV("divider        = %02x\n", mpu_gyro_cfg->divider);
+       MPL_LOGV("dmp_enable     = %02x\n", mpu_gyro_cfg->dmp_enable);
+       MPL_LOGV("fifo_enable    = %02x\n", mpu_gyro_cfg->fifo_enable);
+       MPL_LOGV("dmp_cfg1       = %02x\n", mpu_gyro_cfg->dmp_cfg1);
+       MPL_LOGV("dmp_cfg2       = %02x\n", mpu_gyro_cfg->dmp_cfg2);
        /* mpu_offsets */
        MPL_LOGV("tc[0]      = %02x\n", mpu_offsets->tc[0]);
        MPL_LOGV("tc[1]      = %02x\n", mpu_offsets->tc[1]);
@@ -75,6 +75,7 @@ void mldl_print_cfg(struct mldl_cfg *mldl_cfg)
        MPL_LOGV("product_revision = %02x\n", mpu_chip_info->product_revision);
        MPL_LOGV("product_id       = %02x\n", mpu_chip_info->product_id);
        MPL_LOGV("gyro_sens_trim   = %02x\n", mpu_chip_info->gyro_sens_trim);
+       MPL_LOGV("accel_sens_trim  = %02x\n", mpu_chip_info->accel_sens_trim);
 
        MPL_LOGV("requested_sensors = %04x\n", inv_mpu_cfg->requested_sensors);
        MPL_LOGV("ignore_system_suspend= %04x\n",
old mode 100644 (file)
new mode 100755 (executable)
index 7fef66f50baa785e1801e8d2079ba660bbe86922..a50cd20f926621126e619b7f73c20bf5ec63e701 100755 (executable)
@@ -20,7 +20,7 @@
 #include "mlsl.h"
 #include <linux/i2c.h>
 #include "log.h"
-#include "mpu3050.h"
+#include "mpu6050b1.h"
 
 #define MPU_I2C_RATE 100*1000
 static int inv_i2c_write(struct i2c_adapter *i2c_adap,
@@ -42,13 +42,13 @@ static int inv_i2c_write(struct i2c_adapter *i2c_adap,
        msgs[0].scl_rate = MPU_I2C_RATE;
 
        res = i2c_transfer(i2c_adap, msgs, 1);
-       if (res == 1)
-               return 0;
-       else if(res == 0)
-               return -EBUSY;
-       else
+       if (res < 1) {
+               if (res == 0)
+                       res = -EIO;
+               LOG_RESULT_LOCATION(res);
                return res;
-
+       } else
+               return 0;
 }
 
 static int inv_i2c_write_register(struct i2c_adapter *i2c_adap,
@@ -87,13 +87,13 @@ static int inv_i2c_read(struct i2c_adapter *i2c_adap,
        msgs[1].scl_rate = MPU_I2C_RATE;        
 
        res = i2c_transfer(i2c_adap, msgs, 2);
-       if (res == 2)
-               return 0;
-       else if(res == 0)
-               return -EBUSY;
-       else
+       if (res < 2) {
+               if (res >= 0)
+                       res = -EIO;
+               LOG_RESULT_LOCATION(res);
                return res;
-
+       } else
+               return 0;
 }
 
 static int mpu_memory_read(struct i2c_adapter *i2c_adap,
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 3c54d55811ef65a3a11403f4b2b506cf6de4f180..db440a6253a5a0e29fee94a0f13bd62f9f7f9a6b 100755 (executable)
@@ -16,7 +16,6 @@
        along with this program.  If not, see <http://www.gnu.org/licenses/>.
        $
  */
-#define DEBUG
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
 #include <linux/interrupt.h>
 #include "mldl_cfg.h"
 #include <linux/mpu.h>
 
+#include "accel/mpu6050.h"
+
+#include <linux/syscalls.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/iio/consumer.h>
+
+
+
+
+
+#define CAB_NUM 1
+#define M_CONST             49152
+//#define MPU6050_CABLIC "/data/mpu6050_cablic.dat"
+#define MPU6050_CABLIC "/dev/mtd/mtd6"
+
+static int mpu6050_get = 0;
+static bool Is_cab=false;
+static int count_s=0;
+static int countx=0;
+static int countx_l=0;
+static int county=0;
+static int county_l=0;
+static int countz=0;
+static int countz_l=0;
+static int get_cablic;
+static int gsensor_clear = 0;
+
+
+struct cal_data {
+       int valid;
+       long xoffset;
+       long xoffset_l;
+       long xoffset1;
+       long xoffset1_l;
+       long yoffset;
+       long yoffset_l;
+       long yoffset1;
+       long yoffset1_l;
+       long zoffset;
+       long zoffset_l;
+       long zoffset1;
+       long zoffset1_l;
+//     char magic[4];
+       char reser[512];
+};
+
+static struct cal_data cablic_arry[CAB_NUM];
+static struct kobject *android_gsensor_kobj;
+
+struct mpu6050_in{
+       //struct timer_list sn_timer;
+       struct workqueue_struct *wq;
+       struct delayed_work delay_work;
+       struct work_struct sn_work;
+};
 
 /* Platform data for the MPU */
 struct mpu_private_data {
@@ -77,8 +136,8 @@ struct mpu_private_data {
        struct module *slave_modules[EXT_SLAVE_NUM_TYPES];
 };
 
+struct mpu_platform_data mpu_data; 
 struct mpu_private_data *mpu_private_data;
-static struct i2c_client *this_client;
 
 static void mpu_pm_timeout(u_long data)
 {
@@ -135,7 +194,7 @@ static int mpu_pm_notifier_callback(struct notifier_block *nb,
 static int mpu_dev_open(struct inode *inode, struct file *file)
 {
        struct mpu_private_data *mpu =
-           (struct mpu_private_data *) i2c_get_clientdata(this_client);
+           container_of(file->private_data, struct mpu_private_data, dev);
        struct i2c_client *client = mpu->client;
        int result;
        int ii;
@@ -148,7 +207,6 @@ static int mpu_dev_open(struct inode *inode, struct file *file)
                return -EBUSY;
        }
        mpu->pid = current->pid;
-       file->private_data = &mpu->dev;
 
        /* Reset the sensors to the default */
        if (result) {
@@ -356,19 +414,24 @@ static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg,
        void *user_data;
 
        retval = copy_from_user(&config, usr_config, sizeof(config));
-       if (retval)
+       if (retval){
+               printk("inv_mpu_get_config----------------------\n");
                return -EFAULT;
+       }
 
        user_data = config.data;
        if (config.len && config.data) {
                void *data;
                data = kmalloc(config.len, GFP_KERNEL);
-               if (!data)
+               if (!data){
+                       printk("inv_mpu_get_config----------------------1\n");
                        return -ENOMEM;
+               }
 
                retval = copy_from_user(data,
                                        (void __user *)config.data, config.len);
                if (retval) {
+                       printk("inv_mpu_get_config----------------------2\n");
                        retval = -EFAULT;
                        kfree(data);
                        return retval;
@@ -380,6 +443,7 @@ static int inv_mpu_get_config(struct mldl_cfg *mldl_cfg,
                retval = copy_to_user((unsigned char __user *)user_data,
                                config.data, config.len);
        kfree(config.data);
+
        return retval;
 }
 
@@ -465,6 +529,55 @@ static int slave_get_config(struct mldl_cfg *mldl_cfg,
        return retval;
 }
 
+static int mpu6050_load_cablic(const char *addr)
+{
+       int ret;
+       long fd = sys_open(addr,O_RDONLY,0);
+       printk("yemk:mpu6050_load_cablic\n");
+       if(fd < 0){
+               printk("mpu6050_load_cablic: open file %s\n", MPU6050_CABLIC);
+               return -1;
+       }
+       ret = sys_read(fd,(char __user *)cablic_arry,sizeof(cablic_arry));
+       sys_close(fd);
+
+       return ret;
+}
+
+static void mpu6050_put_cablic(const char *addr)
+{
+       long fd = sys_open(addr,O_CREAT | O_RDWR | O_TRUNC,0);
+       printk("yemk:mpu6050_put_cablic\n");
+       if(fd<0){
+               printk("mpu6050_put_cablic: open file%s\n",MPU6050_CABLIC);
+               return;
+       }
+       sys_write(fd,(const char __user *)cablic_arry,sizeof(cablic_arry));
+
+       sys_close(fd);
+}
+static void mpu_get(struct work_struct *work)
+{
+       struct mpu6050_in  *bat = container_of((work), \
+                       struct mpu6050_in, delay_work);
+
+       if(mpu6050_get==1){
+               mpu6050_put_cablic(MPU6050_CABLIC);
+               mpu6050_get=0;
+       }else{
+               if(get_cablic){
+                       get_cablic=0;
+                       mpu6050_load_cablic(MPU6050_CABLIC);
+               }
+       }
+
+       if(gsensor_clear==1){
+               mpu6050_put_cablic(MPU6050_CABLIC);
+               gsensor_clear=0;
+       }
+       queue_delayed_work(bat ->wq, &bat ->delay_work, msecs_to_jiffies(3000));
+}
+
 static int inv_slave_read(struct mldl_cfg *mldl_cfg,
                          void *gyro_adapter,
                          void *slave_adapter,
@@ -561,6 +674,125 @@ static int mpu_handle_mlsl(void *sl_handle,
        kfree(msg.data);
        return retval;
 }
+static int mpu6050_check(unsigned long arg)
+{
+       char data[6];
+       short int x,y,z;
+       short int zoffs=0,xoffs=0,yoffs=0;
+
+       if(copy_from_user(data, (unsigned char __user *)arg, sizeof(data)))
+               return -EFAULT;
+
+       x = data[0]*256 + data[1];
+       y = data[2]*256 + data[3];
+       z = data[4]*256 + data[5];
+       xoffs = x;
+       yoffs = y;
+       zoffs = z-M_CONST;
+       //printk("yemk1111 cablic_arry[0].zoffset_l=%8ld\n",cablic_arry[0].zoffset_l);
+       if(Is_cab==true){
+               if(zoffs>0){
+                       //printk("zheng cablic_arry[0].zoffset=%8ld\n",cablic_arry[0].zoffset);
+                       cablic_arry[0].zoffset+=zoffs;
+                       countz++;
+               }else{
+                       //printk("zheng cablic_arry[0].zoffset_l=%8ld\n",cablic_arry[0].zoffset_l);
+                       cablic_arry[0].zoffset_l+=zoffs;
+                       countz_l++;
+               }
+               if(xoffs>0){
+                       cablic_arry[0].xoffset+=xoffs;
+                       countx++;
+               }else{
+                       cablic_arry[0].xoffset_l+=xoffs;
+                       countx_l++;
+               }
+               if(yoffs>0){
+                       cablic_arry[0].yoffset+=yoffs;
+                       county++;
+               }else{
+                       cablic_arry[0].yoffset_l+=yoffs;
+                       county_l++;
+               }
+               count_s++;
+               //printk("yemk2222 z=%d,zoffs=%d\n",z,zoffs);
+               //printk("yemk2222 x=%8ld,xoffs=%8ld\n",x,xoffs);
+               //printk("yemk2222 y=%8ld,yoffs=%8ld\n",y,yoffs);
+               if(count_s==20){
+                       //cablic_arry[0].xoffset=cablic_arry[0].xoffset/count_s;
+                       //cablic_arry[0].yoffset=cablic_arry[0].yoffset/count_s;
+                       //printk("yemk11:cab_check->zoffset=%8ld\n",cablic_arry[0].zoffset);
+                       if(countz)
+                               cablic_arry[0].zoffset=(cablic_arry[0].zoffset-cablic_arry[0].zoffset1)/countz;
+                       if(countz_l)
+                               cablic_arry[0].zoffset_l=(cablic_arry[0].zoffset_l-cablic_arry[0].zoffset1_l)/countz_l;
+                       if(countx)
+                               cablic_arry[0].xoffset=(cablic_arry[0].xoffset-cablic_arry[0].xoffset1)/countx;
+                       if(countx_l)
+                               cablic_arry[0].xoffset_l=(cablic_arry[0].xoffset_l-cablic_arry[0].xoffset1_l)/countx_l;
+                       if(county)
+                               cablic_arry[0].yoffset=(cablic_arry[0].yoffset-cablic_arry[0].yoffset1)/county;
+                       if(county_l)
+                                       cablic_arry[0].yoffset_l=(cablic_arry[0].yoffset_l-cablic_arry[0].yoffset1_l)/county_l;
+                       //printk("yemk cab_check->zoffset=%8ld,zoffset1=%8ld\n",cablic_arry[0].zoffset,cablic_arry[0].zoffset1);
+                       //printk("yemk cab_check->zoffset=%d\n",cablic_arry[0].yoffset);
+                       //printk("yemk2222 cab_check->zoffset=%8ld,..%8ld\n",cablic_arry[0].zoffset,cablic_arry[0].zoffset_l);
+                       //printk("yemk2222 cab_check->yoffset=%8ld,..%8ld ..%d --%d\n",cablic_arry[0].yoffset,cablic_arry[0].yoffset_l,county,county_l);
+                       //printk("yemk2222 cab_check->zoffset=%8ld,..%8ld ..%d --%d\n",cablic_arry[0].zoffset,cablic_arry[0].zoffset_l,countz,countz_l);
+                       cablic_arry[0].zoffset1=cablic_arry[0].zoffset;
+                       cablic_arry[0].zoffset1_l=cablic_arry[0].zoffset_l;
+
+                       cablic_arry[0].xoffset1=cablic_arry[0].xoffset;
+                       cablic_arry[0].xoffset1_l=cablic_arry[0].xoffset_l;
+
+                       cablic_arry[0].yoffset1=cablic_arry[0].yoffset;
+                       cablic_arry[0].yoffset1_l=cablic_arry[0].yoffset_l;
+
+                       Is_cab=false;
+                       count_s=0;
+                       countx=0;
+                       countx_l=0;
+                       county=0;
+                       county_l=0;
+                       countz=0;
+                       countz_l=0;
+                       mpu6050_get=1;
+                       cablic_arry[0].valid=7654321;
+
+               }
+       }else{
+               if(cablic_arry[0].valid == 7654321){
+                       if(zoffs>=0){
+                               //printk("zheng z=%d,zoffs=%d\n",z,zoffs);
+                               data[4] = (z-cablic_arry[0].zoffset)/256;
+                               data[5] = (z-cablic_arry[0].zoffset)%256;
+                       }else{
+                               //printk("fu z=%d,zoffs=%d\n",z,zoffs);
+                               data[4] = (z-cablic_arry[0].zoffset_l)/256;
+                               data[5] = (z-cablic_arry[0].zoffset_l)%256;
+                       }
+
+                       if(xoffs>=0){
+                               data[0] = (x-cablic_arry[0].xoffset)/256;
+                               data[1] = (x-cablic_arry[0].xoffset)%256;
+                       }else{
+                               data[0] = (x-cablic_arry[0].xoffset_l)/256;
+                               data[1] = (x-cablic_arry[0].xoffset_l)%256;
+                       }
+
+                       if(yoffs>=0){
+                               data[2] = (y-cablic_arry[0].yoffset)/256;
+                               data[3] = (y-cablic_arry[0].yoffset)%256;
+                       }else{
+                               data[2] = (y-cablic_arry[0].yoffset_l)/256;
+                               data[3] = (y-cablic_arry[0].yoffset_l)%256;
+                       }
+               }
+       }
+       if(copy_to_user((unsigned char __user *)arg,data, sizeof(data)))
+               return -EFAULT;
+       return 0;
+}
 
 /* ioctl - I/O control */
 static long mpu_dev_ioctl(struct file *file,
@@ -584,15 +816,16 @@ static long mpu_dev_ioctl(struct file *file,
                                i2c_get_adapter(pdata_slave[ii]->adapt_num);
        }
        slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE] = client->adapter;
-       
+
        retval = mutex_lock_interruptible(&mpu->mutex);
        if (retval) {
-               dev_err(&this_client->adapter->dev,
+               dev_err(&client->adapter->dev,
                        "%s: mutex_lock_interruptible returned %d\n",
                        __func__, retval);
                return retval;
        }
 
+
        switch (cmd) {
        case MPU_GET_EXT_SLAVE_PLATFORM_DATA:
                retval = mpu_dev_ioctl_get_ext_slave_platform_data(
@@ -659,7 +892,7 @@ static long mpu_dev_ioctl(struct file *file,
                        slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
                        (struct ext_slave_config __user *)arg);
                break;
-       case MPU_GET_CONFIG_ACCEL:
+       case MPU_GET_CONFIG_ACCEL:      
                retval = slave_get_config(
                        mldl_cfg,
                        slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
@@ -709,6 +942,7 @@ static long mpu_dev_ioctl(struct file *file,
                complete(&mpu->completion);
                break;
        case MPU_READ_ACCEL:
+               //printk("###########MPU_READ_ACCEL\n");
                retval = inv_slave_read(
                        mldl_cfg,
                        slave_adapter[EXT_SLAVE_TYPE_GYROSCOPE],
@@ -716,6 +950,7 @@ static long mpu_dev_ioctl(struct file *file,
                        slave[EXT_SLAVE_TYPE_ACCEL],
                        pdata_slave[EXT_SLAVE_TYPE_ACCEL],
                        (unsigned char __user *)arg);
+               mpu6050_check(arg);
                break;
        case MPU_READ_COMPASS:
                retval = inv_slave_read(
@@ -777,9 +1012,8 @@ static long mpu_dev_ioctl(struct file *file,
        };
 
        mutex_unlock(&mpu->mutex);
-
-       
-       //dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",__func__, cmd, arg, retval);   
+       dev_dbg(&client->adapter->dev, "%s: %08x, %08lx, %d\n",
+               __func__, cmd, arg, retval);
 
        if (retval > 0)
                retval = -retval;
@@ -890,13 +1124,7 @@ static const struct file_operations mpu_fops = {
        .owner = THIS_MODULE,
        .read = mpu_read,
        .poll = mpu_poll,
-#if HAVE_COMPAT_IOCTL
-       .compat_ioctl = mpu_dev_ioctl,
-#endif
-#if HAVE_UNLOCKED_IOCTL
        .unlocked_ioctl = mpu_dev_ioctl,
-#endif 
-       //.unlocked_ioctl = mpu_dev_ioctl,
        .open = mpu_dev_open,
        .release = mpu_release,
 };
@@ -943,7 +1171,7 @@ int inv_mpu_register_slave(struct module *slave_module,
        }
 
        slave_pdata->address    = slave_client->addr;
-       slave_pdata->irq        = gpio_to_irq(slave_client->irq);
+       slave_pdata->irq        = 0;
        slave_pdata->adapt_num  = i2c_adapter_id(slave_client->adapter);
 
        dev_info(&slave_client->adapter->dev,
@@ -980,12 +1208,35 @@ int inv_mpu_register_slave(struct module *slave_module,
                }
        }
 
+       if (slave_descr->type == EXT_SLAVE_TYPE_ACCEL &&
+           slave_descr->id == ACCEL_ID_MPU6050 &&
+           slave_descr->config) {
+        
+               /* pass a reference to the mldl_cfg data
+                  structure to the mpu6050 accel "class" */
+               struct ext_slave_config config;
+               config.key = MPU_SLAVE_CONFIG_INTERNAL_REFERENCE;
+               config.len = sizeof(struct mldl_cfg *);
+               config.apply = true;
+               config.data = mldl_cfg;
+               result = slave_descr->config(
+                       slave_client->adapter, slave_descr,
+                       slave_pdata, &config);
+               if (result) {
+                       LOG_RESULT_LOCATION(result);   
+                       goto out_slavedescr_exit;
+               }
+       }
        pdata_slave[slave_descr->type] = slave_pdata;
        mpu->slave_modules[slave_descr->type] = slave_module;
        mldl_cfg->slave[slave_descr->type] = slave_descr;
 
        goto out_unlock_mutex;
 
+out_slavedescr_exit:
+       if (slave_descr->exit)
+               slave_descr->exit(slave_client->adapter,
+                                 slave_descr, slave_pdata);
 out_unlock_mutex:
        mutex_unlock(&mpu->mutex);
 
@@ -998,14 +1249,14 @@ out_unlock_mutex:
                warn_result = slaveirq_init(slave_client->adapter,
                                        slave_pdata, irq_name);
                if (result)
-                       dev_err(&slave_client->adapter->dev,
+                       dev_WARN(&slave_client->adapter->dev,
                                "%s irq assigned error: %d\n",
                                slave_descr->name, warn_result);
        } else {
-               dev_warn(&slave_client->adapter->dev,
+/*             dev_WARN(&slave_client->adapter->dev,
                        "%s irq not assigned: %d %d %d\n",
                        slave_descr->name,
-                       result, (int)irq_name, slave_pdata->irq);
+                       result, (int)irq_name, slave_pdata->irq);*/
        }
 
        return result;
@@ -1052,6 +1303,130 @@ void inv_mpu_unregister_slave(struct i2c_client *slave_client,
 }
 EXPORT_SYMBOL(inv_mpu_unregister_slave);
 
+static int mpu_parse_dt(struct i2c_client *client,
+                                 struct mpu_platform_data *data)
+{
+       int ret;
+       struct device_node *np = client->dev.of_node;
+       //enum of_gpio_flags gpioflags;
+       int length = 0,size = 0;
+       struct property *prop;
+       int debug = 1;
+       int i;
+       char mAarray[20];
+       int orig_x,orig_y,orig_z;
+       enum of_gpio_flags irq_flags;
+       int irq_pin;
+       u32 orientation[GYRO_NUM_AXES * GYRO_NUM_AXES];
+
+
+       irq_pin=of_get_named_gpio_flags(np, "irq-gpio", 0, (enum of_gpio_flags *)&irq_flags);
+       if(irq_pin<0){
+               dev_err(&client->dev, "get irq-gpio error\n");
+               return -EIO;
+       }
+
+       if (gpio_request(irq_pin, "mpu-irq")) {
+               dev_err(&client->dev, "mpu irq request failed\n");
+               return -ENODEV;
+       }
+       client->irq=gpio_to_irq(irq_pin);
+
+       ret = of_property_read_u32(np,"mpu-int_config",&data->int_config);
+       if(ret!=0){
+               dev_err(&client->dev, "get mpu-int_config error\n");
+               return -EIO;
+       }
+
+       ret = of_property_read_u32(np,"mpu-level_shifter",&data->level_shifter);
+       if(ret!=0){
+               dev_err(&client->dev, "get mpu-level_shifter error\n");
+               return -EIO;
+       }
+       
+       
+       prop = of_find_property(np, "mpu-orientation", &length);
+       if (!prop){
+               dev_err(&client->dev, "get mpu-orientation length error\n");
+               return -EINVAL;
+       }
+
+       size = length / sizeof(u32);
+
+       if((size > 0)&&(size <10)){
+               ret = of_property_read_u32_array(np, "mpu-orientation",
+                                       orientation,
+                                        size);
+               
+               if(ret<0){
+                       dev_err(&client->dev, "get mpu-orientation data error\n");
+                       return -EINVAL;
+               }
+       }
+       else{
+               printk(" use default orientation\n");
+       }
+
+       for(i=0;i<9;i++)
+               data->orientation[i]= orientation[i];
+
+       ret = of_property_read_u32(np,"orientation-x",&orig_x);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-x error\n");
+               return -EIO;
+       }
+
+       if(orig_x>0){
+               for(i=0;i<3;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+       ret = of_property_read_u32(np,"orientation-y",&orig_y);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-y error\n");
+               return -EIO;
+       }
+
+       if(orig_y>0){
+               for(i=3;i<6;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+
+       ret = of_property_read_u32(np,"orientation-z",&orig_z);
+       if(ret!=0){
+               dev_err(&client->dev, "get orientation-z error\n");
+               return -EIO;
+       }
+
+       if(orig_z>0){
+               for(i=6;i<9;i++)
+                       if(data->orientation[i])
+                               data->orientation[i]=-1;
+       }
+
+
+       ret = of_property_read_u32(np,"mpu-debug",&debug);
+       if(ret!=0){
+               dev_err(&client->dev, "get mpu-debug error\n");
+               return -EINVAL;
+       }
+
+       if(debug){
+               printk("int_config=%d,level_shifter=%d,client.addr=%x,client.irq=%x\n",data->int_config, \
+                       data->level_shifter,client->addr,client->irq);
+
+               for(i=0;i<size;i++)
+                       printk("%d ",data->orientation[i]);     
+               printk("\n");   
+
+       }
+       return 0;
+}
+
+
 static unsigned short normal_i2c[] = { I2C_CLIENT_END };
 
 static const struct i2c_device_id mpu_id[] = {
@@ -1069,6 +1444,12 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
        struct mldl_cfg *mldl_cfg;
        int res = 0;
        int ii = 0;
+       int ret = 0;
+       struct mpu6050_in *mpu6050_l;
+
+       ret = mpu_parse_dt(client,&mpu_data);
+       if(ret< 0)
+               printk("parse mpu dts failed\n");
 
        dev_info(&client->adapter->dev, "%s: %d\n", __func__, ii++);
 
@@ -1082,6 +1463,12 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
                res = -ENOMEM;
                goto out_alloc_data_failed;
        }
+       mpu6050_l = kzalloc(sizeof(*mpu6050_l), GFP_KERNEL);
+       if (!mpu6050_l) {
+               printk("failed to allocate device info data in mpu6050_init\n");
+               ret = -ENOMEM;
+               return ret;
+       }
        mldl_cfg = &mpu->mldl_cfg;
        mldl_cfg->mpu_ram       = &mpu->mpu_ram;
        mldl_cfg->mpu_gyro_cfg  = &mpu->mpu_gyro_cfg;
@@ -1098,7 +1485,6 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
        }
        mpu_private_data = mpu;
        i2c_set_clientdata(client, mpu);
-       this_client = client;   
        mpu->client = client;
 
        init_waitqueue_head(&mpu->mpu_event_wait);
@@ -1118,13 +1504,11 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
                        "Unable to register pm_notifier %d\n", res);
                goto out_register_pm_notifier_failed;
        }
-
-       pdata = (struct mpu_platform_data *)client->dev.platform_data;
-       if (!pdata) {
-               dev_WARN(&client->adapter->dev,
-                        "Missing platform data for mpu\n");
-       }
-       mldl_cfg->pdata = pdata;
+       mpu6050_l->wq = create_singlethread_workqueue("mpu6050_invensen");
+       INIT_DELAYED_WORK(&mpu6050_l->delay_work, mpu_get);
+       queue_delayed_work(mpu6050_l->wq, &mpu6050_l->delay_work, msecs_to_jiffies(3000));
+       
+       mldl_cfg->pdata = &mpu_data;
 
        mldl_cfg->mpu_chip_info->addr = client->addr;
        res = inv_mpu_open(&mpu->mldl_cfg, client->adapter, NULL, NULL, NULL);
@@ -1156,8 +1540,34 @@ int mpu_probe(struct i2c_client *client, const struct i2c_device_id *devid)
                dev_WARN(&client->adapter->dev,
                         "Missing %s IRQ\n", MPU_NAME);
        }
+       
+       if (!strcmp(mpu_id[1].name, devid->name)) {
+               /* Special case to re-use the inv_mpu_register_slave */
+               struct ext_slave_platform_data *slave_pdata;
+               slave_pdata = kzalloc(sizeof(*slave_pdata), GFP_KERNEL);
+               if (!slave_pdata) {
+                       res = -ENOMEM;
+                       goto out_slave_pdata_kzalloc_failed;
+               }
+               slave_pdata->bus = EXT_SLAVE_BUS_PRIMARY;
+               for (ii = 0; ii < 9; ii++)
+                       slave_pdata->orientation[ii] = mpu_data.orientation[ii];
+               res = inv_mpu_register_slave(
+                       NULL, client,
+                       slave_pdata,
+                       mpu6050_get_slave_descr);
+               if (res) {
+                       /* if inv_mpu_register_slave fails there are no pointer
+                          references to the memory allocated to slave_pdata */
+                       kfree(slave_pdata);
+                       goto out_slave_pdata_kzalloc_failed;
+               }
+       }
        return res;
 
+out_slave_pdata_kzalloc_failed:
+       if (client->irq)
+               mpuirq_exit();
 out_mpuirq_failed:
        misc_deregister(&mpu->dev);
 out_misc_register_failed:
@@ -1201,6 +1611,17 @@ static int mpu_remove(struct i2c_client *client)
                slave_adapter[EXT_SLAVE_TYPE_COMPASS],
                slave_adapter[EXT_SLAVE_TYPE_PRESSURE]);
 
+       if (mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL] &&
+               (mldl_cfg->slave[EXT_SLAVE_TYPE_ACCEL]->id ==
+                       ACCEL_ID_MPU6050)) {
+               struct ext_slave_platform_data *slave_pdata =
+                       mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL];
+               inv_mpu_unregister_slave(
+                       client,
+                       mldl_cfg->pdata_slave[EXT_SLAVE_TYPE_ACCEL],
+                       mpu6050_get_slave_descr);
+               kfree(slave_pdata);
+       }
 
        if (client->irq)
                mpuirq_exit();
@@ -1215,6 +1636,11 @@ static int mpu_remove(struct i2c_client *client)
        return 0;
 }
 
+static const struct of_device_id of_mpu_match[] = {
+       { .compatible = "mpu6050" },
+       { /* Sentinel */ }
+};
+
 static struct i2c_driver mpu_driver = {
        .class = I2C_CLASS_HWMON,
        .probe = mpu_probe,
@@ -1223,6 +1649,7 @@ static struct i2c_driver mpu_driver = {
        .driver = {
                   .owner = THIS_MODULE,
                   .name = MPU_NAME,
+                  .of_match_table      = of_mpu_match,
                   },
        .address_list = normal_i2c,
        .shutdown = mpu_shutdown,       /* optional */
@@ -1230,11 +1657,87 @@ static struct i2c_driver mpu_driver = {
        .resume = mpu_dev_resume,       /* optional */
 
 };
+static ssize_t gsensor_check_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", Is_cab);
+}
+
+static ssize_t gsensor_check_store(struct device *dev,
+               struct device_attribute *attr, char *buf,size_t count)
+{
+       switch (buf[0]) {
+       case '1':
+               Is_cab=true;
+               break;
+       case '0':
+               Is_cab=false;
+               break;
+       default:
+               Is_cab=false;
+               break;
+       }
+       return count;
+
+}
+static ssize_t gsensor_clear_store(struct device *dev,
+               struct device_attribute *attr, char *buf,size_t count)
+{
+//     char mtddevname[64];
+//     int  mtd_index;
+       memset(cablic_arry, 0x00, sizeof(cablic_arry));
+       gsensor_clear = 1;
+       return count;
+
+}
+
+static DEVICE_ATTR(gsensorcheck, 0666, gsensor_check_show, gsensor_check_store);
+static DEVICE_ATTR(gsensorclear, 0666, NULL, gsensor_clear_store);
+
+
+static int gsensor_sysfs_init(void)
+{
+       int ret ;
+
+       android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL);
+       if (android_gsensor_kobj == NULL) {
+               printk(KERN_ERR
+                      "mpu6050 gsensor_sysfs_init:"\
+                      "subsystem_register failed\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_gsensorclear.attr);   // "gsensorclear"
+       if (ret) {
+               printk(KERN_ERR
+                      "mpu6050 gsensor_sysfs_init: gsensorclear"\
+                      "sysfs_create_group failed\n");
+               goto err4;
+       }
+       ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_gsensorcheck.attr);
+       if (ret) {
+               printk(KERN_ERR
+                      "mpu6050 gsensor_sysfs_init:"\
+                      "sysfs_create_group failed\n");
+               goto err4;
+       }
+       return 0 ;
+err4:
+       kobject_del(android_gsensor_kobj);
+err:
+       return ret ;
+}
 
 static int __init mpu_init(void)
 {
        int res = i2c_add_driver(&mpu_driver);
        pr_info("%s: Probe name %s\n", __func__, MPU_NAME);
+       if (res)
+               pr_err("%s failed\n", __func__);
+
+       memset(cablic_arry, 0x00, sizeof(cablic_arry));
+       get_cablic=1;
+       res=gsensor_sysfs_init();
        if (res)
                pr_err("%s failed\n", __func__);
        return res;
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/drivers/misc/inv_mpu/mpu6050b1.h b/drivers/misc/inv_mpu/mpu6050b1.h
new file mode 100755 (executable)
index 0000000..686f6e5
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+       $License:
+       Copyright (C) 2011 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/>.
+       $
+ */
+
+/**
+ * @defgroup
+ * @brief
+ *
+ * @{
+ *      @file     mpu6050.h
+ *      @brief
+ */
+
+#ifndef __MPU_H_
+#error Do not include this file directly.  Include mpu.h instead.
+#endif
+
+#ifndef __MPU6050B1_H_
+#define __MPU6050B1_H_
+
+
+#define MPU_NAME "mpu6050B1"
+#define DEFAULT_MPU_SLAVEADDR          0x68
+
+/*==== MPU6050B1 REGISTER SET ====*/
+enum {
+       MPUREG_XG_OFFS_TC = 0,                  /* 0x00,   0 */
+       MPUREG_YG_OFFS_TC,                      /* 0x01,   1 */
+       MPUREG_ZG_OFFS_TC,                      /* 0x02,   2 */
+       MPUREG_X_FINE_GAIN,                     /* 0x03,   3 */
+       MPUREG_Y_FINE_GAIN,                     /* 0x04,   4 */
+       MPUREG_Z_FINE_GAIN,                     /* 0x05,   5 */
+       MPUREG_XA_OFFS_H,                       /* 0x06,   6 */
+       MPUREG_XA_OFFS_L,                       /* 0x07,   7 */
+       MPUREG_YA_OFFS_H,                       /* 0x08,   8 */
+       MPUREG_YA_OFFS_L,                       /* 0x09,   9 */
+       MPUREG_ZA_OFFS_H,                       /* 0x0a,  10 */
+       MPUREG_ZA_OFFS_L,                       /* 0x0B,  11 */
+       MPUREG_PRODUCT_ID,                      /* 0x0c,  12 */
+       MPUREG_0D_RSVD,                         /* 0x0d,  13 */
+       MPUREG_0E_RSVD,                         /* 0x0e,  14 */
+       MPUREG_0F_RSVD,                         /* 0x0f,  15 */
+       MPUREG_10_RSVD,                         /* 0x00,  16 */
+       MPUREG_11_RSVD,                         /* 0x11,  17 */
+       MPUREG_12_RSVD,                         /* 0x12,  18 */
+       MPUREG_XG_OFFS_USRH,                    /* 0x13,  19 */
+       MPUREG_XG_OFFS_USRL,                    /* 0x14,  20 */
+       MPUREG_YG_OFFS_USRH,                    /* 0x15,  21 */
+       MPUREG_YG_OFFS_USRL,                    /* 0x16,  22 */
+       MPUREG_ZG_OFFS_USRH,                    /* 0x17,  23 */
+       MPUREG_ZG_OFFS_USRL,                    /* 0x18,  24 */
+       MPUREG_SMPLRT_DIV,                      /* 0x19,  25 */
+       MPUREG_CONFIG,                          /* 0x1A,  26 */
+       MPUREG_GYRO_CONFIG,                     /* 0x1b,  27 */
+       MPUREG_ACCEL_CONFIG,                    /* 0x1c,  28 */
+       MPUREG_ACCEL_FF_THR,                    /* 0x1d,  29 */
+       MPUREG_ACCEL_FF_DUR,                    /* 0x1e,  30 */
+       MPUREG_ACCEL_MOT_THR,                   /* 0x1f,  31 */
+       MPUREG_ACCEL_MOT_DUR,                   /* 0x20,  32 */
+       MPUREG_ACCEL_ZRMOT_THR,                 /* 0x21,  33 */
+       MPUREG_ACCEL_ZRMOT_DUR,                 /* 0x22,  34 */
+       MPUREG_FIFO_EN,                         /* 0x23,  35 */
+       MPUREG_I2C_MST_CTRL,                    /* 0x24,  36 */
+       MPUREG_I2C_SLV0_ADDR,                   /* 0x25,  37 */
+       MPUREG_I2C_SLV0_REG,                    /* 0x26,  38 */
+       MPUREG_I2C_SLV0_CTRL,                   /* 0x27,  39 */
+       MPUREG_I2C_SLV1_ADDR,                   /* 0x28,  40 */
+       MPUREG_I2C_SLV1_REG,                    /* 0x29,  41 */
+       MPUREG_I2C_SLV1_CTRL,                   /* 0x2a,  42 */
+       MPUREG_I2C_SLV2_ADDR,                   /* 0x2B,  43 */
+       MPUREG_I2C_SLV2_REG,                    /* 0x2c,  44 */
+       MPUREG_I2C_SLV2_CTRL,                   /* 0x2d,  45 */
+       MPUREG_I2C_SLV3_ADDR,                   /* 0x2E,  46 */
+       MPUREG_I2C_SLV3_REG,                    /* 0x2f,  47 */
+       MPUREG_I2C_SLV3_CTRL,                   /* 0x30,  48 */
+       MPUREG_I2C_SLV4_ADDR,                   /* 0x31,  49 */
+       MPUREG_I2C_SLV4_REG,                    /* 0x32,  50 */
+       MPUREG_I2C_SLV4_DO,                     /* 0x33,  51 */
+       MPUREG_I2C_SLV4_CTRL,                   /* 0x34,  52 */
+       MPUREG_I2C_SLV4_DI,                     /* 0x35,  53 */
+       MPUREG_I2C_MST_STATUS,                  /* 0x36,  54 */
+       MPUREG_INT_PIN_CFG,                     /* 0x37,  55 */
+       MPUREG_INT_ENABLE,                      /* 0x38,  56 */
+       MPUREG_DMP_INT_STATUS,                  /* 0x39,  57 */
+       MPUREG_INT_STATUS,                      /* 0x3A,  58 */
+       MPUREG_ACCEL_XOUT_H,                    /* 0x3B,  59 */
+       MPUREG_ACCEL_XOUT_L,                    /* 0x3c,  60 */
+       MPUREG_ACCEL_YOUT_H,                    /* 0x3d,  61 */
+       MPUREG_ACCEL_YOUT_L,                    /* 0x3e,  62 */
+       MPUREG_ACCEL_ZOUT_H,                    /* 0x3f,  63 */
+       MPUREG_ACCEL_ZOUT_L,                    /* 0x40,  64 */
+       MPUREG_TEMP_OUT_H,                      /* 0x41,  65 */
+       MPUREG_TEMP_OUT_L,                      /* 0x42,  66 */
+       MPUREG_GYRO_XOUT_H,                     /* 0x43,  67 */
+       MPUREG_GYRO_XOUT_L,                     /* 0x44,  68 */
+       MPUREG_GYRO_YOUT_H,                     /* 0x45,  69 */
+       MPUREG_GYRO_YOUT_L,                     /* 0x46,  70 */
+       MPUREG_GYRO_ZOUT_H,                     /* 0x47,  71 */
+       MPUREG_GYRO_ZOUT_L,                     /* 0x48,  72 */
+       MPUREG_EXT_SLV_SENS_DATA_00,            /* 0x49,  73 */
+       MPUREG_EXT_SLV_SENS_DATA_01,            /* 0x4a,  74 */
+       MPUREG_EXT_SLV_SENS_DATA_02,            /* 0x4b,  75 */
+       MPUREG_EXT_SLV_SENS_DATA_03,            /* 0x4c,  76 */
+       MPUREG_EXT_SLV_SENS_DATA_04,            /* 0x4d,  77 */
+       MPUREG_EXT_SLV_SENS_DATA_05,            /* 0x4e,  78 */
+       MPUREG_EXT_SLV_SENS_DATA_06,            /* 0x4F,  79 */
+       MPUREG_EXT_SLV_SENS_DATA_07,            /* 0x50,  80 */
+       MPUREG_EXT_SLV_SENS_DATA_08,            /* 0x51,  81 */
+       MPUREG_EXT_SLV_SENS_DATA_09,            /* 0x52,  82 */
+       MPUREG_EXT_SLV_SENS_DATA_10,            /* 0x53,  83 */
+       MPUREG_EXT_SLV_SENS_DATA_11,            /* 0x54,  84 */
+       MPUREG_EXT_SLV_SENS_DATA_12,            /* 0x55,  85 */
+       MPUREG_EXT_SLV_SENS_DATA_13,            /* 0x56,  86 */
+       MPUREG_EXT_SLV_SENS_DATA_14,            /* 0x57,  87 */
+       MPUREG_EXT_SLV_SENS_DATA_15,            /* 0x58,  88 */
+       MPUREG_EXT_SLV_SENS_DATA_16,            /* 0x59,  89 */
+       MPUREG_EXT_SLV_SENS_DATA_17,            /* 0x5a,  90 */
+       MPUREG_EXT_SLV_SENS_DATA_18,            /* 0x5B,  91 */
+       MPUREG_EXT_SLV_SENS_DATA_19,            /* 0x5c,  92 */
+       MPUREG_EXT_SLV_SENS_DATA_20,            /* 0x5d,  93 */
+       MPUREG_EXT_SLV_SENS_DATA_21,            /* 0x5e,  94 */
+       MPUREG_EXT_SLV_SENS_DATA_22,            /* 0x5f,  95 */
+       MPUREG_EXT_SLV_SENS_DATA_23,            /* 0x60,  96 */
+       MPUREG_ACCEL_INTEL_STATUS,              /* 0x61,  97 */
+       MPUREG_62_RSVD,                         /* 0x62,  98 */
+       MPUREG_I2C_SLV0_DO,                     /* 0x63,  99 */
+       MPUREG_I2C_SLV1_DO,                     /* 0x64, 100 */
+       MPUREG_I2C_SLV2_DO,                     /* 0x65, 101 */
+       MPUREG_I2C_SLV3_DO,                     /* 0x66, 102 */
+       MPUREG_I2C_MST_DELAY_CTRL,              /* 0x67, 103 */
+       MPUREG_SIGNAL_PATH_RESET,               /* 0x68, 104 */
+       MPUREG_ACCEL_INTEL_CTRL,                /* 0x69, 105 */
+       MPUREG_USER_CTRL,                       /* 0x6A, 106 */
+       MPUREG_PWR_MGMT_1,                      /* 0x6B, 107 */
+       MPUREG_PWR_MGMT_2,                      /* 0x6C, 108 */
+       MPUREG_BANK_SEL,                        /* 0x6D, 109 */
+       MPUREG_MEM_START_ADDR,                  /* 0x6E, 100 */
+       MPUREG_MEM_R_W,                         /* 0x6F, 111 */
+       MPUREG_DMP_CFG_1,                       /* 0x70, 112 */
+       MPUREG_DMP_CFG_2,                       /* 0x71, 113 */
+       MPUREG_FIFO_COUNTH,                     /* 0x72, 114 */
+       MPUREG_FIFO_COUNTL,                     /* 0x73, 115 */
+       MPUREG_FIFO_R_W,                        /* 0x74, 116 */
+       MPUREG_WHOAMI,                          /* 0x75, 117 */
+
+       NUM_OF_MPU_REGISTERS                    /* = 0x76, 118 */
+};
+
+/*==== MPU6050B1 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
+};
+
+
+/*==== MPU6050B1 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 MPU6050B1 ====*/
+/*---- MPU6050B1 'XG_OFFS_TC' register (0, 1, 2) ----*/
+#define BIT_PU_SLEEP_MODE                      0x80
+#define BITS_XG_OFFS_TC                                0x7E
+#define BIT_OTP_BNK_VLD                                0x01
+
+#define BIT_I2C_MST_VDDIO                      0x80
+#define BITS_YG_OFFS_TC                                0x7E
+#define BITS_ZG_OFFS_TC                                0x7E
+/*---- MPU6050B1 '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
+/*---- MPU6050B1 'CONFIG' register (1A) ----*/
+/*NONE                                         0xC0 */
+#define        BITS_EXT_SYNC_SET                       0x38
+#define        BITS_DLPF_CFG                           0x07
+/*---- MPU6050B1 '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 */
+/*---- MPU6050B1 'ACCEL_CONFIG' register (1C) ----*/
+#define BITS_ACCEL_FS_SEL                      0x18
+#define BITS_ACCEL_HPF                         0x07
+/*---- MPU6050B1 'I2C_MST_CTRL' register (24) ----*/
+#define BIT_MULT_MST_EN                                0x80
+#define BIT_WAIT_FOR_ES                                0x40
+#define BIT_SLV_3_FIFO_EN                      0x20
+#define BIT_I2C_MST_PSR                                0x10
+#define BITS_I2C_MST_CLK                       0x0F
+/*---- MPU6050B1 'I2C_SLV?_ADDR' register (27,2A,2D,30) ----*/
+#define BIT_I2C_READ                           0x80
+#define BIT_I2C_WRITE                          0x00
+#define BITS_I2C_ADDR                          0x7F
+/*---- MPU6050B1 'I2C_SLV?_CTRL' register (27,2A,2D,30) ----*/
+#define BIT_SLV_ENABLE                         0x80
+#define BIT_SLV_BYTE_SW                                0x40
+#define BIT_SLV_REG_DIS                                0x20
+#define BIT_SLV_GRP                            0x10
+#define BITS_SLV_LENG                          0x0F
+/*---- MPU6050B1 'I2C_SLV4_ADDR' register (31) ----*/
+#define BIT_I2C_SLV4_RNW                       0x80
+/*---- MPU6050B1 'I2C_SLV4_CTRL' register (34) ----*/
+#define BIT_I2C_SLV4_EN                                0x80
+#define BIT_SLV4_DONE_INT_EN                   0x40
+#define BIT_SLV4_REG_DIS                       0x20
+#define MASK_I2C_MST_DLY                       0x1F
+/*---- MPU6050B1 'I2C_MST_STATUS' register (36) ----*/
+#define BIT_PASS_THROUGH                       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
+/*---- MPU6050B1 '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
+/*---- MPU6050B1 '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
+/*---- MPU6050B1 '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
+/*---- MPU6050B1 '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
+/*---- MPU6050B1 'MPUREG_I2C_MST_DELAY_CTRL' register (0x67) ----*/
+#define        BIT_DELAY_ES_SHADOW                     0x80
+#define        BIT_SLV4_DLY_EN                         0x10
+#define        BIT_SLV3_DLY_EN                         0x08
+#define        BIT_SLV2_DLY_EN                         0x04
+#define        BIT_SLV1_DLY_EN                         0x02
+#define        BIT_SLV0_DLY_EN                         0x01
+/*---- MPU6050B1 'BANK_SEL' register (6D) ----*/
+#define        BIT_PRFTCH_EN                           0x40
+#define        BIT_CFG_USER_BANK                       0x20
+#define        BITS_MEM_SEL                            0x1f
+/*---- MPU6050B1 '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
+/*---- MPU6050B1 'PWR_MGMT_1' register (6B) ----*/
+#define        BIT_H_RESET                             0x80
+#define        BIT_SLEEP                               0x40
+#define        BIT_CYCLE                               0x20
+#define BIT_PD_PTAT                            0x08
+#define BITS_CLKSEL                            0x07
+/*---- MPU6050B1 'PWR_MGMT_2' register (6C) ----*/
+#define        BITS_LPA_WAKE_CTRL                      0xC0
+#define        BITS_LPA_WAKE_1HZ                       0x00
+#define        BITS_LPA_WAKE_2HZ                       0x40
+#define        BITS_LPA_WAKE_10HZ                      0x80
+#define        BITS_LPA_WAKE_40HZ                      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
+
+#define ACCEL_MOT_THR_LSB (32) /* mg */
+#define ACCEL_MOT_DUR_LSB (1)
+#define ACCEL_ZRMOT_THR_LSB_CONVERSION(mg) ((mg * 1000) / 255)
+#define ACCEL_ZRMOT_DUR_LSB (64)
+
+/*----------------------------------------------------------------------------*/
+/*---- Alternative names to take care of conflicts with current mpu3050.h ----*/
+/*----------------------------------------------------------------------------*/
+
+/*-- registers --*/
+#define MPUREG_DLPF_FS_SYNC    MPUREG_CONFIG                   /* 0x1A */
+
+#define MPUREG_PWR_MGM         MPUREG_PWR_MGMT_1               /* 0x6B */
+#define MPUREG_FIFO_EN1                MPUREG_FIFO_EN                  /* 0x23 */
+#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 */
+
+/*-- 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
+
+/*---- MPU6050 Silicon Revisions ----*/
+#define MPU_SILICON_REV_A2             1       /* MPU6050A2 Device */
+#define MPU_SILICON_REV_B1             2       /* MPU6050B1 Device */
+
+/*---- MPU6050 notable product revisions ----*/
+#define MPU_PRODUCT_KEY_B1_E1_5                105
+#define MPU_PRODUCT_KEY_B2_F1          431
+
+/*---- 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 MPUREG_CONFIG_VALUE(ext_sync, lpf) \
+       ((ext_sync << 3) | lpf)
+
+#define MPUREG_GYRO_CONFIG_VALUE(x_st, y_st, z_st, full_scale) \
+       ((x_st ? 0x80 : 0) |                            \
+        (y_st ? 0x70 : 0) |                            \
+        (z_st ? 0x60 : 0) |                            \
+        (full_scale << 3))
+
+#endif                         /* __MPU6050_H_ */
index 8bfddc87a04ef75df4e1a23d5e9dd58237a8585a..59baa0671660661f685da26c41eb85da90804ac8 100755 (executable)
@@ -36,7 +36,7 @@
 #include <linux/wait.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
+
 #include <linux/mpu.h>
 #include "mpuirq.h"
 #include "mldl_cfg.h"
@@ -202,8 +202,8 @@ int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg)
 
        dev_info(&mpu_client->adapter->dev,
                 "Module Param interface = %s\n", interface);
-       
-       mpuirq_dev_data.irq = gpio_to_irq(mpu_client->irq);
+
+       mpuirq_dev_data.irq = mpu_client->irq;
        mpuirq_dev_data.pid = 0;
        mpuirq_dev_data.accel_divider = -1;
        mpuirq_dev_data.data_ready = 0;
@@ -217,10 +217,12 @@ int mpuirq_init(struct i2c_client *mpu_client, struct mldl_cfg *mldl_cfg)
                else
                        flags = IRQF_TRIGGER_RISING;
 
-               flags |= IRQF_SHARED;
-               res =
-                   request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags,
-                               interface, &mpuirq_dev_data.irq);
+               flags =IRQF_TRIGGER_RISING;//|= IRQF_SHARED;
+
+               res =devm_request_threaded_irq(&mpu_client->dev, mpuirq_dev_data.irq, NULL, mpuirq_handler, flags|IRQF_ONESHOT, interface, &mpuirq_dev_data.irq);
+               //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",
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 601858f9c4d5be609ecfb6b2e05064dd3ad42e3f..5aeb7602c5cc7d3edd7622959dce1f79d43e8a37 100755 (executable)
@@ -71,7 +71,7 @@ static void timerirq_handler(unsigned long arg)
        data->data.irqtime = (((long long)irqtime.tv_sec) << 32);
        data->data.irqtime += irqtime.tv_usec;
        data->data.data_type |= 1;
-
+       
        dev_dbg(data->dev->this_device,
                "%s, %lld, %ld\n", __func__, data->data.irqtime,
                (unsigned long)data);
@@ -207,6 +207,7 @@ static long timerirq_ioctl(struct file *file,
                "%s current->pid %d, %d, %ld\n",
                __func__, current->pid, cmd, arg);
 
+       
        if (!data)
                return -EFAULT;
 
old mode 100644 (file)
new mode 100755 (executable)
index 00d9e6c624054302f44f0fb3d37499a87a056a57..1e4ecd56b66ac69fa60df71a9b2cba5551700d4e 100755 (executable)
@@ -153,6 +153,7 @@ enum ext_slave_id {
 
        COMPASS_ID_AK8975,
        COMPASS_ID_AK8972,
+       COMPASS_ID_AK8963,
        COMPASS_ID_AMI30X,
        COMPASS_ID_AMI306,
        COMPASS_ID_YAS529,
@@ -161,6 +162,7 @@ enum ext_slave_id {
        COMPASS_ID_LSM303DLH,
        COMPASS_ID_LSM303DLM,
        COMPASS_ID_MMC314X,
+       COMPASS_ID_MMC328X,
        COMPASS_ID_HSCDTD002B,
        COMPASS_ID_HSCDTD004A,
 
@@ -300,8 +302,8 @@ struct ext_slave_descr {
  * column should have exactly 1 non-zero value.
  */
 struct mpu_platform_data {
-       __u8 int_config;
-       __u8 level_shifter;
+       __u32 int_config;
+       __u32 level_shifter;
        __s8 orientation[GYRO_NUM_AXES * GYRO_NUM_AXES];
 };