From 68b6dfca6b373919c49fdffd43bdead020868f2f Mon Sep 17 00:00:00 2001 From: ywj Date: Fri, 4 Apr 2014 10:52:17 +0800 Subject: [PATCH] on 977 add mpu config and update mpu code --- arch/arm/boot/dts/rk3288-p977.dts | 46 +- drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/inv_mpu/Kconfig | 1 + drivers/misc/inv_mpu/Makefile | 0 drivers/misc/inv_mpu/README | 0 drivers/misc/inv_mpu/accel/Kconfig | 0 drivers/misc/inv_mpu/accel/Makefile | 0 drivers/misc/inv_mpu/accel/adxl34x.c | 0 drivers/misc/inv_mpu/accel/bma150.c | 4 +- drivers/misc/inv_mpu/accel/bma222.c | 16 +- drivers/misc/inv_mpu/accel/bma250.c | 0 drivers/misc/inv_mpu/accel/cma3000.c | 0 drivers/misc/inv_mpu/accel/kxsd9.c | 0 drivers/misc/inv_mpu/accel/lis331.c | 0 drivers/misc/inv_mpu/accel/lis3dh.c | 0 drivers/misc/inv_mpu/accel/lsm303dlx_a.c | 0 drivers/misc/inv_mpu/accel/mma8450.c | 0 drivers/misc/inv_mpu/accel/mma845x.c | 0 drivers/misc/inv_mpu/accel/mpu6050.c | 699 +++++++++++++ drivers/misc/inv_mpu/accel/mpu6050.h | 0 drivers/misc/inv_mpu/compass/Kconfig | 9 + drivers/misc/inv_mpu/compass/Makefile | 2 + drivers/misc/inv_mpu/compass/ak8963.c | 648 ++++++++++++ drivers/misc/inv_mpu/compass/ak8972.c | 0 drivers/misc/inv_mpu/compass/ak8975.c | 139 ++- drivers/misc/inv_mpu/compass/ami306.c | 0 drivers/misc/inv_mpu/compass/ami30x.c | 0 drivers/misc/inv_mpu/compass/ami_hw.h | 0 drivers/misc/inv_mpu/compass/ami_sensor_def.h | 0 drivers/misc/inv_mpu/compass/hmc5883.c | 0 drivers/misc/inv_mpu/compass/hscdtd002b.c | 0 drivers/misc/inv_mpu/compass/hscdtd004a.c | 0 drivers/misc/inv_mpu/compass/lsm303dlx_m.c | 0 drivers/misc/inv_mpu/compass/mmc314x.c | 0 drivers/misc/inv_mpu/compass/yas529-kernel.c | 0 drivers/misc/inv_mpu/compass/yas530.c | 0 drivers/misc/inv_mpu/log.h | 0 drivers/misc/inv_mpu/mldl_cfg.c | 940 +++++++++++------- drivers/misc/inv_mpu/mldl_cfg.h | 2 +- drivers/misc/inv_mpu/mldl_print_cfg.c | 21 +- drivers/misc/inv_mpu/mldl_print_cfg.h | 0 drivers/misc/inv_mpu/mlsl-kernel.c | 26 +- drivers/misc/inv_mpu/mlsl.h | 0 drivers/misc/inv_mpu/mltypes.h | 0 drivers/misc/inv_mpu/mpu-dev.c | 563 ++++++++++- drivers/misc/inv_mpu/mpu-dev.h | 0 drivers/misc/inv_mpu/mpu3050.h | 0 drivers/misc/inv_mpu/mpu6050b1.h | 435 ++++++++ drivers/misc/inv_mpu/mpuirq.c | 16 +- drivers/misc/inv_mpu/mpuirq.h | 0 drivers/misc/inv_mpu/pressure/Kconfig | 0 drivers/misc/inv_mpu/pressure/Makefile | 0 drivers/misc/inv_mpu/pressure/bma085.c | 0 drivers/misc/inv_mpu/slaveirq.h | 0 drivers/misc/inv_mpu/timerirq.c | 3 +- drivers/misc/inv_mpu/timerirq.h | 0 include/linux/mpu.h | 6 +- 58 files changed, 3118 insertions(+), 460 deletions(-) mode change 100644 => 100755 drivers/misc/Kconfig mode change 100644 => 100755 drivers/misc/Makefile mode change 100644 => 100755 drivers/misc/inv_mpu/Kconfig mode change 100644 => 100755 drivers/misc/inv_mpu/Makefile mode change 100644 => 100755 drivers/misc/inv_mpu/README mode change 100644 => 100755 drivers/misc/inv_mpu/accel/Kconfig mode change 100644 => 100755 drivers/misc/inv_mpu/accel/Makefile mode change 100644 => 100755 drivers/misc/inv_mpu/accel/adxl34x.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/bma150.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/bma222.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/bma250.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/cma3000.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/kxsd9.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/lis331.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/lis3dh.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/lsm303dlx_a.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/mma8450.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/mma845x.c create mode 100755 drivers/misc/inv_mpu/accel/mpu6050.c mode change 100644 => 100755 drivers/misc/inv_mpu/accel/mpu6050.h mode change 100644 => 100755 drivers/misc/inv_mpu/compass/Kconfig mode change 100644 => 100755 drivers/misc/inv_mpu/compass/Makefile create mode 100755 drivers/misc/inv_mpu/compass/ak8963.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/ak8972.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/ami306.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/ami30x.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/ami_hw.h mode change 100644 => 100755 drivers/misc/inv_mpu/compass/ami_sensor_def.h mode change 100644 => 100755 drivers/misc/inv_mpu/compass/hmc5883.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/hscdtd002b.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/hscdtd004a.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/lsm303dlx_m.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/mmc314x.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/yas529-kernel.c mode change 100644 => 100755 drivers/misc/inv_mpu/compass/yas530.c mode change 100644 => 100755 drivers/misc/inv_mpu/log.h mode change 100644 => 100755 drivers/misc/inv_mpu/mldl_cfg.h mode change 100644 => 100755 drivers/misc/inv_mpu/mldl_print_cfg.c mode change 100644 => 100755 drivers/misc/inv_mpu/mldl_print_cfg.h mode change 100644 => 100755 drivers/misc/inv_mpu/mlsl.h mode change 100644 => 100755 drivers/misc/inv_mpu/mltypes.h mode change 100644 => 100755 drivers/misc/inv_mpu/mpu-dev.h mode change 100644 => 100755 drivers/misc/inv_mpu/mpu3050.h create mode 100755 drivers/misc/inv_mpu/mpu6050b1.h mode change 100644 => 100755 drivers/misc/inv_mpu/mpuirq.h mode change 100644 => 100755 drivers/misc/inv_mpu/pressure/Kconfig mode change 100644 => 100755 drivers/misc/inv_mpu/pressure/Makefile mode change 100644 => 100755 drivers/misc/inv_mpu/pressure/bma085.c mode change 100644 => 100755 drivers/misc/inv_mpu/slaveirq.h mode change 100644 => 100755 drivers/misc/inv_mpu/timerirq.h diff --git a/arch/arm/boot/dts/rk3288-p977.dts b/arch/arm/boot/dts/rk3288-p977.dts index eb9a2627e781..871c5de0b476 100755 --- a/arch/arm/boot/dts/rk3288-p977.dts +++ b/arch/arm/boot/dts/rk3288-p977.dts @@ -303,7 +303,7 @@ compatible = "nxp,pcf8563"; reg = <0x51>; }; - +/* sensor@1d { compatible = "gs_mma8452"; reg = <0x1d>; @@ -312,7 +312,9 @@ irq_enable = <1>; poll_delay_ms = <30>; layout = <8>; + status = "disabled"; }; + sensor@0d { compatible = "ak8975"; reg = <0x0d>; @@ -321,7 +323,9 @@ irq_enable = <1>; poll_delay_ms = <30>; layout = <1>; + status = "disabled"; }; +*/ sensor@10 { compatible = "ls_cm3218"; reg = <0x10>; @@ -331,7 +335,45 @@ 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 { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig old mode 100644 new mode 100755 index 3f5743424ff7..b3bf720d02a1 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -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" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile old mode 100644 new mode 100755 index a57666cec342..2e082e308588 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -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 diff --git a/drivers/misc/inv_mpu/Kconfig b/drivers/misc/inv_mpu/Kconfig old mode 100644 new mode 100755 index 43f8881192bf..864363062e01 --- a/drivers/misc/inv_mpu/Kconfig +++ b/drivers/misc/inv_mpu/Kconfig @@ -9,6 +9,7 @@ config MPU_SENSORS_TIMERIRQ menuconfig: INV_SENSORS tristate "Motion Processing Unit" depends on I2C + default n if INV_SENSORS diff --git a/drivers/misc/inv_mpu/Makefile b/drivers/misc/inv_mpu/Makefile old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/README b/drivers/misc/inv_mpu/README old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/Kconfig b/drivers/misc/inv_mpu/accel/Kconfig old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/Makefile b/drivers/misc/inv_mpu/accel/Makefile old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/adxl34x.c b/drivers/misc/inv_mpu/accel/adxl34x.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/bma150.c b/drivers/misc/inv_mpu/accel/bma150.c old mode 100644 new mode 100755 index fd2d7b5dd1c3..745d90a6744f --- a/drivers/misc/inv_mpu/accel/bma150.c +++ b/drivers/misc/inv_mpu/accel/bma150.c @@ -25,7 +25,7 @@ * @file bma150.c * @brief Accelerometer setup and handling methods for Bosch BMA150. */ -#define DEBUG + /* -------------------------------------------------------------------------- */ #include #include @@ -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; diff --git a/drivers/misc/inv_mpu/accel/bma222.c b/drivers/misc/inv_mpu/accel/bma222.c old mode 100644 new mode 100755 index e9cfb676c5d9..a8e14bd654da --- a/drivers/misc/inv_mpu/accel/bma222.c +++ b/drivers/misc/inv_mpu/accel/bma222.c @@ -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)) { diff --git a/drivers/misc/inv_mpu/accel/bma250.c b/drivers/misc/inv_mpu/accel/bma250.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/cma3000.c b/drivers/misc/inv_mpu/accel/cma3000.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/kxsd9.c b/drivers/misc/inv_mpu/accel/kxsd9.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/lis331.c b/drivers/misc/inv_mpu/accel/lis331.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/lis3dh.c b/drivers/misc/inv_mpu/accel/lis3dh.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/lsm303dlx_a.c b/drivers/misc/inv_mpu/accel/lsm303dlx_a.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/mma8450.c b/drivers/misc/inv_mpu/accel/mma8450.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/mma845x.c b/drivers/misc/inv_mpu/accel/mma845x.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/accel/mpu6050.c b/drivers/misc/inv_mpu/accel/mpu6050.c new file mode 100755 index 000000000000..efb6627f50e3 --- /dev/null +++ b/drivers/misc/inv_mpu/accel/mpu6050.c @@ -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 . + $ + */ + +/** + * @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 +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#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, ®); + 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, ®); + 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, ®); + 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, ®); + 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; +} + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/accel/mpu6050.h b/drivers/misc/inv_mpu/accel/mpu6050.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/Kconfig b/drivers/misc/inv_mpu/compass/Kconfig old mode 100644 new mode 100755 index 6c4c13a6e19a..2830d320a6e7 --- a/drivers/misc/inv_mpu/compass/Kconfig +++ b/drivers/misc/inv_mpu/compass/Kconfig @@ -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 diff --git a/drivers/misc/inv_mpu/compass/Makefile b/drivers/misc/inv_mpu/compass/Makefile old mode 100644 new mode 100755 index aa8aa6a2657b..08d35481c002 --- a/drivers/misc/inv_mpu/compass/Makefile +++ b/drivers/misc/inv_mpu/compass/Makefile @@ -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 index 000000000000..ced3789b6d25 --- /dev/null +++ b/drivers/misc/inv_mpu/compass/ak8963.c @@ -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 . + $ + */ + +/** + * @addtogroup COMPASSDL + * + * @{ + * @file ak8963.c + * @brief Magnetometer setup and handling methods for the AKM AK8963, + * AKM AK8963B, and AKM AK8963C compass devices. + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include "mpu-dev.h" + +#include +#include +#include "mlsl.h" +#include "mldl_cfg.h" +#undef MPL_LOG_TAG +#define MPL_LOG_TAG "MPL-compass" +#include +#include + +//#include +//#include +//#include + +/* -------------------------------------------------------------------------- */ +#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 = ®s[0]; + unsigned char *stat2 = ®s[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, ®s[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;iorientation[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"); + +/** + * @} + */ diff --git a/drivers/misc/inv_mpu/compass/ak8972.c b/drivers/misc/inv_mpu/compass/ak8972.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/ak8975.c b/drivers/misc/inv_mpu/compass/ak8975.c index 9a67d7c1e397..e6f5b4a344da 100755 --- a/drivers/misc/inv_mpu/compass/ak8975.c +++ b/drivers/misc/inv_mpu/compass/ak8975.c @@ -27,7 +27,6 @@ */ /* -------------------------------------------------------------------------- */ -#define DEBUG #include #include @@ -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;iorientation[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, }; diff --git a/drivers/misc/inv_mpu/compass/ami306.c b/drivers/misc/inv_mpu/compass/ami306.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/ami30x.c b/drivers/misc/inv_mpu/compass/ami30x.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/ami_hw.h b/drivers/misc/inv_mpu/compass/ami_hw.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/ami_sensor_def.h b/drivers/misc/inv_mpu/compass/ami_sensor_def.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/hmc5883.c b/drivers/misc/inv_mpu/compass/hmc5883.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/hscdtd002b.c b/drivers/misc/inv_mpu/compass/hscdtd002b.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/hscdtd004a.c b/drivers/misc/inv_mpu/compass/hscdtd004a.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/lsm303dlx_m.c b/drivers/misc/inv_mpu/compass/lsm303dlx_m.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/mmc314x.c b/drivers/misc/inv_mpu/compass/mmc314x.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/yas529-kernel.c b/drivers/misc/inv_mpu/compass/yas529-kernel.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/compass/yas530.c b/drivers/misc/inv_mpu/compass/yas530.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/log.h b/drivers/misc/inv_mpu/log.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/mldl_cfg.c b/drivers/misc/inv_mpu/mldl_cfg.c index 155f4a980b25..e49305cb0586 100755 --- a/drivers/misc/inv_mpu/mldl_cfg.c +++ b/drivers/misc/inv_mpu/mldl_cfg.c @@ -33,7 +33,7 @@ #include "mldl_cfg.h" #include -#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, ®); 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, ®val); + MPUREG_YG_OFFS_TC, 1, ®val); 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, ®); + 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, ®); - 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, ®); + 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; diff --git a/drivers/misc/inv_mpu/mldl_cfg.h b/drivers/misc/inv_mpu/mldl_cfg.h old mode 100644 new mode 100755 index 1c23878940b7..a12fcc528135 --- a/drivers/misc/inv_mpu/mldl_cfg.h +++ b/drivers/misc/inv_mpu/mldl_cfg.h @@ -31,7 +31,7 @@ #include "mltypes.h" #include "mlsl.h" #include -#include "mpu3050.h" +#include "mpu6050b1.h" #include "log.h" diff --git a/drivers/misc/inv_mpu/mldl_print_cfg.c b/drivers/misc/inv_mpu/mldl_print_cfg.c old mode 100644 new mode 100755 index 5c6951b69823..79f8f455735f --- a/drivers/misc/inv_mpu/mldl_print_cfg.c +++ b/drivers/misc/inv_mpu/mldl_print_cfg.c @@ -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", diff --git a/drivers/misc/inv_mpu/mldl_print_cfg.h b/drivers/misc/inv_mpu/mldl_print_cfg.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/mlsl-kernel.c b/drivers/misc/inv_mpu/mlsl-kernel.c index 7fef66f50baa..a50cd20f9266 100755 --- a/drivers/misc/inv_mpu/mlsl-kernel.c +++ b/drivers/misc/inv_mpu/mlsl-kernel.c @@ -20,7 +20,7 @@ #include "mlsl.h" #include #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, diff --git a/drivers/misc/inv_mpu/mlsl.h b/drivers/misc/inv_mpu/mlsl.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/mltypes.h b/drivers/misc/inv_mpu/mltypes.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/mpu-dev.c b/drivers/misc/inv_mpu/mpu-dev.c index 3c54d55811ef..db440a6253a5 100755 --- a/drivers/misc/inv_mpu/mpu-dev.c +++ b/drivers/misc/inv_mpu/mpu-dev.c @@ -16,7 +16,6 @@ along with this program. If not, see . $ */ -#define DEBUG #include #include #include @@ -50,6 +49,66 @@ #include "mldl_cfg.h" #include +#include "accel/mpu6050.h" + +#include +#include +#include + +#include +#include +#include +#include + + + + + +#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;iorientation[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; diff --git a/drivers/misc/inv_mpu/mpu-dev.h b/drivers/misc/inv_mpu/mpu-dev.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/mpu3050.h b/drivers/misc/inv_mpu/mpu3050.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/mpu6050b1.h b/drivers/misc/inv_mpu/mpu6050b1.h new file mode 100755 index 000000000000..686f6e5d86a5 --- /dev/null +++ b/drivers/misc/inv_mpu/mpu6050b1.h @@ -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 . + $ + */ + +/** + * @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_ */ diff --git a/drivers/misc/inv_mpu/mpuirq.c b/drivers/misc/inv_mpu/mpuirq.c index 8bfddc87a04e..59baa0671660 100755 --- a/drivers/misc/inv_mpu/mpuirq.c +++ b/drivers/misc/inv_mpu/mpuirq.c @@ -36,7 +36,7 @@ #include #include #include -#include + #include #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", diff --git a/drivers/misc/inv_mpu/mpuirq.h b/drivers/misc/inv_mpu/mpuirq.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/pressure/Kconfig b/drivers/misc/inv_mpu/pressure/Kconfig old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/pressure/Makefile b/drivers/misc/inv_mpu/pressure/Makefile old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/pressure/bma085.c b/drivers/misc/inv_mpu/pressure/bma085.c old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/slaveirq.h b/drivers/misc/inv_mpu/slaveirq.h old mode 100644 new mode 100755 diff --git a/drivers/misc/inv_mpu/timerirq.c b/drivers/misc/inv_mpu/timerirq.c index 601858f9c4d5..5aeb7602c5cc 100755 --- a/drivers/misc/inv_mpu/timerirq.c +++ b/drivers/misc/inv_mpu/timerirq.c @@ -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; diff --git a/drivers/misc/inv_mpu/timerirq.h b/drivers/misc/inv_mpu/timerirq.h old mode 100644 new mode 100755 diff --git a/include/linux/mpu.h b/include/linux/mpu.h index 00d9e6c62405..1e4ecd56b66a 100755 --- a/include/linux/mpu.h +++ b/include/linux/mpu.h @@ -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]; }; -- 2.34.1