input: mpu3050: Add HTC version of MPU3050 sensor
HTC kernel version: evitaul-jb-crc-3.4.10-ec474a3
Change-Id: I53903035d40fe4eae1b4240068765c3e32a31ddd
diff --git a/drivers/input/misc/mpu3050/Kconfig b/drivers/input/misc/mpu3050/Kconfig
new file mode 100644
index 0000000..91f1939
--- /dev/null
+++ b/drivers/input/misc/mpu3050/Kconfig
@@ -0,0 +1,176 @@
+config MPU_SENSORS_MPU3050
+ tristate "MPU3050"
+ depends on I2C
+ help
+ If you say yes here you get support for the MPU3050 Gyroscope driver
+ This driver can also be built as a module. If so, the module
+ will be called mpu3050.
+
+choice
+ prompt "Accelerometer Type"
+ depends on MPU_SENSORS_MPU3050
+ default MPU_SENSORS_BMA150
+
+config MPU_SENSORS_ACCELEROMETER_NONE
+ bool "NONE"
+ depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000
+ help
+ This disables accelerometer support for the MPU3050
+
+config MPU_SENSORS_ADXL346
+ bool "ADI adxl346"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the ADI adxl346 accelerometer
+
+config MPU_SENSORS_BMA150
+ bool "Bosch BMA150"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Bosch BMA150 accelerometer
+
+config MPU_SENSORS_BMA250
+ bool "Bosch BMA250"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Bosch BMA250 accelerometer
+
+config MPU_SENSORS_BMA222
+ bool "Bosch BMA222"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Bosch BMA222 accelerometer
+
+config MPU_SENSORS_KXSD9
+ bool "Kionix KXSD9"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Kionix KXSD9 accelerometer
+
+config MPU_SENSORS_KXTF9
+ bool "Kionix KXTF9"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Kionix KXFT9 accelerometer
+
+config MPU_SENSORS_LIS331DLH
+ bool "ST lis331dlh"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the ST lis331dlh accelerometer
+
+config MPU_SENSORS_LIS3DH
+ bool "ST lis3dh"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the ST lis3dh accelerometer
+
+config MPU_SENSORS_LSM303DLHA
+ bool "ST lsm303dlh"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the ST lsm303dlh accelerometer
+
+config MPU_SENSORS_MMA8450
+ bool "Freescale mma8450"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Freescale mma8450 accelerometer
+
+config MPU_SENSORS_MMA845X
+ bool "Freescale mma8451/8452/8453"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Freescale mma8451/8452/8453 accelerometer
+
+endchoice
+
+choice
+ prompt "Compass Type"
+ depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050
+ default MPU_SENSORS_AK8963
+
+config MPU_SENSORS_COMPASS_NONE
+ bool "NONE"
+ depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050
+ help
+ This disables compass support for the MPU6000
+
+config MPU_SENSORS_AK8975
+ bool "AKM ak8975"
+ depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050
+ help
+ This enables support for the AKM ak8975 compass
+
+config MPU_SENSORS_AK8963
+ bool "AKM ak8963"
+ depends on MPU_SENSORS_MPU6000 || MPU_SENSORS_MPU3050
+ help
+ This enables support for the AKM ak8963 compass
+
+config MPU_SENSORS_MMC314X
+ bool "MEMSIC mmc314x"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the MEMSIC mmc314x compass
+
+config MPU_SENSORS_AMI30X
+ bool "Aichi Steel ami30X"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Aichi Steel ami304/ami305 compass
+
+config MPU_SENSORS_HMC5883
+ bool "Honeywell hmc5883"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Honeywell hmc5883 compass
+
+config MPU_SENSORS_LSM303DLHM
+ bool "ST lsm303dlh"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the ST lsm303dlh compass
+
+config MPU_SENSORS_MMC314X
+ bool "MEMSIC mmc314xMS"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the MEMSIC mmc314xMS compass
+
+config MPU_SENSORS_YAS529
+ bool "Yamaha yas529"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Yamaha yas529 compass
+
+config MPU_SENSORS_HSCDTD002B
+ bool "Alps hscdtd002b"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Alps hscdtd002b compass
+
+config MPU_SENSORS_HSCDTD004A
+ bool "Alps hscdtd004a"
+ depends on MPU_SENSORS_MPU3050
+ help
+ This enables support for the Alps hscdtd004a compass
+
+endchoice
+
+config MPU_SENSORS_TIMERIRQ
+ tristate "Timer IRQ"
+ help
+ If you say yes here you get access to the timerirq device handle which
+ can be used to select on. This can be used instead of IRQ's, sleeping,
+ or timer threads. Reading from this device returns the same type of
+ information as reading from the MPU and slave IRQ's.
+
+config MPU_SENSORS_DEBUG
+ bool "MPU debug"
+ depends on MPU_SENSORS_MPU3050 || MPU_SENSORS_MPU6000 || MPU_SENSORS_TIMERIRQ
+ help
+ If you say yes here you get extra debug messages from the MPU3050
+ and other slave sensors.
+
+
diff --git a/drivers/input/misc/mpu3050/Makefile b/drivers/input/misc/mpu3050/Makefile
new file mode 100644
index 0000000..94dc4be
--- /dev/null
+++ b/drivers/input/misc/mpu3050/Makefile
@@ -0,0 +1,140 @@
+
+# Kernel makefile for motions sensors
+#
+#
+
+# MPU
+obj-$(CONFIG_MPU_SENSORS_MPU3050) += mpu3050.o
+mpu3050-objs += mpuirq.o \
+ slaveirq.o \
+ mpu-dev.o \
+ mpu-i2c.o \
+ mlsl-kernel.o \
+ mlos-kernel.o \
+ $(MLLITE_DIR)mldl_cfg.o
+
+#
+# Accel options
+#
+ifdef CONFIG_MPU_SENSORS_ADXL346
+mpu3050-objs += $(MLLITE_DIR)accel/adxl346.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_BMA150
+mpu3050-objs += $(MLLITE_DIR)accel/bma150.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_BMA250
+mpu3050-objs += $(MLLITE_DIR)accel/bma250.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_BMA222
+mpu3050-objs += $(MLLITE_DIR)accel/bma222.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_KXSD9
+mpu3050-objs += $(MLLITE_DIR)accel/kxsd9.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_KXTF9
+mpu3050-objs += $(MLLITE_DIR)accel/kxtf9.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_LIS331DLH
+mpu3050-objs += $(MLLITE_DIR)accel/lis331.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_LIS3DH
+mpu3050-objs += $(MLLITE_DIR)accel/lis3dh.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_LSM303DLHA
+mpu3050-objs += $(MLLITE_DIR)accel/lsm303a.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_MMA8450
+mpu3050-objs += $(MLLITE_DIR)accel/mma8450.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_MMA845X
+mpu3050-objs += $(MLLITE_DIR)accel/mma845x.o
+endif
+
+#
+# Compass options
+#
+ifdef CONFIG_MPU_SENSORS_AK8975
+mpu3050-objs += $(MLLITE_DIR)compass/ak8975.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_AK8963
+mpu3050-objs += $(MLLITE_DIR)compass/ak8963.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_AMI30X
+mpu3050-objs += $(MLLITE_DIR)compass/ami30x.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_HMC5883
+mpu3050-objs += $(MLLITE_DIR)compass/hmc5883.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_LSM303DLHM
+mpu3050-objs += $(MLLITE_DIR)compass/lsm303m.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_MMC314X
+mpu3050-objs += $(MLLITE_DIR)compass/mmc314x.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_YAS529
+mpu3050-objs += $(MLLITE_DIR)compass/yas529-kernel.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_HSCDTD002B
+mpu3050-objs += $(MLLITE_DIR)compass/hscdtd002b.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_HSCDTD004A
+mpu3050-objs += $(MLLITE_DIR)compass/hscdtd004a.o
+endif
+#
+# Pressure options
+#
+ifdef CONFIG_MPU_SENSORS_BMA085
+mpu3050-objs += $(MLLITE_DIR)pressure/bma085.o
+endif
+
+EXTRA_CFLAGS += -I$(M)/$(MLLITE_DIR) \
+ -I$(M)/../../include \
+ -Idrivers/input/misc/mpu3050 \
+ -Iinclude/linux
+
+obj-$(CONFIG_MPU_SENSORS_MPU6000)+= mpu6000.o
+mpu6000-objs += mpuirq.o \
+ slaveirq.o \
+ mpu-dev.o \
+ mpu-i2c.o \
+ mlsl-kernel.o \
+ mlos-kernel.o \
+ $(MLLITE_DIR)mldl_cfg.o \
+ $(MLLITE_DIR)accel/mantis.o
+
+ifdef CONFIG_MPU_SENSORS_AK8975
+mpu6000-objs += $(MLLITE_DIR)compass/ak8975.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_AK8963
+mpu6000-objs += $(MLLITE_DIR)compass/ak8963.o
+endif
+
+ifdef CONFIG_MPU_SENSORS_MPU6000
+EXTRA_CFLAGS += -DM_HW
+endif
+
+obj-$(CONFIG_MPU_SENSORS_TIMERIRQ)+= timerirq.o
+
+ifdef CONFIG_MPU_SENSORS_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/input/misc/mpu3050/accel/bma250.c b/drivers/input/misc/mpu3050/accel/bma250.c
new file mode 100644
index 0000000..3f6a8ae
--- /dev/null
+++ b/drivers/input/misc/mpu3050/accel/bma250.c
@@ -0,0 +1,574 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+#include <linux/delay.h>
+
+#include "mpu.h"
+#include "mlos.h"
+#include "mlsl.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-acc"
+
+#define BOSCH_CTRL_REG (0x0F)
+#define BOSCH_INT_REG (0x16)
+#define BOSCH_PWR_REG (0x11)
+#define BMA250_REG_SOFT_RESET (0x14)
+#define BMA250_BW_REG (0x10)
+
+#define ACCEL_BOSCH_CTRL_MASK (0x0F)
+#define ACCEL_BOSCH_CTRL_MASK_FSR (0xF8)
+#define ACCEL_BOSCH_INT_MASK_WUP (0xF8)
+#define ACCEL_BOSCH_INT_MASK_IRQ (0xDF)
+#define BMA250_BW_MASK (0xE0)
+
+#define D(x...) printk(KERN_DEBUG "[GSNR][BMA250] " x)
+#define I(x...) printk(KERN_INFO "[GSNR][BMA250] " x)
+#define E(x...) printk(KERN_ERR "[GSNR][BMA250 ERROR] " x)
+#define DIF(x...) \
+ if (debug_flag) \
+ printk(KERN_DEBUG "[GSNR][BMA250 DEBUG] " x)
+
+
+struct bma250_config {
+ unsigned int odr;
+ unsigned int fsr;
+ unsigned int irq_type;
+ unsigned int power_mode;
+ unsigned char ctrl_reg;
+ unsigned char bw_reg;
+ unsigned char int_reg;
+};
+
+struct bma250_private_data {
+ struct bma250_config suspend;
+ struct bma250_config resume;
+ unsigned char state;
+};
+
+static int set_normal_mode(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata)
+{
+ int result = 0;
+
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BOSCH_PWR_REG, 0x00);
+ ERROR_CHECK(result);
+
+ usleep(2000);
+
+ return 0;
+}
+
+static int bma250_set_irq(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct bma250_config *config,
+ int apply,
+ long irq_type)
+{
+ unsigned char irq_bits = 0;
+ int result = ML_SUCCESS;
+
+
+ return ML_SUCCESS;
+
+ if (irq_type == MPU_SLAVE_IRQ_TYPE_MOTION)
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+ config->irq_type = (unsigned char)irq_type;
+
+ if (irq_type == MPU_SLAVE_IRQ_TYPE_DATA_READY) {
+ irq_bits = 0x20;
+ config->int_reg &= ACCEL_BOSCH_INT_MASK_WUP;
+ } else {
+ irq_bits = 0x00;
+ config->int_reg &= ACCEL_BOSCH_INT_MASK_WUP;
+ }
+
+ config->int_reg &= ACCEL_BOSCH_INT_MASK_IRQ;
+ config->int_reg |= irq_bits;
+
+ if (apply) {
+
+ if (!config->power_mode) {
+
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BMA250_REG_SOFT_RESET,
+ 0xB6);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+ }
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_CTRL_REG, config->ctrl_reg);
+ ERROR_CHECK(result);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_INT_REG, config->int_reg);
+ ERROR_CHECK(result);
+
+ if (!config->power_mode) {
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BOSCH_PWR_REG, 0x80);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+ } else {
+ result = set_normal_mode(mlsl_handle, pdata);
+ ERROR_CHECK(result);
+ }
+ }
+ return result;
+}
+
+static int bma250_set_odr(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct bma250_config *config,
+ int apply,
+ long odr)
+{
+ unsigned char odr_bits = 0;
+ unsigned char wup_bits = 0;
+ int result = ML_SUCCESS;
+
+
+ if (odr > 100000) {
+ config->odr = 31250;
+ odr_bits = 0x0A;
+ config->power_mode = 1;
+ } else if (odr > 50000) {
+ config->odr = 31250;
+ odr_bits = 0x0A;
+ config->power_mode = 1;
+ } else if (odr > 20000) {
+ config->odr = 31250;
+ odr_bits = 0x0A;
+ config->power_mode = 1;
+ } else if (odr > 15000) {
+ config->odr = 31250;
+ odr_bits = 0x0A;
+ config->power_mode = 1;
+ } else if (odr > 0) {
+ config->odr = 31250;
+ odr_bits = 0x0A;
+ config->power_mode = 1;
+ } else {
+ config->odr = 0;
+ wup_bits = 0x00;
+ config->power_mode = 0;
+ }
+
+ switch (config->power_mode) {
+ case 1:
+ config->bw_reg &= BMA250_BW_MASK;
+ config->bw_reg |= odr_bits;
+ config->int_reg &= ACCEL_BOSCH_INT_MASK_WUP;
+ break;
+ case 0:
+ config->int_reg &= ACCEL_BOSCH_INT_MASK_WUP;
+ config->int_reg |= wup_bits;
+ break;
+ default:
+ break;
+ }
+
+ MPL_LOGV("ODR: %d \n", config->odr);
+ if (apply) {
+
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BMA250_REG_SOFT_RESET,
+ 0xB6);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BMA250_BW_REG,
+ config->bw_reg);
+ ERROR_CHECK(result);
+
+
+
+ if (!config->power_mode) {
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BOSCH_PWR_REG,
+ 0x80);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+ } else {
+ result = set_normal_mode(mlsl_handle, pdata);
+ ERROR_CHECK(result);
+ }
+ }
+
+ return result;
+}
+
+static int bma250_set_fsr(void *mlsl_handle,
+ struct ext_slave_platform_data *pdata,
+ struct bma250_config *config,
+ int apply,
+ long fsr)
+{
+ unsigned char fsr_bits;
+ int result = ML_SUCCESS;
+
+
+ if (fsr <= 2048) {
+ fsr_bits = 0x03;
+ config->fsr = 2048;
+ } else if (fsr <= 4096) {
+ fsr_bits = 0x03;
+ config->fsr = 2048;
+ } else if (fsr <= 8192) {
+ fsr_bits = 0x03;
+ config->fsr = 2048;
+ } else if (fsr <= 16384) {
+ fsr_bits = 0x03;
+ config->fsr = 2048;
+ } else {
+ fsr_bits = 0x03;
+ config->fsr = 2048;
+ }
+
+ config->ctrl_reg &= ACCEL_BOSCH_CTRL_MASK_FSR;
+ config->ctrl_reg |= fsr_bits;
+
+ MPL_LOGV("FSR: %d \n", config->fsr);
+ if (apply) {
+
+ if (!config->power_mode) {
+
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BMA250_REG_SOFT_RESET, 0xB6);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+ }
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_CTRL_REG, config->ctrl_reg);
+ ERROR_CHECK(result);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_CTRL_REG, config->ctrl_reg);
+ ERROR_CHECK(result);
+
+ if (!config->power_mode) {
+ result = MLSLSerialWriteSingle(mlsl_handle,
+ pdata->address, BOSCH_PWR_REG, 0x80);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+ } else {
+ result = set_normal_mode(mlsl_handle, pdata);
+ ERROR_CHECK(result);
+ }
+ }
+ return result;
+}
+
+static int bma250_suspend(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+
+ int result = 0;
+ unsigned char ctrl_reg;
+ unsigned char int_reg;
+
+ struct bma250_private_data *private_data = pdata->private_data;
+ ctrl_reg = private_data->suspend.ctrl_reg;
+ int_reg = private_data->suspend.int_reg;
+
+ private_data->state = 1;
+
+
+
+
+
+
+ if (!private_data->suspend.power_mode) {
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_PWR_REG, 0x80);
+ ERROR_CHECK(result);
+ }
+
+ return result;
+}
+
+
+static int bma250_resume(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+
+ int result;
+ unsigned char ctrl_reg;
+ unsigned char bw_reg;
+ unsigned char int_reg;
+
+ struct bma250_private_data *private_data = pdata->private_data;
+ ctrl_reg = private_data->resume.ctrl_reg;
+ bw_reg = private_data->resume.bw_reg;
+ int_reg = private_data->resume.int_reg;
+
+ private_data->state = 0;
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BMA250_REG_SOFT_RESET, 0xB6);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_CTRL_REG, ctrl_reg);
+ ERROR_CHECK(result);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BMA250_BW_REG, bw_reg);
+ ERROR_CHECK(result);
+
+
+
+ if (!private_data->resume.power_mode) {
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BOSCH_PWR_REG, 0x80);
+ ERROR_CHECK(result);
+ } else {
+ result = set_normal_mode(mlsl_handle, pdata);
+ ERROR_CHECK(result);
+ }
+
+ return result;
+}
+
+static int bma250_read(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ unsigned char *data)
+{
+ int result;
+
+ result = MLSLSerialRead(mlsl_handle, pdata->address,
+ slave->reg, slave->len, data);
+
+ return result;
+}
+
+static int bma250_init(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ tMLError result;
+ unsigned char reg = 0;
+ unsigned char bw_reg = 0;
+
+ struct bma250_private_data *private_data;
+ private_data = (struct bma250_private_data *)
+ MLOSMalloc(sizeof(struct bma250_private_data));
+
+ printk(KERN_DEBUG "%s\n", __func__);
+
+ if (!private_data)
+ return ML_ERROR_MEMORY_EXAUSTED;
+
+
+
+ pdata->private_data = private_data;
+
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ BMA250_REG_SOFT_RESET, 0xB6);
+ ERROR_CHECK(result);
+ MLOSSleep(1);
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->address, BOSCH_CTRL_REG, 1,
+ ®);
+ ERROR_CHECK(result);
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->address, BMA250_BW_REG, 1,
+ &bw_reg);
+ ERROR_CHECK(result);
+
+ private_data->resume.ctrl_reg = reg;
+ private_data->suspend.ctrl_reg = reg;
+
+ private_data->resume.bw_reg = bw_reg;
+ private_data->suspend.bw_reg = bw_reg;
+
+
+
+ private_data->resume.int_reg = reg;
+ private_data->suspend.int_reg = reg;
+
+ private_data->resume.power_mode = 1;
+ private_data->suspend.power_mode = 0;
+
+ private_data->state = 0;
+
+ bma250_set_odr(mlsl_handle, pdata, &private_data->suspend,
+ FALSE, 0);
+ bma250_set_odr(mlsl_handle, pdata, &private_data->resume,
+ TRUE, 25000);
+ bma250_set_fsr(mlsl_handle, pdata, &private_data->suspend,
+ FALSE, 2048);
+ bma250_set_fsr(mlsl_handle, pdata, &private_data->resume,
+ FALSE, 2048);
+
+
+
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->address, BOSCH_PWR_REG,
+ 0x80);
+ ERROR_CHECK(result);
+
+ return result;
+}
+
+static int bma250_exit(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ if (pdata->private_data)
+ return MLOSFree(pdata->private_data);
+ else
+ return ML_SUCCESS;
+}
+
+static int bma250_config(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config *data)
+{
+ struct bma250_private_data *private_data = pdata->private_data;
+ if (!data->data)
+ return ML_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_CONFIG_ODR_SUSPEND:
+ return bma250_set_odr(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply,
+ *((long *)data->data));
+ case MPU_SLAVE_CONFIG_ODR_RESUME:
+ return bma250_set_odr(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply,
+ *((long *)data->data));
+ case MPU_SLAVE_CONFIG_FSR_SUSPEND:
+ return bma250_set_fsr(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply,
+ *((long *)data->data));
+ case MPU_SLAVE_CONFIG_FSR_RESUME:
+ return bma250_set_fsr(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply,
+ *((long *)data->data));
+ case MPU_SLAVE_CONFIG_IRQ_SUSPEND:
+ return bma250_set_irq(mlsl_handle, pdata,
+ &private_data->suspend,
+ data->apply,
+ *((long *)data->data));
+ case MPU_SLAVE_CONFIG_IRQ_RESUME:
+ return bma250_set_irq(mlsl_handle, pdata,
+ &private_data->resume,
+ data->apply,
+ *((long *)data->data));
+ default:
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+ return ML_SUCCESS;
+}
+
+static int bma250_get_config(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config *data)
+{
+ struct bma250_private_data *private_data = pdata->private_data;
+ if (!data->data)
+ return ML_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_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 ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return ML_SUCCESS;
+}
+
+static struct ext_slave_descr bma250_descr = {
+ bma250_init,
+ bma250_exit,
+ bma250_suspend,
+ bma250_resume,
+ bma250_read,
+ bma250_config,
+ bma250_get_config,
+ "bma250",
+ EXT_SLAVE_TYPE_ACCELEROMETER,
+ ACCEL_ID_BMA250,
+ 0x02,
+ 6,
+ EXT_SLAVE_LITTLE_ENDIAN,
+ {2, 0},
+};
+
+struct ext_slave_descr *bma250_get_slave_descr(void)
+{
+ return &bma250_descr;
+}
+EXPORT_SYMBOL(bma250_get_slave_descr);
+
+#ifdef __KERNEL__
+MODULE_AUTHOR("Invensense");
+MODULE_DESCRIPTION("User space IRQ handler for MPU3xxx devices");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("bma");
+#endif
+
diff --git a/drivers/input/misc/mpu3050/compass/ak8975.c b/drivers/input/misc/mpu3050/compass/ak8975.c
new file mode 100644
index 0000000..2a58f56
--- /dev/null
+++ b/drivers/input/misc/mpu3050/compass/ak8975.c
@@ -0,0 +1,205 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+
+
+#include <string.h>
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#endif
+
+#include "mpu.h"
+#include "mlsl.h"
+#include "mlos.h"
+
+#include <log.h>
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "MPL-compass"
+
+
+#define AK8975_REG_ST1 (0x02)
+#define AK8975_REG_HXL (0x03)
+#define AK8975_REG_ST2 (0x09)
+
+#define AK8975_REG_CNTL (0x0A)
+
+#define AK8975_CNTL_MODE_POWER_DOWN (0x00)
+#define AK8975_CNTL_MODE_SINGLE_MEASUREMENT (0x01)
+
+int ak8975_suspend(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result = ML_SUCCESS;
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ AK8975_REG_CNTL,
+ AK8975_CNTL_MODE_POWER_DOWN);
+ MLOSSleep(1);
+ ERROR_CHECK(result);
+ return result;
+}
+
+int ak8975_resume(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata)
+{
+ int result = ML_SUCCESS;
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ AK8975_REG_CNTL,
+ AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
+ ERROR_CHECK(result);
+ return result;
+}
+
+int ak8975_read(void *mlsl_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata, unsigned char *data)
+{
+ unsigned char regs[8];
+ unsigned char *stat = ®s[0];
+ unsigned char *stat2 = ®s[7];
+ int result = ML_SUCCESS;
+ int status = ML_SUCCESS;
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->address, AK8975_REG_ST1,
+ 8, regs);
+ ERROR_CHECK(result);
+
+ if (*stat & 0x01) {
+ memcpy(data, ®s[1], 6);
+ status = ML_SUCCESS;
+ }
+
+ if (*stat2 & 0x04)
+ status = ML_ERROR_COMPASS_DATA_ERROR;
+ if (*stat2 & 0x08)
+ status = ML_ERROR_COMPASS_DATA_OVERFLOW;
+ if (*stat & 0x02) {
+
+ status = ML_SUCCESS;
+ }
+
+ if (*stat != 0x00 || *stat2 != 0x00) {
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->address,
+ AK8975_REG_CNTL,
+ AK8975_CNTL_MODE_SINGLE_MEASUREMENT);
+ ERROR_CHECK(result);
+ }
+
+ return status;
+}
+
+static int ak8975_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 ML_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_WRITE_REGISTERS:
+ result = MLSLSerialWrite(mlsl_handle, pdata->address,
+ data->len,
+ (unsigned char *)data->data);
+ ERROR_CHECK(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 ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return ML_SUCCESS;
+}
+
+static int ak8975_get_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 ML_ERROR_INVALID_PARAMETER;
+
+ switch (data->key) {
+ case MPU_SLAVE_READ_REGISTERS:
+ {
+ unsigned char *serial_data = (unsigned char *)data->data;
+ result = MLSLSerialRead(mlsl_handle, pdata->address,
+ serial_data[0],
+ data->len - 1,
+ &serial_data[1]);
+ ERROR_CHECK(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 ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+ };
+
+ return ML_SUCCESS;
+}
+
+struct ext_slave_descr ak8975_descr = {
+ NULL,
+ NULL,
+ ak8975_suspend,
+ ak8975_resume,
+ ak8975_read,
+ ak8975_config,
+ ak8975_get_config,
+ "ak8975",
+ EXT_SLAVE_TYPE_COMPASS,
+ COMPASS_ID_AKM,
+ 0x01,
+ 9,
+ EXT_SLAVE_LITTLE_ENDIAN,
+ {9830, 4000}
+};
+
+struct ext_slave_descr *ak8975_get_slave_descr(void)
+{
+ return &ak8975_descr;
+}
+EXPORT_SYMBOL(ak8975_get_slave_descr);
+
diff --git a/drivers/input/misc/mpu3050/log.h b/drivers/input/misc/mpu3050/log.h
new file mode 100644
index 0000000..7b24aca
--- /dev/null
+++ b/drivers/input/misc/mpu3050/log.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2010 InvenSense Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBS_CUTILS_MPL_LOG_H
+#define _LIBS_CUTILS_MPL_LOG_H
+
+#include <stdarg.h>
+
+#ifdef ANDROID
+#include <utils/Log.h>
+#endif
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef MPL_LOG_NDEBUG
+#ifdef NDEBUG
+#define MPL_LOG_NDEBUG 1
+#else
+#define MPL_LOG_NDEBUG 0
+#endif
+#endif
+
+#ifdef __KERNEL__
+#define MPL_LOG_UNKNOWN MPL_LOG_VERBOSE
+#define MPL_LOG_DEFAULT KERN_DEFAULT
+#define MPL_LOG_VERBOSE KERN_CONT
+#define MPL_LOG_DEBUG KERN_NOTICE
+#define MPL_LOG_INFO KERN_INFO
+#define MPL_LOG_WARN KERN_WARNING
+#define MPL_LOG_ERROR KERN_ERR
+#define MPL_LOG_SILENT MPL_LOG_VERBOSE
+
+#else
+#define MPL_LOG_UNKNOWN (0)
+#define MPL_LOG_DEFAULT (1)
+#define MPL_LOG_VERBOSE (2)
+#define MPL_LOG_DEBUG (3)
+#define MPL_LOG_INFO (4)
+#define MPL_LOG_WARN (5)
+#define MPL_LOG_ERROR (6)
+#define MPL_LOG_SILENT (8)
+#endif
+
+
+#ifndef MPL_LOG_TAG
+#ifdef __KERNEL__
+#define MPL_LOG_TAG
+#else
+#define MPL_LOG_TAG NULL
+#endif
+#endif
+
+
+#ifndef MPL_LOGV
+#if MPL_LOG_NDEBUG
+#define MPL_LOGV(...) ((void)0)
+#else
+#define MPL_LOGV(...) ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+#endif
+
+#ifndef CONDITION
+#define CONDITION(cond) ((cond) != 0)
+#endif
+
+#ifndef MPL_LOGV_IF
+#if MPL_LOG_NDEBUG
+#define MPL_LOGV_IF(cond, ...) ((void)0)
+#else
+#define MPL_LOGV_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)MPL_LOG(LOG_VERBOSE, MPL_LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+#endif
+#endif
+
+#ifndef MPL_LOGD
+#define MPL_LOGD(...) ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGD_IF
+#define MPL_LOGD_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)MPL_LOG(LOG_DEBUG, MPL_LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+#endif
+
+#ifndef MPL_LOGI
+#define MPL_LOGI(...) ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGI_IF
+#define MPL_LOGI_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)MPL_LOG(LOG_INFO, MPL_LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+#endif
+
+#ifndef MPL_LOGW
+#define MPL_LOGW(...) ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGW_IF
+#define MPL_LOGW_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)MPL_LOG(LOG_WARN, MPL_LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+#endif
+
+#ifndef MPL_LOGE
+#define MPL_LOGE(...) ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__))
+#endif
+
+#ifndef MPL_LOGE_IF
+#define MPL_LOGE_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)MPL_LOG(LOG_ERROR, MPL_LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+#endif
+
+
+#define MPL_LOG_ALWAYS_FATAL_IF(cond, ...) \
+ ((CONDITION(cond)) \
+ ? ((void)android_printAssert(#cond, MPL_LOG_TAG, __VA_ARGS__)) \
+ : (void)0)
+
+#define MPL_LOG_ALWAYS_FATAL(...) \
+ (((void)android_printAssert(NULL, MPL_LOG_TAG, __VA_ARGS__)))
+
+#if MPL_LOG_NDEBUG
+
+#define MPL_LOG_FATAL_IF(cond, ...) ((void)0)
+#define MPL_LOG_FATAL(...) ((void)0)
+
+#else
+
+#define MPL_LOG_FATAL_IF(cond, ...) MPL_LOG_ALWAYS_FATAL_IF(cond, __VA_ARGS__)
+#define MPL_LOG_FATAL(...) MPL_LOG_ALWAYS_FATAL(__VA_ARGS__)
+
+#endif
+
+#define MPL_LOG_ASSERT(cond, ...) MPL_LOG_FATAL_IF(!(cond), __VA_ARGS__)
+
+
+#ifndef MPL_LOG
+#define MPL_LOG(priority, tag, ...) \
+ MPL_LOG_PRI(priority, tag, __VA_ARGS__)
+#endif
+
+#ifndef MPL_LOG_PRI
+#ifdef ANDROID
+#define MPL_LOG_PRI(priority, tag, ...) \
+ LOG(priority, tag, __VA_ARGS__)
+#elif defined __KERNEL__
+#define MPL_LOG_PRI(priority, tag, ...) \
+ printk(MPL_##priority tag __VA_ARGS__)
+#else
+#define MPL_LOG_PRI(priority, tag, ...) \
+ _MLPrintLog(MPL_##priority, tag, __VA_ARGS__)
+#endif
+#endif
+
+#ifndef MPL_LOG_PRI_VA
+#ifdef ANDROID
+#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
+ android_vprintLog(priority, NULL, tag, fmt, args)
+#elif defined __KERNEL__
+#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
+ vprintk(MPL_##priority tag fmt, args)
+#else
+#define MPL_LOG_PRI_VA(priority, tag, fmt, args) \
+ _MLPrintVaLog(priority, NULL, tag, fmt, args)
+#endif
+#endif
+
+
+
+#ifndef ANDROID
+ int _MLPrintLog(int priority, const char *tag, const char *fmt,
+ ...);
+ int _MLPrintVaLog(int priority, const char *tag, const char *fmt,
+ va_list args);
+ int _MLWriteLog(const char *buf, int buflen);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/input/misc/mpu3050/mldl_cfg.c b/drivers/input/misc/mpu3050/mldl_cfg.c
new file mode 100644
index 0000000..6b12dda
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mldl_cfg.c
@@ -0,0 +1,1434 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+
+
+#include <stddef.h>
+
+#include "mldl_cfg.h"
+#include "mpu.h"
+
+#include "mlsl.h"
+#include "mlos.h"
+
+#include "log.h"
+#undef MPL_LOG_TAG
+#define MPL_LOG_TAG "mldl_cfg:"
+
+#ifdef M_HW
+#define SLEEP 0
+#define WAKE_UP 7
+#define RESET 1
+#define STANDBY 1
+#else
+#define SLEEP 1
+#define WAKE_UP 0
+#define RESET 1
+#define STANDBY 1
+#endif
+
+#define D(x...) printk(KERN_DEBUG "[GYRO][MPU3050] " x)
+#define I(x...) printk(KERN_INFO "[GYRO][MPU3050] " x)
+#define E(x...) printk(KERN_ERR "[GYRO][MPU3050 ERROR] " x)
+
+
+
+static int dmp_stop(struct mldl_cfg *mldl_cfg, void *gyro_handle)
+{
+ unsigned char userCtrlReg = 0;
+ int result;
+
+ if (!mldl_cfg->dmp_is_running)
+ return ML_SUCCESS;
+
+ result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL, 1, &userCtrlReg);
+ ERROR_CHECK(result);
+ userCtrlReg = (userCtrlReg & (~BIT_FIFO_EN)) | BIT_FIFO_RST;
+ userCtrlReg = (userCtrlReg & (~BIT_DMP_EN)) | BIT_DMP_RST;
+
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL, userCtrlReg);
+ ERROR_CHECK(result);
+ mldl_cfg->dmp_is_running = 0;
+
+ return result;
+
+}
+static int dmp_start(struct mldl_cfg *pdata, void *mlsl_handle)
+{
+ unsigned char userCtrlReg = 0;
+ int result;
+
+ if (pdata->dmp_is_running == pdata->dmp_enable)
+ return ML_SUCCESS;
+
+ result = MLSLSerialRead(mlsl_handle, pdata->addr,
+ MPUREG_USER_CTRL, 1, &userCtrlReg);
+ ERROR_CHECK(result);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_USER_CTRL,
+ ((userCtrlReg & (~BIT_FIFO_EN))
+ | BIT_FIFO_RST));
+ ERROR_CHECK(result);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_USER_CTRL, userCtrlReg);
+ ERROR_CHECK(result);
+
+ result = MLSLSerialRead(mlsl_handle, pdata->addr,
+ MPUREG_USER_CTRL, 1, &userCtrlReg);
+ ERROR_CHECK(result);
+
+ if (pdata->dmp_enable)
+ userCtrlReg |= BIT_DMP_EN;
+ else
+ userCtrlReg &= ~BIT_DMP_EN;
+
+ if (pdata->fifo_enable)
+ userCtrlReg |= BIT_FIFO_EN;
+ else
+ userCtrlReg &= ~BIT_FIFO_EN;
+
+ userCtrlReg |= BIT_DMP_RST;
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_USER_CTRL, userCtrlReg);
+ ERROR_CHECK(result);
+ pdata->dmp_is_running = pdata->dmp_enable;
+
+ return result;
+}
+
+static int MLDLSetI2CBypass(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle,
+ unsigned char enable)
+{
+ unsigned char b = 0;
+ int result;
+
+ if ((mldl_cfg->gyro_is_bypassed && enable) ||
+ (!mldl_cfg->gyro_is_bypassed && !enable))
+ return ML_SUCCESS;
+
+
+ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL, 1, &b);
+ ERROR_CHECK(result);
+
+ b &= ~BIT_AUX_IF_EN;
+
+ if (!enable) {
+ result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL,
+ (b | BIT_AUX_IF_EN));
+ ERROR_CHECK(result);
+ } else {
+ result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+ MPUREG_AUX_SLV_ADDR, 0x7F);
+ ERROR_CHECK(result);
+ MLOSSleep(2);
+ result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL, (b));
+ ERROR_CHECK(result);
+ MLOSSleep(SAMPLING_PERIOD_US(mldl_cfg) / 1000);
+ result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+ MPUREG_AUX_SLV_ADDR,
+ mldl_cfg->pdata->
+ accel.address);
+ ERROR_CHECK(result);
+
+#ifdef M_HW
+ result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL,
+ (b | BIT_I2C_MST_RST));
+
+#else
+ result = MLSLSerialWriteSingle(mlsl_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL,
+ (b | BIT_AUX_IF_RST));
+#endif
+ ERROR_CHECK(result);
+ MLOSSleep(2);
+ }
+ mldl_cfg->gyro_is_bypassed = enable;
+
+ return result;
+}
+
+struct tsProdRevMap {
+ unsigned char siliconRev;
+ unsigned short sensTrim;
+};
+
+#define NUM_OF_PROD_REVS (DIM(prodRevsMap))
+
+#ifdef M_HW
+#define OLDEST_PROD_REV_SUPPORTED 1
+static struct tsProdRevMap prodRevsMap[] = {
+ {0, 0},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+ {MPU_SILICON_REV_A1, 131},
+};
+
+#else
+#define OLDEST_PROD_REV_SUPPORTED 11
+
+static struct tsProdRevMap prodRevsMap[] = {
+ {0, 0},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_A4, 131},
+ {MPU_SILICON_REV_B1, 131},
+ {MPU_SILICON_REV_B1, 131},
+ {MPU_SILICON_REV_B1, 131},
+ {MPU_SILICON_REV_B1, 131},
+ {MPU_SILICON_REV_B4, 131},
+ {MPU_SILICON_REV_B4, 131},
+ {MPU_SILICON_REV_B4, 131},
+ {MPU_SILICON_REV_B4, 131},
+ {MPU_SILICON_REV_B4, 115},
+ {MPU_SILICON_REV_B4, 115},
+ {MPU_SILICON_REV_B6, 131},
+ {MPU_SILICON_REV_B4, 115},
+ {MPU_SILICON_REV_B6, 0},
+ {MPU_SILICON_REV_B6, 0},
+ {MPU_SILICON_REV_B6, 0},
+ {MPU_SILICON_REV_B6, 131},
+};
+#endif
+
+static int MLDLGetSiliconRev(struct mldl_cfg *pdata,
+ void *mlsl_handle)
+{
+ int result;
+ unsigned char index = 0x00;
+ unsigned char bank =
+ (BIT_PRFTCH_EN | BIT_CFG_USER_BANK | MPU_MEM_OTP_BANK_0);
+ unsigned short memAddr = ((bank << 8) | 0x06);
+
+ result = MLSLSerialReadMem(mlsl_handle, pdata->addr,
+ memAddr, 1, &index);
+ ERROR_CHECK(result)
+ if (result)
+ return result;
+ index >>= 2;
+
+
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_BANK_SEL, 0);
+ ERROR_CHECK(result)
+ if (result)
+ return result;
+
+ if (index < OLDEST_PROD_REV_SUPPORTED || NUM_OF_PROD_REVS <= index) {
+ pdata->silicon_revision = 0;
+ pdata->trim = 0;
+ MPL_LOGE("Unsupported Product Revision Detected : %d\n", index);
+ return ML_ERROR_INVALID_MODULE;
+ }
+
+ pdata->silicon_revision = prodRevsMap[index].siliconRev;
+ pdata->trim = prodRevsMap[index].sensTrim;
+
+ if (pdata->trim == 0) {
+ MPL_LOGE("sensitivity trim is 0"
+ " - unsupported non production part.\n");
+ return ML_ERROR_INVALID_MODULE;
+ }
+
+ return result;
+}
+
+static int MLDLSetLevelShifterBit(struct mldl_cfg *pdata,
+ void *mlsl_handle,
+ unsigned char enable)
+{
+#ifndef M_HW
+ int result;
+ unsigned char reg;
+ unsigned char mask;
+ unsigned char regval = 0;
+
+ if (0 == pdata->silicon_revision)
+ return ML_ERROR_INVALID_PARAMETER;
+
+ if ((pdata->silicon_revision & 0xf) < MPU_SILICON_REV_B6) {
+ reg = MPUREG_ACCEL_BURST_ADDR;
+ mask = 0x80;
+ } else {
+ reg = MPUREG_FIFO_EN2;
+ mask = 0x04;
+ }
+
+ result = MLSLSerialRead(mlsl_handle, pdata->addr, reg, 1, ®val);
+ if (result)
+ return result;
+
+ if (enable)
+ regval |= mask;
+ else
+ regval &= ~mask;
+
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->addr, reg, regval);
+
+ return result;
+#else
+ return ML_SUCCESS;
+#endif
+}
+
+
+#ifdef M_HW
+static tMLError mpu60xx_pwr_mgmt(struct mldl_cfg *pdata,
+ void *mlsl_handle,
+ unsigned char reset,
+ unsigned char powerselection)
+{
+ unsigned char b;
+ tMLError result;
+
+ if (powerselection < 0 || powerselection > 7)
+ return ML_ERROR_INVALID_PARAMETER;
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_1, 1,
+ &b);
+ ERROR_CHECK(result);
+
+ b &= ~(BITS_PWRSEL);
+
+ if (reset) {
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b | BIT_H_RESET);
+#define M_HW_RESET_ERRATTA
+#ifndef M_HW_RESET_ERRATTA
+ ERROR_CHECK(result);
+#else
+ MLOSSleep(50);
+#endif
+ }
+
+ b |= (powerselection << 4);
+
+ if (b & BITS_PWRSEL)
+ pdata->gyro_is_suspended = FALSE;
+ else
+ pdata->gyro_is_suspended = TRUE;
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b);
+ ERROR_CHECK(result);
+
+ return ML_SUCCESS;
+}
+
+static tMLError MLDLStandByGyros(struct mldl_cfg *pdata,
+ void *mlsl_handle,
+ unsigned char disable_gx,
+ unsigned char disable_gy,
+ unsigned char disable_gz)
+{
+ unsigned char b;
+ tMLError result;
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1,
+ &b);
+ ERROR_CHECK(result);
+
+ b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
+ b |= (disable_gx << 2 | disable_gy << 1 | disable_gz);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGMT_2, b);
+ ERROR_CHECK(result);
+
+ return ML_SUCCESS;
+}
+
+static tMLError MLDLStandByAccels(struct mldl_cfg *pdata,
+ void *mlsl_handle,
+ unsigned char disable_ax,
+ unsigned char disable_ay,
+ unsigned char disable_az)
+{
+ unsigned char b;
+ tMLError result;
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGMT_2, 1,
+ &b);
+ ERROR_CHECK(result);
+
+ b &= ~(BIT_STBY_XA | BIT_STBY_YA | BIT_STBY_ZA);
+ b |= (disable_ax << 2 | disable_ay << 1 | disable_az);
+
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGMT_2, b);
+ ERROR_CHECK(result);
+
+ return ML_SUCCESS;
+}
+
+#else
+
+static int MLDLPowerMgmtMPU(struct mldl_cfg *pdata,
+ void *mlsl_handle,
+ unsigned char reset,
+ unsigned char sleep,
+ unsigned char disable_gx,
+ unsigned char disable_gy,
+ unsigned char disable_gz)
+{
+ unsigned char b = 0;
+ int result;
+
+ result =
+ MLSLSerialRead(mlsl_handle, pdata->addr, MPUREG_PWR_MGM, 1,
+ &b);
+ ERROR_CHECK(result);
+
+
+ if ((!(b & BIT_SLEEP)) && reset)
+ result = MLDLSetI2CBypass(pdata, mlsl_handle, 1);
+
+
+ if ((!(b & BIT_SLEEP)) && sleep)
+ dmp_stop(pdata, mlsl_handle);
+
+
+ if (reset) {
+ MPL_LOGV("Reset MPU3050\n");
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b | BIT_H_RESET);
+ ERROR_CHECK(result);
+ MLOSSleep(5);
+ pdata->gyro_needs_reset = FALSE;
+ result = MLSLSerialRead(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, 1, &b);
+ ERROR_CHECK(result);
+ }
+
+
+ if (b & BIT_SLEEP)
+ pdata->gyro_is_suspended = TRUE;
+ else
+ pdata->gyro_is_suspended = FALSE;
+
+
+ if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
+ (((sleep != 0) * BIT_SLEEP) |
+ ((disable_gx != 0) * BIT_STBY_XG) |
+ ((disable_gy != 0) * BIT_STBY_YG) |
+ ((disable_gz != 0) * BIT_STBY_ZG))) {
+ return ML_SUCCESS;
+ }
+
+ if ((b & (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)) ==
+ (BIT_SLEEP | BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG)
+ && ((!sleep) && disable_gx && disable_gy && disable_gz)) {
+ result = MLDLPowerMgmtMPU(pdata, mlsl_handle, 0, 1, 0, 0, 0);
+ if (result)
+ return result;
+ b |= BIT_SLEEP;
+ b &= ~(BIT_STBY_XG | BIT_STBY_YG | BIT_STBY_ZG);
+ }
+
+ if ((b & BIT_SLEEP) != ((sleep != 0) * BIT_SLEEP)) {
+ if (sleep) {
+ result = MLDLSetI2CBypass(pdata, mlsl_handle, 1);
+ ERROR_CHECK(result);
+ b |= BIT_SLEEP;
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b);
+ ERROR_CHECK(result);
+ pdata->gyro_is_suspended = TRUE;
+ } else {
+ b &= ~BIT_SLEEP;
+ result =
+ MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b);
+ ERROR_CHECK(result);
+ pdata->gyro_is_suspended = FALSE;
+ MLOSSleep(5);
+ }
+ }
+ if ((b & BIT_STBY_XG) != ((disable_gx != 0) * BIT_STBY_XG)) {
+ b ^= BIT_STBY_XG;
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b);
+ ERROR_CHECK(result);
+ }
+ if ((b & BIT_STBY_YG) != ((disable_gy != 0) * BIT_STBY_YG)) {
+ b ^= BIT_STBY_YG;
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b);
+ ERROR_CHECK(result);
+ }
+ if ((b & BIT_STBY_ZG) != ((disable_gz != 0) * BIT_STBY_ZG)) {
+ b ^= BIT_STBY_ZG;
+ result = MLSLSerialWriteSingle(mlsl_handle, pdata->addr,
+ MPUREG_PWR_MGM, b);
+ ERROR_CHECK(result);
+ }
+
+ return ML_SUCCESS;
+}
+#endif
+
+
+void mpu_print_cfg(struct mldl_cfg *mldl_cfg)
+{
+ struct mpu3050_platform_data *pdata = mldl_cfg->pdata;
+ struct ext_slave_platform_data *accel = &mldl_cfg->pdata->accel;
+ struct ext_slave_platform_data *compass =
+ &mldl_cfg->pdata->compass;
+ struct ext_slave_platform_data *pressure =
+ &mldl_cfg->pdata->pressure;
+
+ MPL_LOGD("mldl_cfg.addr = %02x\n", mldl_cfg->addr);
+ MPL_LOGD("mldl_cfg.int_config = %02x\n",
+ mldl_cfg->int_config);
+ MPL_LOGD("mldl_cfg.ext_sync = %02x\n", mldl_cfg->ext_sync);
+ MPL_LOGD("mldl_cfg.full_scale = %02x\n",
+ mldl_cfg->full_scale);
+ MPL_LOGD("mldl_cfg.lpf = %02x\n", mldl_cfg->lpf);
+ MPL_LOGD("mldl_cfg.clk_src = %02x\n", mldl_cfg->clk_src);
+ MPL_LOGD("mldl_cfg.divider = %02x\n", mldl_cfg->divider);
+ MPL_LOGD("mldl_cfg.dmp_enable = %02x\n",
+ mldl_cfg->dmp_enable);
+ MPL_LOGD("mldl_cfg.fifo_enable = %02x\n",
+ mldl_cfg->fifo_enable);
+ MPL_LOGD("mldl_cfg.dmp_cfg1 = %02x\n", mldl_cfg->dmp_cfg1);
+ MPL_LOGD("mldl_cfg.dmp_cfg2 = %02x\n", mldl_cfg->dmp_cfg2);
+ MPL_LOGD("mldl_cfg.offset_tc[0] = %02x\n",
+ mldl_cfg->offset_tc[0]);
+ MPL_LOGD("mldl_cfg.offset_tc[1] = %02x\n",
+ mldl_cfg->offset_tc[1]);
+ MPL_LOGD("mldl_cfg.offset_tc[2] = %02x\n",
+ mldl_cfg->offset_tc[2]);
+ MPL_LOGD("mldl_cfg.silicon_revision = %02x\n",
+ mldl_cfg->silicon_revision);
+ MPL_LOGD("mldl_cfg.product_id = %02x\n",
+ mldl_cfg->product_id);
+ MPL_LOGD("mldl_cfg.trim = %02x\n", mldl_cfg->trim);
+ MPL_LOGD("mldl_cfg.requested_sensors= %04lx\n",
+ mldl_cfg->requested_sensors);
+
+ if (mldl_cfg->accel) {
+ MPL_LOGD("slave_accel->suspend = %02x\n",
+ (int) mldl_cfg->accel->suspend);
+ MPL_LOGD("slave_accel->resume = %02x\n",
+ (int) mldl_cfg->accel->resume);
+ MPL_LOGD("slave_accel->read = %02x\n",
+ (int) mldl_cfg->accel->read);
+ MPL_LOGD("slave_accel->type = %02x\n",
+ mldl_cfg->accel->type);
+ MPL_LOGD("slave_accel->reg = %02x\n",
+ mldl_cfg->accel->reg);
+ MPL_LOGD("slave_accel->len = %02x\n",
+ mldl_cfg->accel->len);
+ MPL_LOGD("slave_accel->endian = %02x\n",
+ mldl_cfg->accel->endian);
+ MPL_LOGD("slave_accel->range.mantissa= %02lx\n",
+ mldl_cfg->accel->range.mantissa);
+ MPL_LOGD("slave_accel->range.fraction= %02lx\n",
+ mldl_cfg->accel->range.fraction);
+ } else {
+ MPL_LOGD("slave_accel = NULL\n");
+ }
+
+ if (mldl_cfg->compass) {
+ MPL_LOGD("slave_compass->suspend = %02x\n",
+ (int) mldl_cfg->compass->suspend);
+ MPL_LOGD("slave_compass->resume = %02x\n",
+ (int) mldl_cfg->compass->resume);
+ MPL_LOGD("slave_compass->read = %02x\n",
+ (int) mldl_cfg->compass->read);
+ MPL_LOGD("slave_compass->type = %02x\n",
+ mldl_cfg->compass->type);
+ MPL_LOGD("slave_compass->reg = %02x\n",
+ mldl_cfg->compass->reg);
+ MPL_LOGD("slave_compass->len = %02x\n",
+ mldl_cfg->compass->len);
+ MPL_LOGD("slave_compass->endian = %02x\n",
+ mldl_cfg->compass->endian);
+ MPL_LOGD("slave_compass->range.mantissa= %02lx\n",
+ mldl_cfg->compass->range.mantissa);
+ MPL_LOGD("slave_compass->range.fraction= %02lx\n",
+ mldl_cfg->compass->range.fraction);
+
+ } else {
+ MPL_LOGD("slave_compass = NULL\n");
+ }
+
+ if (mldl_cfg->pressure) {
+ MPL_LOGD("slave_pressure->suspend = %02x\n",
+ (int) mldl_cfg->pressure->suspend);
+ MPL_LOGD("slave_pressure->resume = %02x\n",
+ (int) mldl_cfg->pressure->resume);
+ MPL_LOGD("slave_pressure->read = %02x\n",
+ (int) mldl_cfg->pressure->read);
+ MPL_LOGD("slave_pressure->type = %02x\n",
+ mldl_cfg->pressure->type);
+ MPL_LOGD("slave_pressure->reg = %02x\n",
+ mldl_cfg->pressure->reg);
+ MPL_LOGD("slave_pressure->len = %02x\n",
+ mldl_cfg->pressure->len);
+ MPL_LOGD("slave_pressure->endian = %02x\n",
+ mldl_cfg->pressure->endian);
+ MPL_LOGD("slave_pressure->range.mantissa= %02lx\n",
+ mldl_cfg->pressure->range.mantissa);
+ MPL_LOGD("slave_pressure->range.fraction= %02lx\n",
+ mldl_cfg->pressure->range.fraction);
+
+ } else {
+ MPL_LOGD("slave_pressure = NULL\n");
+ }
+ MPL_LOGD("accel->get_slave_descr = %x\n",
+ (unsigned int) accel->get_slave_descr);
+ MPL_LOGD("accel->irq = %02x\n", accel->irq);
+ MPL_LOGD("accel->adapt_num = %02x\n", accel->adapt_num);
+ MPL_LOGD("accel->bus = %02x\n", accel->bus);
+ MPL_LOGD("accel->address = %02x\n", accel->address);
+ MPL_LOGD("accel->orientation =\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n",
+ accel->orientation[0], accel->orientation[1],
+ accel->orientation[2], accel->orientation[3],
+ accel->orientation[4], accel->orientation[5],
+ accel->orientation[6], accel->orientation[7],
+ accel->orientation[8]);
+ MPL_LOGD("compass->get_slave_descr = %x\n",
+ (unsigned int) compass->get_slave_descr);
+ MPL_LOGD("compass->irq = %02x\n", compass->irq);
+ MPL_LOGD("compass->adapt_num = %02x\n", compass->adapt_num);
+ MPL_LOGD("compass->bus = %02x\n", compass->bus);
+ MPL_LOGD("compass->address = %02x\n", compass->address);
+ MPL_LOGD("compass->orientation =\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n",
+ compass->orientation[0], compass->orientation[1],
+ compass->orientation[2], compass->orientation[3],
+ compass->orientation[4], compass->orientation[5],
+ compass->orientation[6], compass->orientation[7],
+ compass->orientation[8]);
+ MPL_LOGD("pressure->get_slave_descr = %x\n",
+ (unsigned int) pressure->get_slave_descr);
+ MPL_LOGD("pressure->irq = %02x\n", pressure->irq);
+ MPL_LOGD("pressure->adapt_num = %02x\n", pressure->adapt_num);
+ MPL_LOGD("pressure->bus = %02x\n", pressure->bus);
+ MPL_LOGD("pressure->address = %02x\n", pressure->address);
+ MPL_LOGD("pressure->orientation =\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n",
+ pressure->orientation[0], pressure->orientation[1],
+ pressure->orientation[2], pressure->orientation[3],
+ pressure->orientation[4], pressure->orientation[5],
+ pressure->orientation[6], pressure->orientation[7],
+ pressure->orientation[8]);
+
+ MPL_LOGD("pdata->int_config = %02x\n", pdata->int_config);
+ MPL_LOGD("pdata->level_shifter = %02x\n",
+ pdata->level_shifter);
+ MPL_LOGD("pdata->orientation =\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n"
+ " %2d %2d %2d\n",
+ pdata->orientation[0], pdata->orientation[1],
+ pdata->orientation[2], pdata->orientation[3],
+ pdata->orientation[4], pdata->orientation[5],
+ pdata->orientation[6], pdata->orientation[7],
+ pdata->orientation[8]);
+
+ MPL_LOGD("Struct sizes: mldl_cfg: %d, "
+ "ext_slave_descr:%d, "
+ "mpu3050_platform_data:%d: RamOffset: %d\n",
+ sizeof(struct mldl_cfg), sizeof(struct ext_slave_descr),
+ sizeof(struct mpu3050_platform_data),
+ offsetof(struct mldl_cfg, ram));
+}
+
+int mpu_set_slave(struct mldl_cfg *mldl_cfg,
+ void *gyro_handle,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *slave_pdata)
+{
+ int result;
+ unsigned char reg = 0;
+ unsigned char slave_reg;
+ unsigned char slave_len;
+ unsigned char slave_endian;
+ unsigned char slave_address;
+
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+
+ if (NULL == slave || NULL == slave_pdata) {
+ slave_reg = 0;
+ slave_len = 0;
+ slave_endian = 0;
+ slave_address = 0;
+ } else {
+ slave_reg = slave->reg;
+ slave_len = slave->len;
+ slave_endian = slave->endian;
+ slave_address = slave_pdata->address;
+ }
+
+
+ result = MLSLSerialWriteSingle(gyro_handle,
+ mldl_cfg->addr,
+ MPUREG_AUX_SLV_ADDR,
+ slave_address);
+ ERROR_CHECK(result);
+
+ result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+ MPUREG_ACCEL_BURST_ADDR, 1,
+ ®);
+ ERROR_CHECK(result);
+ reg = ((reg & 0x80) | slave_reg);
+ result = MLSLSerialWriteSingle(gyro_handle,
+ mldl_cfg->addr,
+ MPUREG_ACCEL_BURST_ADDR,
+ reg);
+ ERROR_CHECK(result);
+
+#ifdef M_HW
+
+ if (slave_len > BITS_SLV_LENG) {
+ MPL_LOGW("Limiting slave burst read length to "
+ "the allowed maximum (15B, req. %d)\n",
+ slave_len);
+ slave_len = BITS_SLV_LENG;
+ }
+ reg = slave_len;
+ if (slave_endian == EXT_SLAVE_LITTLE_ENDIAN)
+ reg |= BIT_SLV_BYTE_SW;
+ reg |= BIT_SLV_GRP;
+ reg |= BIT_SLV_ENABLE;
+
+ result = MLSLSerialWriteSingle(gyro_handle,
+ mldl_cfg->addr,
+ MPUREG_I2C_SLV0_CTRL,
+ reg);
+#else
+
+ result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+ MPUREG_USER_CTRL, 1, ®);
+ ERROR_CHECK(result);
+ reg = (reg & ~BIT_AUX_RD_LENG);
+ result = MLSLSerialWriteSingle(gyro_handle,
+ mldl_cfg->addr,
+ MPUREG_USER_CTRL, reg);
+ ERROR_CHECK(result);
+#endif
+
+ if (slave_address) {
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, FALSE);
+ ERROR_CHECK(result);
+ }
+ return result;
+}
+
+static int mpu_was_reset(struct mldl_cfg *mldl_cfg, void *gyro_handle)
+{
+ int result = ML_SUCCESS;
+ unsigned char reg = 0;
+
+ result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+ MPUREG_DMP_CFG_2, 1, ®);
+ ERROR_CHECK(result);
+
+ if (mldl_cfg->dmp_cfg2 != reg)
+ return TRUE;
+
+ if (0 != mldl_cfg->dmp_cfg1)
+ return FALSE;
+
+ result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+ MPUREG_SMPLRT_DIV, 1, ®);
+ ERROR_CHECK(result);
+ if (reg != mldl_cfg->divider)
+ return TRUE;
+
+ if (0 != mldl_cfg->divider)
+ return FALSE;
+
+
+ return TRUE;
+}
+
+static int gyro_resume(struct mldl_cfg *mldl_cfg, void *gyro_handle)
+{
+ int result;
+ int ii;
+ int jj;
+ unsigned char reg = 0;
+ unsigned char regs[7];
+
+
+#ifdef M_HW
+ result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, RESET,
+ WAKE_UP);
+ ERROR_CHECK(result);
+
+
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1);
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_INT_PIN_CFG,
+ (mldl_cfg->pdata->int_config |
+ BIT_BYPASS_EN));
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_INT_ENABLE,
+ (mldl_cfg->int_config));
+ ERROR_CHECK(result);
+#else
+ result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 0, 0,
+ mldl_cfg->gyro_power & BIT_STBY_XG,
+ mldl_cfg->gyro_power & BIT_STBY_YG,
+ mldl_cfg->gyro_power & BIT_STBY_ZG);
+
+ if (!mldl_cfg->gyro_needs_reset &&
+ !mpu_was_reset(mldl_cfg, gyro_handle)) {
+ return ML_SUCCESS;
+ }
+
+ result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle, 1, 0,
+ mldl_cfg->gyro_power & BIT_STBY_XG,
+ mldl_cfg->gyro_power & BIT_STBY_YG,
+ mldl_cfg->gyro_power & BIT_STBY_ZG);
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_INT_CFG,
+ (mldl_cfg->int_config |
+ mldl_cfg->pdata->int_config));
+ ERROR_CHECK(result);
+#endif
+
+ result = MLSLSerialRead(gyro_handle, mldl_cfg->addr,
+ MPUREG_PWR_MGM, 1, ®);
+ ERROR_CHECK(result);
+ reg &= ~BITS_CLKSEL;
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_PWR_MGM,
+ mldl_cfg->clk_src | reg);
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_SMPLRT_DIV,
+ mldl_cfg->divider);
+ ERROR_CHECK(result);
+
+#ifdef M_HW
+ reg = DLPF_FS_SYNC_VALUE(0, mldl_cfg->full_scale, 0);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_GYRO_CONFIG, reg);
+ reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync, 0, mldl_cfg->lpf);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_CONFIG, reg);
+#else
+ reg = DLPF_FS_SYNC_VALUE(mldl_cfg->ext_sync,
+ mldl_cfg->full_scale, mldl_cfg->lpf);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_DLPF_FS_SYNC, reg);
+#endif
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_DMP_CFG_1,
+ mldl_cfg->dmp_cfg1);
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_DMP_CFG_2,
+ mldl_cfg->dmp_cfg2);
+ ERROR_CHECK(result);
+
+
+ for (ii = 0; ii < MPU_MEM_NUM_RAM_BANKS; ii++) {
+ unsigned char read[MPU_MEM_BANK_SIZE] = {0};
+
+ result = MLSLSerialWriteMem(gyro_handle,
+ mldl_cfg->addr,
+ ((ii << 8) | 0x00),
+ MPU_MEM_BANK_SIZE,
+ mldl_cfg->ram[ii]);
+ ERROR_CHECK(result);
+ result = MLSLSerialReadMem(gyro_handle, mldl_cfg->addr,
+ ((ii << 8) | 0x00),
+ MPU_MEM_BANK_SIZE, read);
+ ERROR_CHECK(result);
+
+#ifdef M_HW
+#define ML_SKIP_CHECK 38
+#else
+#define ML_SKIP_CHECK 20
+#endif
+ for (jj = 0; jj < MPU_MEM_BANK_SIZE; jj++) {
+
+ if (ii == 0 && jj < ML_SKIP_CHECK)
+ continue;
+ if (mldl_cfg->ram[ii][jj] != read[jj]) {
+ result = ML_ERROR_SERIAL_WRITE;
+ break;
+ }
+ }
+ ERROR_CHECK(result);
+ }
+
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_XG_OFFS_TC,
+ mldl_cfg->offset_tc[0]);
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_YG_OFFS_TC,
+ mldl_cfg->offset_tc[1]);
+ ERROR_CHECK(result);
+ result = MLSLSerialWriteSingle(gyro_handle, mldl_cfg->addr,
+ MPUREG_ZG_OFFS_TC,
+ mldl_cfg->offset_tc[2]);
+ ERROR_CHECK(result);
+
+ regs[0] = MPUREG_X_OFFS_USRH;
+ for (ii = 0; ii < DIM(mldl_cfg->offset); ii++) {
+ regs[1 + ii * 2] =
+ (unsigned char)(mldl_cfg->offset[ii] >> 8)
+ & 0xff;
+ regs[1 + ii * 2 + 1] =
+ (unsigned char)(mldl_cfg->offset[ii] & 0xff);
+ }
+ result = MLSLSerialWrite(gyro_handle, mldl_cfg->addr, 7, regs);
+ ERROR_CHECK(result);
+
+
+ result = MLDLSetLevelShifterBit(mldl_cfg, gyro_handle,
+ mldl_cfg->pdata->level_shifter);
+ ERROR_CHECK(result);
+ return result;
+}
+
+int mpu3050_open(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle)
+{
+ int result;
+
+ mldl_cfg->int_config = BIT_INT_ANYRD_2CLEAR | BIT_DMP_INT_EN;
+ mldl_cfg->clk_src = MPU_CLK_SEL_PLLGYROZ;
+ mldl_cfg->lpf = MPU_FILTER_42HZ;
+ mldl_cfg->full_scale = MPU_FS_2000DPS;
+ mldl_cfg->divider = 4;
+ mldl_cfg->dmp_enable = 1;
+ mldl_cfg->fifo_enable = 1;
+ mldl_cfg->ext_sync = 0;
+ mldl_cfg->dmp_cfg1 = 0;
+ mldl_cfg->dmp_cfg2 = 0;
+ mldl_cfg->gyro_power = 0;
+ mldl_cfg->gyro_is_bypassed = TRUE;
+ mldl_cfg->dmp_is_running = FALSE;
+ mldl_cfg->gyro_is_suspended = TRUE;
+ mldl_cfg->accel_is_suspended = TRUE;
+ mldl_cfg->compass_is_suspended = TRUE;
+ mldl_cfg->pressure_is_suspended = TRUE;
+ mldl_cfg->gyro_needs_reset = FALSE;
+ if (mldl_cfg->addr == 0) {
+#ifdef __KERNEL__
+ return ML_ERROR_INVALID_PARAMETER;
+#else
+ mldl_cfg->addr = 0x68;
+#endif
+ }
+
+#ifdef M_HW
+ result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle,
+ RESET, WAKE_UP);
+#else
+ result = MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, RESET, 0, 0, 0, 0);
+#endif
+ ERROR_CHECK(result);
+
+ result = MLDLGetSiliconRev(mldl_cfg, mlsl_handle);
+ ERROR_CHECK(result);
+#ifndef M_HW
+ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+ MPUREG_PRODUCT_ID, 1,
+ &mldl_cfg->product_id);
+ ERROR_CHECK(result);
+#endif
+
+
+ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+ MPUREG_XG_OFFS_TC, 1,
+ &mldl_cfg->offset_tc[0]);
+ ERROR_CHECK(result);
+ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+ MPUREG_YG_OFFS_TC, 1,
+ &mldl_cfg->offset_tc[1]);
+ ERROR_CHECK(result);
+ result = MLSLSerialRead(mlsl_handle, mldl_cfg->addr,
+ MPUREG_ZG_OFFS_TC, 1,
+ &mldl_cfg->offset_tc[2]);
+ ERROR_CHECK(result);
+
+
+#ifdef M_HW
+ result = mpu60xx_pwr_mgmt(mldl_cfg, mlsl_handle,
+ FALSE, SLEEP);
+#else
+ result =
+ MLDLPowerMgmtMPU(mldl_cfg, mlsl_handle, 0, SLEEP, 0, 0, 0);
+#endif
+ ERROR_CHECK(result);
+
+ if (mldl_cfg->accel && mldl_cfg->accel->init) {
+ result = mldl_cfg->accel->init(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel);
+ ERROR_CHECK(result);
+ }
+
+ if (mldl_cfg->compass && mldl_cfg->compass->init) {
+ result = mldl_cfg->compass->init(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass);
+ if (ML_SUCCESS != result) {
+ MPL_LOGE("mldl_cfg->compass->init returned %d\n",
+ result);
+ goto out_accel;
+ }
+ }
+ if (mldl_cfg->pressure && mldl_cfg->pressure->init) {
+ result = mldl_cfg->pressure->init(pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure);
+ if (ML_SUCCESS != result) {
+ MPL_LOGE("mldl_cfg->pressure->init returned %d\n",
+ result);
+ goto out_compass;
+ }
+ }
+
+ mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO;
+ if (mldl_cfg->accel && mldl_cfg->accel->resume)
+ mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL;
+
+ if (mldl_cfg->compass && mldl_cfg->compass->resume)
+ mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS;
+
+ if (mldl_cfg->pressure && mldl_cfg->pressure->resume)
+ mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE;
+
+ return result;
+
+out_compass:
+ if (mldl_cfg->compass->init)
+ mldl_cfg->compass->exit(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass);
+out_accel:
+ if (mldl_cfg->accel->init)
+ mldl_cfg->accel->exit(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel);
+ return result;
+
+}
+
+int mpu3050_close(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle)
+{
+ int result = ML_SUCCESS;
+ int ret_result = ML_SUCCESS;
+
+ if (mldl_cfg->accel && mldl_cfg->accel->exit) {
+ result = mldl_cfg->accel->exit(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel);
+ if (ML_SUCCESS != result)
+ MPL_LOGE("Accel exit failed %d\n", result);
+ ret_result = result;
+ }
+ if (ML_SUCCESS == ret_result)
+ ret_result = result;
+
+ if (mldl_cfg->compass && mldl_cfg->compass->exit) {
+ result = mldl_cfg->compass->exit(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass);
+ if (ML_SUCCESS != result)
+ MPL_LOGE("Compass exit failed %d\n", result);
+ }
+ if (ML_SUCCESS == ret_result)
+ ret_result = result;
+
+ if (mldl_cfg->pressure && mldl_cfg->pressure->exit) {
+ result = mldl_cfg->pressure->exit(pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure);
+ if (ML_SUCCESS != result)
+ MPL_LOGE("Pressure exit failed %d\n", result);
+ }
+ if (ML_SUCCESS == ret_result)
+ ret_result = result;
+
+ return ret_result;
+}
+
+int mpu3050_resume(struct mldl_cfg *mldl_cfg,
+ void *gyro_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle,
+ bool resume_gyro,
+ bool resume_accel,
+ bool resume_compass,
+ bool resume_pressure)
+{
+ int result = ML_SUCCESS;
+
+#ifdef CONFIG_MPU_SENSORS_DEBUG
+ mpu_print_cfg(mldl_cfg);
+#endif
+
+ if (resume_accel &&
+ ((!mldl_cfg->accel) || (!mldl_cfg->accel->resume)))
+ return ML_ERROR_INVALID_PARAMETER;
+ if (resume_compass &&
+ ((!mldl_cfg->compass) || (!mldl_cfg->compass->resume)))
+ return ML_ERROR_INVALID_PARAMETER;
+ if (resume_pressure &&
+ ((!mldl_cfg->pressure) || (!mldl_cfg->pressure->resume)))
+ return ML_ERROR_INVALID_PARAMETER;
+
+ if (resume_gyro && mldl_cfg->gyro_is_suspended) {
+ result = gyro_resume(mldl_cfg, gyro_handle);
+ ERROR_CHECK(result);
+ }
+
+ if (resume_accel && mldl_cfg->accel_is_suspended) {
+ if (!mldl_cfg->gyro_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+ ERROR_CHECK(result);
+ }
+ result = mldl_cfg->accel->resume(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel);
+ ERROR_CHECK(result);
+ mldl_cfg->accel_is_suspended = FALSE;
+ }
+
+ if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->accel_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+ result = mpu_set_slave(mldl_cfg,
+ gyro_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel);
+ ERROR_CHECK(result);
+ }
+
+ if (resume_compass && mldl_cfg->compass_is_suspended) {
+ if (!mldl_cfg->gyro_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+ ERROR_CHECK(result);
+ }
+ result = mldl_cfg->compass->resume(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->
+ compass);
+ ERROR_CHECK(result);
+ mldl_cfg->compass_is_suspended = FALSE;
+ }
+
+ if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->compass_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
+ result = mpu_set_slave(mldl_cfg,
+ gyro_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass);
+ ERROR_CHECK(result);
+ }
+
+ if (resume_pressure && mldl_cfg->pressure_is_suspended) {
+ if (!mldl_cfg->gyro_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, TRUE);
+ ERROR_CHECK(result);
+ }
+ result = mldl_cfg->pressure->resume(pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->
+ pressure);
+ ERROR_CHECK(result);
+ mldl_cfg->pressure_is_suspended = FALSE;
+ }
+
+ if (!mldl_cfg->gyro_is_suspended && !mldl_cfg->pressure_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
+ result = mpu_set_slave(mldl_cfg,
+ gyro_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure);
+ ERROR_CHECK(result);
+ }
+
+
+ if (resume_gyro) {
+ result = dmp_start(mldl_cfg, gyro_handle);
+ ERROR_CHECK(result);
+ }
+
+ return result;
+}
+
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg,
+ void *gyro_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle,
+ bool suspend_gyro,
+ bool suspend_accel,
+ bool suspend_compass,
+ bool suspend_pressure)
+{
+ int result = ML_SUCCESS;
+
+ if (suspend_gyro && !mldl_cfg->gyro_is_suspended) {
+#ifdef M_HW
+ return ML_SUCCESS;
+
+ result = MLDLSetI2CBypass(mldl_cfg, gyro_handle, 1);
+ ERROR_CHECK(result);
+ result = mpu60xx_pwr_mgmt(mldl_cfg, gyro_handle, 0, SLEEP);
+#else
+ result = MLDLPowerMgmtMPU(mldl_cfg, gyro_handle,
+ 0, SLEEP, 0, 0, 0);
+#endif
+ ERROR_CHECK(result);
+ }
+
+ if (!mldl_cfg->accel_is_suspended && suspend_accel &&
+ mldl_cfg->accel && mldl_cfg->accel->suspend) {
+ if (!mldl_cfg->gyro_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus) {
+ result = mpu_set_slave(mldl_cfg, gyro_handle,
+ NULL, NULL);
+ ERROR_CHECK(result);
+ }
+ result = mldl_cfg->accel->suspend(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel);
+ ERROR_CHECK(result);
+ mldl_cfg->accel_is_suspended = TRUE;
+ }
+
+ if (!mldl_cfg->compass_is_suspended && suspend_compass &&
+ mldl_cfg->compass && mldl_cfg->compass->suspend) {
+ if (!mldl_cfg->gyro_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus) {
+ result = mpu_set_slave(mldl_cfg, gyro_handle,
+ NULL, NULL);
+ ERROR_CHECK(result);
+ }
+ result = mldl_cfg->compass->suspend(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->
+ pdata->compass);
+ ERROR_CHECK(result);
+ mldl_cfg->compass_is_suspended = TRUE;
+ }
+
+ if (!mldl_cfg->pressure_is_suspended && suspend_pressure &&
+ mldl_cfg->pressure && mldl_cfg->pressure->suspend) {
+ if (!mldl_cfg->gyro_is_suspended &&
+ EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus) {
+ result = mpu_set_slave(mldl_cfg, gyro_handle,
+ NULL, NULL);
+ ERROR_CHECK(result);
+ }
+ result = mldl_cfg->pressure->suspend(pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->
+ pdata->pressure);
+ ERROR_CHECK(result);
+ mldl_cfg->pressure_is_suspended = TRUE;
+ }
+ return result;
+}
+
+
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg,
+ void *accel_handle, unsigned char *data)
+{
+ if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->read)
+ if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->accel.bus)
+ && (!mldl_cfg->gyro_is_bypassed))
+ return ML_ERROR_FEATURE_NOT_ENABLED;
+ else
+ return mldl_cfg->accel->read(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg,
+ void *compass_handle, unsigned char *data)
+{
+ if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->read)
+ if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->compass.bus)
+ && (!mldl_cfg->gyro_is_bypassed))
+ return ML_ERROR_FEATURE_NOT_ENABLED;
+ else
+ return mldl_cfg->compass->read(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg,
+ void *pressure_handle, unsigned char *data)
+{
+ if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->read)
+ if ((EXT_SLAVE_BUS_SECONDARY == mldl_cfg->pdata->pressure.bus)
+ && (!mldl_cfg->gyro_is_bypassed))
+ return ML_ERROR_FEATURE_NOT_ENABLED;
+ else
+ return mldl_cfg->pressure->read(
+ pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+int mpu3050_config_accel(struct mldl_cfg *mldl_cfg,
+ void *accel_handle,
+ struct ext_slave_config *data)
+{
+ if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->config)
+ return mldl_cfg->accel->config(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+}
+
+int mpu3050_config_compass(struct mldl_cfg *mldl_cfg,
+ void *compass_handle,
+ struct ext_slave_config *data)
+{
+ if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->config)
+ return mldl_cfg->compass->config(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+}
+
+int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg,
+ void *pressure_handle,
+ struct ext_slave_config *data)
+{
+ if (NULL != mldl_cfg->pressure && NULL != mldl_cfg->pressure->config)
+ return mldl_cfg->pressure->config(pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg,
+ void *accel_handle,
+ struct ext_slave_config *data)
+{
+ if (NULL != mldl_cfg->accel && NULL != mldl_cfg->accel->get_config)
+ return mldl_cfg->accel->get_config(accel_handle,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+}
+
+int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg,
+ void *compass_handle,
+ struct ext_slave_config *data)
+{
+ if (NULL != mldl_cfg->compass && NULL != mldl_cfg->compass->get_config)
+ return mldl_cfg->compass->get_config(compass_handle,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+
+}
+
+int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg,
+ void *pressure_handle,
+ struct ext_slave_config *data)
+{
+ if (NULL != mldl_cfg->pressure &&
+ NULL != mldl_cfg->pressure->get_config)
+ return mldl_cfg->pressure->get_config(pressure_handle,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure,
+ data);
+ else
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+
diff --git a/drivers/input/misc/mpu3050/mldl_cfg.h b/drivers/input/misc/mpu3050/mldl_cfg.h
new file mode 100644
index 0000000..f838565
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mldl_cfg.h
@@ -0,0 +1,178 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+
+#ifndef __MLDL_CFG_H__
+#define __MLDL_CFG_H__
+
+
+#include "mlsl.h"
+#include "mpu.h"
+
+
+
+
+
+
+#define ML_X_GYRO (0x0001)
+#define ML_Y_GYRO (0x0002)
+#define ML_Z_GYRO (0x0004)
+#define ML_DMP_PROCESSOR (0x0008)
+
+#define ML_X_ACCEL (0x0010)
+#define ML_Y_ACCEL (0x0020)
+#define ML_Z_ACCEL (0x0040)
+
+#define ML_X_COMPASS (0x0080)
+#define ML_Y_COMPASS (0x0100)
+#define ML_Z_COMPASS (0x0200)
+
+#define ML_X_PRESSURE (0x0300)
+#define ML_Y_PRESSURE (0x0800)
+#define ML_Z_PRESSURE (0x1000)
+
+#define ML_TEMPERATURE (0x2000)
+#define ML_TIME (0x4000)
+
+#define ML_THREE_AXIS_GYRO (0x000F)
+#define ML_THREE_AXIS_ACCEL (0x0070)
+#define ML_THREE_AXIS_COMPASS (0x0380)
+#define ML_THREE_AXIS_PRESSURE (0x1C00)
+
+#define ML_FIVE_AXIS (0x007B)
+#define ML_SIX_AXIS_GYRO_ACCEL (0x007F)
+#define ML_SIX_AXIS_ACCEL_COMPASS (0x03F0)
+#define ML_NINE_AXIS (0x03FF)
+#define ML_ALL_SENSORS (0x7FFF)
+
+#define SAMPLING_RATE_HZ(mldl_cfg) \
+ ((((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \
+ ? (8000) \
+ : (1000)) \
+ / ((mldl_cfg)->divider + 1))
+
+#define SAMPLING_PERIOD_US(mldl_cfg) \
+ ((1000000L * ((mldl_cfg)->divider + 1)) / \
+ (((((mldl_cfg)->lpf) == 0) || (((mldl_cfg)->lpf) == 7)) \
+ ? (8000) \
+ : (1000)))
+
+struct mldl_cfg {
+
+ unsigned long requested_sensors;
+ unsigned char addr;
+ unsigned char int_config;
+ unsigned char ext_sync;
+ unsigned char full_scale;
+ unsigned char lpf;
+ unsigned char clk_src;
+ unsigned char divider;
+ unsigned char dmp_enable;
+ unsigned char fifo_enable;
+ unsigned char dmp_cfg1;
+ unsigned char dmp_cfg2;
+ unsigned char gyro_power;
+ unsigned char offset_tc[MPU_NUM_AXES];
+ unsigned short offset[MPU_NUM_AXES];
+ unsigned char ram[MPU_MEM_NUM_RAM_BANKS][MPU_MEM_BANK_SIZE];
+
+
+ unsigned char silicon_revision;
+ unsigned char product_id;
+ unsigned short trim;
+
+
+ int gyro_is_bypassed;
+ int dmp_is_running;
+ int gyro_is_suspended;
+ int accel_is_suspended;
+ int compass_is_suspended;
+ int pressure_is_suspended;
+ int gyro_needs_reset;
+
+
+ struct ext_slave_descr *accel;
+ struct ext_slave_descr *compass;
+ struct ext_slave_descr *pressure;
+
+
+ struct mpu3050_platform_data *pdata;
+};
+
+
+int mpu3050_open(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle);
+int mpu3050_close(struct mldl_cfg *mldl_cfg,
+ void *mlsl_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle);
+int mpu3050_resume(struct mldl_cfg *mldl_cfg,
+ void *gyro_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle,
+ bool resume_gyro,
+ bool resume_accel,
+ bool resume_compass,
+ bool resume_pressure);
+int mpu3050_suspend(struct mldl_cfg *mldl_cfg,
+ void *gyro_handle,
+ void *accel_handle,
+ void *compass_handle,
+ void *pressure_handle,
+ bool suspend_gyro,
+ bool suspend_accel,
+ bool suspend_compass,
+ bool suspend_pressure);
+int mpu3050_read_accel(struct mldl_cfg *mldl_cfg,
+ void *accel_handle,
+ unsigned char *data);
+int mpu3050_read_compass(struct mldl_cfg *mldl_cfg,
+ void *compass_handle,
+ unsigned char *data);
+int mpu3050_read_pressure(struct mldl_cfg *mldl_cfg, void *mlsl_handle,
+ unsigned char *data);
+
+int mpu3050_config_accel(struct mldl_cfg *mldl_cfg,
+ void *accel_handle,
+ struct ext_slave_config *data);
+int mpu3050_config_compass(struct mldl_cfg *mldl_cfg,
+ void *compass_handle,
+ struct ext_slave_config *data);
+int mpu3050_config_pressure(struct mldl_cfg *mldl_cfg,
+ void *pressure_handle,
+ struct ext_slave_config *data);
+
+int mpu3050_get_config_accel(struct mldl_cfg *mldl_cfg,
+ void *accel_handle,
+ struct ext_slave_config *data);
+int mpu3050_get_config_compass(struct mldl_cfg *mldl_cfg,
+ void *compass_handle,
+ struct ext_slave_config *data);
+int mpu3050_get_config_pressure(struct mldl_cfg *mldl_cfg,
+ void *pressure_handle,
+ struct ext_slave_config *data);
+
+
+#endif
+
diff --git a/drivers/input/misc/mpu3050/mlos-kernel.c b/drivers/input/misc/mpu3050/mlos-kernel.c
new file mode 100644
index 0000000..22c5e07
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mlos-kernel.c
@@ -0,0 +1,79 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#include "mlos.h"
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+void *MLOSMalloc(unsigned int numBytes)
+{
+ return kmalloc(numBytes, GFP_KERNEL);
+}
+
+tMLError MLOSFree(void *ptr)
+{
+ kfree(ptr);
+ return ML_SUCCESS;
+}
+
+tMLError MLOSCreateMutex(HANDLE *mutex)
+{
+
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+tMLError MLOSLockMutex(HANDLE mutex)
+{
+
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+tMLError MLOSUnlockMutex(HANDLE mutex)
+{
+
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+tMLError MLOSDestroyMutex(HANDLE handle)
+{
+
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
+
+FILE *MLOSFOpen(char *filename)
+{
+
+ return NULL;
+}
+
+void MLOSFClose(FILE *fp)
+{
+
+}
+
+void MLOSSleep(int mSecs)
+{
+ msleep(mSecs);
+}
+
+unsigned long MLOSGetTickCount(void)
+{
+
+ return ML_ERROR_FEATURE_NOT_IMPLEMENTED;
+}
diff --git a/drivers/input/misc/mpu3050/mlos.h b/drivers/input/misc/mpu3050/mlos.h
new file mode 100644
index 0000000..c0668574
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mlos.h
@@ -0,0 +1,73 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef _MLOS_H
+#define _MLOS_H
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#endif
+
+#include "mltypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+
+
+
+#define MLOS_GENERIC_READ ((unsigned int)0x80000000)
+#define MLOS_GENERIC_WRITE ((unsigned int)0x40000000)
+#define MLOS_FILE_SHARE_READ ((unsigned int)0x00000001)
+#define MLOS_FILE_SHARE_WRITE ((unsigned int)0x00000002)
+#define MLOS_OPEN_EXISTING ((unsigned int)0x00000003)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ void *MLOSMalloc(unsigned int numBytes);
+ tMLError MLOSFree(void *ptr);
+ tMLError MLOSCreateMutex(HANDLE *mutex);
+ tMLError MLOSLockMutex(HANDLE mutex);
+ tMLError MLOSUnlockMutex(HANDLE mutex);
+ FILE *MLOSFOpen(char *filename);
+ void MLOSFClose(FILE *fp);
+
+ tMLError MLOSDestroyMutex(HANDLE handle);
+
+ void MLOSSleep(int mSecs);
+ unsigned long MLOSGetTickCount(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/drivers/input/misc/mpu3050/mlsl-kernel.c b/drivers/input/misc/mpu3050/mlsl-kernel.c
new file mode 100644
index 0000000..d5bc256
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mlsl-kernel.c
@@ -0,0 +1,229 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#include "mlsl.h"
+#include "mpu-i2c.h"
+
+
+
+
+tMLError MLSLSerialOpen(char const *port, void **sl_handle)
+{
+ return ML_SUCCESS;
+}
+
+tMLError MLSLSerialReset(void *sl_handle)
+{
+ return ML_SUCCESS;
+}
+
+tMLError MLSLSerialClose(void *sl_handle)
+{
+ return ML_SUCCESS;
+}
+
+tMLError MLSLSerialWriteSingle(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned char registerAddr,
+ unsigned char data)
+{
+ return sensor_i2c_write_register((struct i2c_adapter *) sl_handle,
+ slaveAddr, registerAddr, data);
+}
+
+
+tMLError MLSLSerialWrite(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length, unsigned char const *data)
+{
+ tMLError result;
+ const unsigned short dataLength = length - 1;
+ const unsigned char startRegAddr = data[0];
+ unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1];
+ unsigned short bytesWritten = 0;
+
+ while (bytesWritten < dataLength) {
+ unsigned short thisLen = min(SERIAL_MAX_TRANSFER_SIZE,
+ dataLength - bytesWritten);
+ if (bytesWritten == 0) {
+ result = sensor_i2c_write((struct i2c_adapter *)
+ sl_handle, slaveAddr,
+ 1 + thisLen, data);
+ } else {
+
+ i2cWrite[0] = startRegAddr + bytesWritten;
+ memcpy(&i2cWrite[1], &data[1 + bytesWritten],
+ thisLen);
+ result = sensor_i2c_write((struct i2c_adapter *)
+ sl_handle, slaveAddr,
+ 1 + thisLen, i2cWrite);
+ }
+ if (ML_SUCCESS != result)
+ return result;
+ bytesWritten += thisLen;
+ }
+ return ML_SUCCESS;
+}
+
+
+tMLError MLSLSerialRead(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned char registerAddr,
+ unsigned short length, unsigned char *data)
+{
+ tMLError result;
+ unsigned short bytesRead = 0;
+
+ if (registerAddr == MPUREG_FIFO_R_W
+ || registerAddr == MPUREG_MEM_R_W) {
+ return ML_ERROR_INVALID_PARAMETER;
+ }
+ while (bytesRead < length) {
+ unsigned short thisLen =
+ min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
+ result =
+ sensor_i2c_read((struct i2c_adapter *) sl_handle,
+ slaveAddr, registerAddr + bytesRead,
+ thisLen, &data[bytesRead]);
+ if (ML_SUCCESS != result)
+ return result;
+ bytesRead += thisLen;
+ }
+ return ML_SUCCESS;
+}
+
+
+tMLError MLSLSerialWriteMem(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short memAddr,
+ unsigned short length,
+ unsigned char const *data)
+{
+ tMLError result;
+ unsigned short bytesWritten = 0;
+
+ if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) {
+ printk
+ ("memory read length (%d B) extends beyond its limits (%d) "
+ "if started at location %d\n", length,
+ MPU_MEM_BANK_SIZE, memAddr & 0xFF);
+ return ML_ERROR_INVALID_PARAMETER;
+ }
+ while (bytesWritten < length) {
+ unsigned short thisLen =
+ min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten);
+ result =
+ mpu_memory_write((struct i2c_adapter *) sl_handle,
+ slaveAddr, memAddr + bytesWritten,
+ thisLen, &data[bytesWritten]);
+ if (ML_SUCCESS != result)
+ return result;
+ bytesWritten += thisLen;
+ }
+ return ML_SUCCESS;
+}
+
+
+tMLError MLSLSerialReadMem(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short memAddr,
+ unsigned short length, unsigned char *data)
+{
+ tMLError result;
+ unsigned short bytesRead = 0;
+
+ if ((memAddr & 0xFF) + length > MPU_MEM_BANK_SIZE) {
+ printk
+ ("memory read length (%d B) extends beyond its limits (%d) "
+ "if started at location %d\n", length,
+ MPU_MEM_BANK_SIZE, memAddr & 0xFF);
+ return ML_ERROR_INVALID_PARAMETER;
+ }
+ while (bytesRead < length) {
+ unsigned short thisLen =
+ min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
+ result =
+ mpu_memory_read((struct i2c_adapter *) sl_handle,
+ slaveAddr, memAddr + bytesRead,
+ thisLen, &data[bytesRead]);
+ if (ML_SUCCESS != result)
+ return result;
+ bytesRead += thisLen;
+ }
+ return ML_SUCCESS;
+}
+
+
+tMLError MLSLSerialWriteFifo(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char const *data)
+{
+ tMLError result;
+ unsigned char i2cWrite[SERIAL_MAX_TRANSFER_SIZE + 1];
+ unsigned short bytesWritten = 0;
+
+ if (length > FIFO_HW_SIZE) {
+ printk(KERN_ERR
+ "maximum fifo write length is %d\n", FIFO_HW_SIZE);
+ return ML_ERROR_INVALID_PARAMETER;
+ }
+ while (bytesWritten < length) {
+ unsigned short thisLen =
+ min(SERIAL_MAX_TRANSFER_SIZE, length - bytesWritten);
+ i2cWrite[0] = MPUREG_FIFO_R_W;
+ memcpy(&i2cWrite[1], &data[bytesWritten], thisLen);
+ result = sensor_i2c_write((struct i2c_adapter *) sl_handle,
+ slaveAddr, thisLen + 1,
+ i2cWrite);
+ if (ML_SUCCESS != result)
+ return result;
+ bytesWritten += thisLen;
+ }
+ return ML_SUCCESS;
+}
+
+
+tMLError MLSLSerialReadFifo(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length, unsigned char *data)
+{
+ tMLError result;
+ unsigned short bytesRead = 0;
+
+ if (length > FIFO_HW_SIZE) {
+ printk(KERN_ERR
+ "maximum fifo read length is %d\n", FIFO_HW_SIZE);
+ return ML_ERROR_INVALID_PARAMETER;
+ }
+ while (bytesRead < length) {
+ unsigned short thisLen =
+ min(SERIAL_MAX_TRANSFER_SIZE, length - bytesRead);
+ result =
+ sensor_i2c_read((struct i2c_adapter *) sl_handle,
+ slaveAddr, MPUREG_FIFO_R_W, thisLen,
+ &data[bytesRead]);
+ if (ML_SUCCESS != result)
+ return result;
+ bytesRead += thisLen;
+ }
+
+ return ML_SUCCESS;
+}
+
diff --git a/drivers/input/misc/mpu3050/mlsl.h b/drivers/input/misc/mpu3050/mlsl.h
new file mode 100644
index 0000000..e1e796c
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mlsl.h
@@ -0,0 +1,86 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef __MSSL_H__
+#define __MSSL_H__
+
+#include "mltypes.h"
+#include "mpu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define SERIAL_MAX_TRANSFER_SIZE 128
+
+
+
+ tMLError MLSLSerialOpen(char const *port,
+ void **sl_handle);
+ tMLError MLSLSerialReset(void *sl_handle);
+ tMLError MLSLSerialClose(void *sl_handle);
+
+ tMLError MLSLSerialWriteSingle(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned char registerAddr,
+ unsigned char data);
+
+ tMLError MLSLSerialRead(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned char registerAddr,
+ unsigned short length,
+ unsigned char *data);
+
+ tMLError MLSLSerialWrite(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char const *data);
+
+ tMLError MLSLSerialReadMem(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short memAddr,
+ unsigned short length,
+ unsigned char *data);
+
+ tMLError MLSLSerialWriteMem(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short memAddr,
+ unsigned short length,
+ unsigned char const *data);
+
+ tMLError MLSLSerialReadFifo(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char *data);
+
+ tMLError MLSLSerialWriteFifo(void *sl_handle,
+ unsigned char slaveAddr,
+ unsigned short length,
+ unsigned char const *data);
+
+ tMLError MLSLWriteCal(unsigned char *cal, unsigned int len);
+ tMLError MLSLReadCal(unsigned char *cal, unsigned int len);
+ tMLError MLSLGetCalLength(unsigned int *len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/input/misc/mpu3050/mltypes.h b/drivers/input/misc/mpu3050/mltypes.h
new file mode 100644
index 0000000..d3f4acc
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mltypes.h
@@ -0,0 +1,138 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+
+#ifndef MLTYPES_H
+#define MLTYPES_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include "stdint_invensense.h"
+#endif
+#include "log.h"
+
+
+typedef unsigned char tMLError;
+
+#if defined(LINUX) || defined(__KERNEL__)
+typedef unsigned int HANDLE;
+#endif
+
+#ifdef __KERNEL__
+typedef HANDLE FILE;
+#endif
+
+#ifndef __cplusplus
+#ifndef __KERNEL__
+typedef int_fast8_t bool;
+#endif
+#endif
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef DIM
+#define DIM(array) (sizeof(array)/sizeof((array)[0]))
+#endif
+
+#define ERROR_NAME(x) (#x)
+#define ERROR_CHECK(x) \
+ { \
+ if (ML_SUCCESS != x) { \
+ MPL_LOGE("[mpu_err]%s|%s|%d returning %d\n", \
+ __FILE__, __func__, __LINE__, x); \
+ return x; \
+ } \
+ }
+
+#define ERROR_CHECK_FIRST(first, x) \
+ { if (ML_SUCCESS == first) first = x; }
+
+#define ML_SUCCESS (0)
+#define ML_ERROR (1)
+
+#define ML_ERROR_INVALID_PARAMETER (2)
+#define ML_ERROR_FEATURE_NOT_ENABLED (3)
+#define ML_ERROR_FEATURE_NOT_IMPLEMENTED (4)
+#define ML_ERROR_DMP_NOT_STARTED (6)
+#define ML_ERROR_DMP_STARTED (7)
+#define ML_ERROR_NOT_OPENED (8)
+#define ML_ERROR_OPENED (9)
+#define ML_ERROR_INVALID_MODULE (10)
+#define ML_ERROR_MEMORY_EXAUSTED (11)
+#define ML_ERROR_DIVIDE_BY_ZERO (12)
+#define ML_ERROR_ASSERTION_FAILURE (13)
+#define ML_ERROR_FILE_OPEN (14)
+#define ML_ERROR_FILE_READ (15)
+#define ML_ERROR_FILE_WRITE (16)
+#define ML_ERROR_INVALID_CONFIGURATION (17)
+
+#define ML_ERROR_SERIAL_CLOSED (20)
+#define ML_ERROR_SERIAL_OPEN_ERROR (21)
+#define ML_ERROR_SERIAL_READ (22)
+#define ML_ERROR_SERIAL_WRITE (23)
+#define ML_ERROR_SERIAL_DEVICE_NOT_RECOGNIZED (24)
+
+#define ML_ERROR_SM_TRANSITION (25)
+#define ML_ERROR_SM_IMPROPER_STATE (26)
+
+#define ML_ERROR_FIFO_OVERFLOW (30)
+#define ML_ERROR_FIFO_FOOTER (31)
+#define ML_ERROR_FIFO_READ_COUNT (32)
+#define ML_ERROR_FIFO_READ_DATA (33)
+
+#define ML_ERROR_MEMORY_SET (40)
+
+#define ML_ERROR_LOG_MEMORY_ERROR (50)
+#define ML_ERROR_LOG_OUTPUT_ERROR (51)
+
+#define ML_ERROR_OS_BAD_PTR (60)
+#define ML_ERROR_OS_BAD_HANDLE (61)
+#define ML_ERROR_OS_CREATE_FAILED (62)
+#define ML_ERROR_OS_LOCK_FAILED (63)
+
+#define ML_ERROR_COMPASS_DATA_OVERFLOW (70)
+#define ML_ERROR_COMPASS_DATA_UNDERFLOW (71)
+#define ML_ERROR_COMPASS_DATA_NOT_READY (72)
+#define ML_ERROR_COMPASS_DATA_ERROR (73)
+
+#define ML_ERROR_CALIBRATION_LOAD (75)
+#define ML_ERROR_CALIBRATION_STORE (76)
+#define ML_ERROR_CALIBRATION_LEN (77)
+#define ML_ERROR_CALIBRATION_CHECKSUM (78)
+
+#define ML_ERROR_ACCEL_DATA_OVERFLOW (79)
+#define ML_ERROR_ACCEL_DATA_UNDERFLOW (80)
+#define ML_ERROR_ACCEL_DATA_NOT_READY (81)
+#define ML_ERROR_ACCEL_DATA_ERROR (82)
+
+
+
+#endif
diff --git a/drivers/input/misc/mpu3050/mpu-dev.c b/drivers/input/misc/mpu3050/mpu-dev.c
new file mode 100644
index 0000000..a641af8
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mpu-dev.c
@@ -0,0 +1,1480 @@
+/*
+ mpu-dev.c - mpu3050 char device interface
+
+ Copyright (C) 1995-97 Simon G. Vogl
+ Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/pm.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "mpuirq.h"
+#include "slaveirq.h"
+#include "mlsl.h"
+#include "mpu-i2c.h"
+#include "mldl_cfg.h"
+#include "mpu.h"
+
+#define MPU3050_EARLY_SUSPEND_IN_DRIVER 0
+
+#define D(x...) printk(KERN_DEBUG "[GYRO][MPU3050] " x)
+#define I(x...) printk(KERN_INFO "[GYRO][MPU3050] " x)
+#define E(x...) printk(KERN_ERR "[GYRO][MPU3050 ERROR] " x)
+
+struct mpu_private_data {
+ struct mldl_cfg mldl_cfg;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+};
+
+static int pid;
+
+static struct i2c_client *this_client;
+
+int mpu_debug_flag;
+int mpu_sensors_reset;
+int mpu_lpm_flag;
+
+static int mpu_open(struct inode *inode, struct file *file)
+{
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(this_client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+
+ dev_dbg(&this_client->adapter->dev, "mpu_open\n");
+ dev_dbg(&this_client->adapter->dev, "current->pid %d\n",
+ current->pid);
+ pid = current->pid;
+ file->private_data = this_client;
+
+
+
+
+
+ mldl_cfg->requested_sensors = ML_THREE_AXIS_GYRO;
+ if (mldl_cfg->accel && mldl_cfg->accel->resume)
+ mldl_cfg->requested_sensors |= ML_THREE_AXIS_ACCEL;
+
+ if (mldl_cfg->compass && mldl_cfg->compass->resume)
+ mldl_cfg->requested_sensors |= ML_THREE_AXIS_COMPASS;
+
+ if (mldl_cfg->pressure && mldl_cfg->pressure->resume)
+ mldl_cfg->requested_sensors |= ML_THREE_AXIS_PRESSURE;
+
+ return 0;
+}
+
+static int mpu_release(struct inode *inode, struct file *file)
+{
+ struct i2c_client *client =
+ (struct i2c_client *) file->private_data;
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+ int result = 0;
+
+ pid = 0;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter = i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter = i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+ result = mpu3050_suspend(mldl_cfg, client->adapter,
+ accel_adapter, compass_adapter,
+ pressure_adapter,
+ TRUE, TRUE, TRUE, TRUE);
+
+ dev_dbg(&this_client->adapter->dev, "mpu_release\n");
+ return result;
+}
+
+static noinline int mpudev_ioctl_rdrw(struct i2c_client *client,
+ unsigned long arg)
+{
+ struct i2c_rdwr_ioctl_data rdwr_arg;
+ struct i2c_msg *rdwr_pa;
+ u8 __user **data_ptrs;
+ int i, res;
+
+ if (copy_from_user(&rdwr_arg,
+ (struct i2c_rdwr_ioctl_data __user *) arg,
+ sizeof(rdwr_arg)))
+ return -EFAULT;
+
+ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+ return -EINVAL;
+
+ rdwr_pa = (struct i2c_msg *)
+ kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
+ if (!rdwr_pa)
+ return -ENOMEM;
+
+ if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
+ rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
+ kfree(rdwr_pa);
+ return -EFAULT;
+ }
+
+ data_ptrs =
+ kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
+ if (data_ptrs == NULL) {
+ kfree(rdwr_pa);
+ return -ENOMEM;
+ }
+
+ res = 0;
+ for (i = 0; i < rdwr_arg.nmsgs; i++) {
+ if ((rdwr_pa[i].len > 8192) ||
+ (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
+ res = -EINVAL;
+ break;
+ }
+ data_ptrs[i] = (u8 __user *) rdwr_pa[i].buf;
+ rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
+ if (rdwr_pa[i].buf == NULL) {
+ res = -ENOMEM;
+ break;
+ }
+ if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
+ rdwr_pa[i].len)) {
+ ++i;
+ res = -EFAULT;
+ break;
+ }
+ }
+ if (res < 0) {
+ int j;
+ for (j = 0; j < i; ++j)
+ kfree(rdwr_pa[j].buf);
+ kfree(data_ptrs);
+ kfree(rdwr_pa);
+ return res;
+ }
+
+ res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);
+ while (i-- > 0) {
+ if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) {
+ if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf,
+ rdwr_pa[i].len))
+ res = -EFAULT;
+ }
+ kfree(rdwr_pa[i].buf);
+ }
+ kfree(data_ptrs);
+ kfree(rdwr_pa);
+ return res;
+}
+
+static ssize_t mpu_read(struct file *file,
+ char __user *buf, size_t count, loff_t *offset)
+{
+ char *tmp;
+ int ret;
+
+ struct i2c_client *client =
+ (struct i2c_client *) file->private_data;
+
+ if (count > 8192)
+ count = 8192;
+
+ tmp = kmalloc(count, GFP_KERNEL);
+ if (tmp == NULL)
+ return -ENOMEM;
+
+ pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n",
+ iminor(file->f_path.dentry->d_inode), count);
+
+ ret = i2c_master_recv(client, tmp, count);
+ if (ret >= 0) {
+ ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret;
+ if (ret)
+ ret = -EFAULT;
+ }
+ kfree(tmp);
+ return ret;
+}
+
+static int
+mpu_ioctl_set_mpu_pdata(struct i2c_client *client, unsigned long arg)
+{
+ int ii;
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mpu3050_platform_data *pdata = mpu->mldl_cfg.pdata;
+ struct mpu3050_platform_data local_pdata;
+
+ if (copy_from_user(&local_pdata, (unsigned char __user *) arg,
+ sizeof(local_pdata)))
+ return -EFAULT;
+
+ pdata->int_config = local_pdata.int_config;
+ for (ii = 0; ii < DIM(pdata->orientation); ii++)
+ pdata->orientation[ii] = local_pdata.orientation[ii];
+ pdata->level_shifter = local_pdata.level_shifter;
+
+ pdata->accel.address = local_pdata.accel.address;
+ for (ii = 0; ii < DIM(pdata->accel.orientation); ii++)
+ pdata->accel.orientation[ii] =
+ local_pdata.accel.orientation[ii];
+
+ pdata->compass.address = local_pdata.compass.address;
+ for (ii = 0; ii < DIM(pdata->compass.orientation); ii++)
+ pdata->compass.orientation[ii] =
+ local_pdata.compass.orientation[ii];
+
+ pdata->pressure.address = local_pdata.pressure.address;
+ for (ii = 0; ii < DIM(pdata->pressure.orientation); ii++)
+ pdata->pressure.orientation[ii] =
+ local_pdata.pressure.orientation[ii];
+
+ dev_dbg(&client->adapter->dev, "%s\n", __func__);
+
+ return ML_SUCCESS;
+}
+
+static int
+mpu_ioctl_set_mpu_config(struct i2c_client *client, unsigned long arg)
+{
+ int ii;
+ int result = ML_SUCCESS;
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct mldl_cfg *temp_mldl_cfg;
+
+ dev_dbg(&this_client->adapter->dev, "%s\n", __func__);
+
+ temp_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
+ if (NULL == temp_mldl_cfg)
+ return -ENOMEM;
+
+ if (copy_from_user(temp_mldl_cfg, (struct mldl_cfg __user *) arg,
+ offsetof(struct mldl_cfg, silicon_revision))) {
+ result = -EFAULT;
+ goto out;
+ }
+
+ if (mldl_cfg->gyro_is_suspended) {
+ if (mldl_cfg->addr != temp_mldl_cfg->addr)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->int_config != temp_mldl_cfg->int_config)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->ext_sync != temp_mldl_cfg->ext_sync)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->full_scale != temp_mldl_cfg->full_scale)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->lpf != temp_mldl_cfg->lpf)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->clk_src != temp_mldl_cfg->clk_src)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->divider != temp_mldl_cfg->divider)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->dmp_enable != temp_mldl_cfg->dmp_enable)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->fifo_enable != temp_mldl_cfg->fifo_enable)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->dmp_cfg1 != temp_mldl_cfg->dmp_cfg1)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->dmp_cfg2 != temp_mldl_cfg->dmp_cfg2)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (mldl_cfg->gyro_power != temp_mldl_cfg->gyro_power)
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ for (ii = 0; ii < MPU_NUM_AXES; ii++)
+ if (mldl_cfg->offset_tc[ii] !=
+ temp_mldl_cfg->offset_tc[ii])
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ for (ii = 0; ii < MPU_NUM_AXES; ii++)
+ if (mldl_cfg->offset[ii] != temp_mldl_cfg->offset[ii])
+ mldl_cfg->gyro_needs_reset = TRUE;
+
+ if (memcmp(mldl_cfg->ram, temp_mldl_cfg->ram,
+ MPU_MEM_NUM_RAM_BANKS * MPU_MEM_BANK_SIZE *
+ sizeof(unsigned char)))
+ mldl_cfg->gyro_needs_reset = TRUE;
+ }
+
+ memcpy(mldl_cfg, temp_mldl_cfg,
+ offsetof(struct mldl_cfg, silicon_revision));
+
+out:
+ kfree(temp_mldl_cfg);
+ return result;
+}
+
+static int
+mpu_ioctl_get_mpu_config(struct i2c_client *client, unsigned long arg)
+{
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct mldl_cfg *local_mldl_cfg;
+ int retval = 0;
+
+ local_mldl_cfg = kzalloc(sizeof(struct mldl_cfg), GFP_KERNEL);
+ if (NULL == local_mldl_cfg)
+ return -ENOMEM;
+
+ retval =
+ copy_from_user(local_mldl_cfg, (struct mldl_cfg __user *) arg,
+ sizeof(struct mldl_cfg));
+ if (retval) {
+ dev_err(&this_client->adapter->dev,
+ "%s|%s:%d: EFAULT on arg\n",
+ __FILE__, __func__, __LINE__);
+ retval = -EFAULT;
+ goto out;
+ }
+
+
+ if (mldl_cfg->accel) {
+ retval = copy_to_user((void __user *)local_mldl_cfg->accel,
+ mldl_cfg->accel,
+ sizeof(*mldl_cfg->accel));
+ if (retval) {
+ dev_err(&this_client->adapter->dev,
+ "%s|%s:%d: EFAULT on accel\n",
+ __FILE__, __func__, __LINE__);
+ retval = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (mldl_cfg->compass) {
+ retval = copy_to_user((void __user *)local_mldl_cfg->compass,
+ mldl_cfg->compass,
+ sizeof(*mldl_cfg->compass));
+ if (retval) {
+ dev_err(&this_client->adapter->dev,
+ "%s|%s:%d: EFAULT on compass\n",
+ __FILE__, __func__, __LINE__);
+ retval = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (mldl_cfg->pressure) {
+ retval = copy_to_user((void __user *)local_mldl_cfg->pressure,
+ mldl_cfg->pressure,
+ sizeof(*mldl_cfg->pressure));
+ if (retval) {
+ dev_err(&this_client->adapter->dev,
+ "%s|%s:%d: EFAULT on pressure\n",
+ __FILE__, __func__, __LINE__);
+ retval = -EFAULT;
+ goto out;
+ }
+ }
+
+ if (mldl_cfg->pdata) {
+ retval = copy_to_user((void __user *)local_mldl_cfg->pdata,
+ mldl_cfg->pdata,
+ sizeof(*mldl_cfg->pdata));
+ if (retval) {
+ dev_err(&this_client->adapter->dev,
+ "%s|%s:%d: EFAULT on pdata\n",
+ __FILE__, __func__, __LINE__);
+ retval = -EFAULT;
+ goto out;
+ }
+ }
+
+
+ retval = copy_to_user((struct mldl_cfg __user *) arg,
+ mldl_cfg, offsetof(struct mldl_cfg, accel));
+
+ if (retval)
+ retval = -EFAULT;
+out:
+ kfree(local_mldl_cfg);
+ return retval;
+}
+
+static int slave_config(void *adapter,
+ struct mldl_cfg *mldl_cfg,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config __user *usr_config)
+{
+ int retval = ML_SUCCESS;
+ if ((slave) && (slave->config)) {
+ struct ext_slave_config config;
+ retval = copy_from_user(
+ &config,
+ usr_config,
+ sizeof(config));
+ if (retval)
+ return -EFAULT;
+
+ if (config.len && config.data) {
+ int *data;
+ data = kzalloc(config.len, GFP_KERNEL);
+ if (!data)
+ return ML_ERROR_MEMORY_EXAUSTED;
+
+ retval = copy_from_user(data,
+ (void __user *)config.data,
+ config.len);
+ if (retval) {
+ retval = -EFAULT;
+ kfree(data);
+ return retval;
+ }
+ config.data = data;
+ }
+ retval = slave->config(adapter,
+ slave,
+ pdata,
+ &config);
+ kfree(config.data);
+ }
+ return retval;
+}
+
+static int slave_get_config(void *adapter,
+ struct mldl_cfg *mldl_cfg,
+ struct ext_slave_descr *slave,
+ struct ext_slave_platform_data *pdata,
+ struct ext_slave_config __user *usr_config)
+{
+ int retval = ML_SUCCESS;
+ if ((slave) && (slave->get_config)) {
+ struct ext_slave_config config;
+ void *user_data;
+ retval = copy_from_user(
+ &config,
+ usr_config,
+ sizeof(config));
+ if (retval)
+ return -EFAULT;
+
+ user_data = config.data;
+ if (config.len && config.data) {
+ int *data;
+ data = kzalloc(config.len, GFP_KERNEL);
+ if (!data)
+ return ML_ERROR_MEMORY_EXAUSTED;
+
+ retval = copy_from_user(data,
+ (void __user *)config.data,
+ config.len);
+ if (retval) {
+ retval = -EFAULT;
+ kfree(data);
+ return retval;
+ }
+ config.data = data;
+ }
+ retval = slave->get_config(adapter,
+ slave,
+ pdata,
+ &config);
+ if (retval) {
+ kfree(config.data);
+ return retval;
+ }
+ retval = copy_to_user((unsigned char __user *) user_data,
+ config.data,
+ config.len);
+ kfree(config.data);
+ }
+ return retval;
+}
+
+static long mpu_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client =
+ (struct i2c_client *) file->private_data;
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ int retval = 0;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ switch (cmd) {
+ case I2C_RDWR:
+ mpudev_ioctl_rdrw(client, arg);
+ break;
+ case I2C_SLAVE:
+ if ((arg & 0x7E) != (client->addr & 0x7E)) {
+ dev_err(&this_client->adapter->dev,
+ "[mpu_err]%s: Invalid I2C_SLAVE arg %lu\n",
+ __func__, arg);
+ }
+ break;
+ case MPU_SET_MPU_CONFIG:
+ retval = mpu_ioctl_set_mpu_config(client, arg);
+ break;
+ case MPU_SET_INT_CONFIG:
+ mldl_cfg->int_config = (unsigned char) arg;
+ break;
+ case MPU_SET_EXT_SYNC:
+ mldl_cfg->ext_sync = (enum mpu_ext_sync) arg;
+ break;
+ case MPU_SET_FULL_SCALE:
+ mldl_cfg->full_scale = (enum mpu_fullscale) arg;
+ break;
+ case MPU_SET_LPF:
+ mldl_cfg->lpf = (enum mpu_filter) arg;
+ break;
+ case MPU_SET_CLK_SRC:
+ mldl_cfg->clk_src = (enum mpu_clock_sel) arg;
+ break;
+ case MPU_SET_DIVIDER:
+ mldl_cfg->divider = (unsigned char) arg;
+ break;
+ case MPU_SET_LEVEL_SHIFTER:
+ mldl_cfg->pdata->level_shifter = (unsigned char) arg;
+ break;
+ case MPU_SET_DMP_ENABLE:
+ mldl_cfg->dmp_enable = (unsigned char) arg;
+ break;
+ case MPU_SET_FIFO_ENABLE:
+ mldl_cfg->fifo_enable = (unsigned char) arg;
+ break;
+ case MPU_SET_DMP_CFG1:
+ mldl_cfg->dmp_cfg1 = (unsigned char) arg;
+ break;
+ case MPU_SET_DMP_CFG2:
+ mldl_cfg->dmp_cfg2 = (unsigned char) arg;
+ break;
+ case MPU_SET_OFFSET_TC:
+ retval = copy_from_user(mldl_cfg->offset_tc,
+ (unsigned char __user *) arg,
+ sizeof(mldl_cfg->offset_tc));
+ if (retval)
+ retval = -EFAULT;
+
+ break;
+ case MPU_SET_RAM:
+ retval = copy_from_user(mldl_cfg->ram,
+ (unsigned char __user *) arg,
+ sizeof(mldl_cfg->ram));
+ if (retval)
+ retval = -EFAULT;
+ break;
+ case MPU_SET_PLATFORM_DATA:
+ retval = mpu_ioctl_set_mpu_pdata(client, arg);
+ break;
+ case MPU_GET_MPU_CONFIG:
+ retval = mpu_ioctl_get_mpu_config(client, arg);
+ break;
+ case MPU_GET_INT_CONFIG:
+ retval = put_user(mldl_cfg->int_config,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_EXT_SYNC:
+ retval = put_user(mldl_cfg->ext_sync,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_FULL_SCALE:
+ retval = put_user(mldl_cfg->full_scale,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_LPF:
+ retval = put_user(mldl_cfg->lpf,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_CLK_SRC:
+ retval = put_user(mldl_cfg->clk_src,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_DIVIDER:
+ retval = put_user(mldl_cfg->divider,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_LEVEL_SHIFTER:
+ retval = put_user(mldl_cfg->pdata->level_shifter,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_DMP_ENABLE:
+ retval = put_user(mldl_cfg->dmp_enable,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_FIFO_ENABLE:
+ retval = put_user(mldl_cfg->fifo_enable,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_DMP_CFG1:
+ retval = put_user(mldl_cfg->dmp_cfg1,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_DMP_CFG2:
+ retval = put_user(mldl_cfg->dmp_cfg2,
+ (unsigned char __user *) arg);
+ break;
+ case MPU_GET_OFFSET_TC:
+ retval = copy_to_user((unsigned char __user *) arg,
+ mldl_cfg->offset_tc,
+ sizeof(mldl_cfg->offset_tc));
+ if (retval)
+ retval = -EFAULT;
+ break;
+ case MPU_GET_RAM:
+ retval = copy_to_user((unsigned char __user *) arg,
+ mldl_cfg->ram,
+ sizeof(mldl_cfg->ram));
+ if (retval)
+ retval = -EFAULT;
+ break;
+ case MPU_CONFIG_ACCEL:
+ retval = slave_config(accel_adapter, mldl_cfg,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel,
+ (struct ext_slave_config __user *) arg);
+ break;
+ case MPU_CONFIG_COMPASS:
+ retval = slave_config(compass_adapter, mldl_cfg,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass,
+ (struct ext_slave_config __user *) arg);
+ break;
+ case MPU_CONFIG_PRESSURE:
+ retval = slave_config(pressure_adapter, mldl_cfg,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure,
+ (struct ext_slave_config __user *) arg);
+ break;
+ case MPU_GET_CONFIG_ACCEL:
+ retval = slave_get_config(accel_adapter, mldl_cfg,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel,
+ (struct ext_slave_config __user *) arg);
+ break;
+ case MPU_GET_CONFIG_COMPASS:
+ retval = slave_get_config(compass_adapter, mldl_cfg,
+ mldl_cfg->compass,
+ &mldl_cfg->pdata->compass,
+ (struct ext_slave_config __user *) arg);
+ break;
+ case MPU_GET_CONFIG_PRESSURE:
+ retval = slave_get_config(pressure_adapter, mldl_cfg,
+ mldl_cfg->pressure,
+ &mldl_cfg->pdata->pressure,
+ (struct ext_slave_config __user *) arg);
+ break;
+ case MPU_SUSPEND:
+ {
+ unsigned long sensors;
+ sensors = ~(mldl_cfg->requested_sensors);
+ retval = mpu3050_suspend(mldl_cfg,
+ client->adapter,
+ accel_adapter,
+ compass_adapter,
+ pressure_adapter,
+ ((sensors & ML_THREE_AXIS_GYRO)
+ == ML_THREE_AXIS_GYRO),
+ ((sensors & ML_THREE_AXIS_ACCEL)
+ == ML_THREE_AXIS_ACCEL),
+ ((sensors & ML_THREE_AXIS_COMPASS)
+ == ML_THREE_AXIS_COMPASS),
+ ((sensors & ML_THREE_AXIS_PRESSURE)
+ == ML_THREE_AXIS_PRESSURE));
+ }
+ break;
+ case MPU_RESUME:
+ {
+ unsigned long sensors;
+
+
+ sensors = mldl_cfg->requested_sensors;
+ retval = mpu3050_resume(mldl_cfg,
+ client->adapter,
+ accel_adapter,
+ compass_adapter,
+ pressure_adapter,
+ sensors & ML_THREE_AXIS_GYRO,
+ sensors & ML_THREE_AXIS_ACCEL,
+ sensors & ML_THREE_AXIS_COMPASS,
+ sensors & ML_THREE_AXIS_PRESSURE);
+ }
+ break;
+ case MPU_READ_ACCEL:
+ {
+ unsigned char data[6];
+ retval = mpu3050_read_accel(mldl_cfg, client->adapter,
+ data);
+ if ((ML_SUCCESS == retval) &&
+ (copy_to_user((unsigned char __user *) arg,
+ data, sizeof(data))))
+ retval = -EFAULT;
+ }
+ break;
+ case MPU_READ_COMPASS:
+ {
+ unsigned char data[6];
+ struct i2c_adapter *compass_adapt =
+ i2c_get_adapter(mldl_cfg->pdata->compass.
+ adapt_num);
+ retval = mpu3050_read_compass(mldl_cfg, compass_adapt,
+ data);
+ if ((ML_SUCCESS == retval) &&
+ (copy_to_user((unsigned char *) arg,
+ data, sizeof(data))))
+ retval = -EFAULT;
+ }
+ break;
+ case MPU_READ_PRESSURE:
+ {
+ unsigned char data[3];
+ struct i2c_adapter *pressure_adapt =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.
+ adapt_num);
+ retval =
+ mpu3050_read_pressure(mldl_cfg, pressure_adapt,
+ data);
+ if ((ML_SUCCESS == retval) &&
+ (copy_to_user((unsigned char __user *) arg,
+ data, sizeof(data))))
+ retval = -EFAULT;
+ }
+ break;
+#ifdef HTC_READ_CAL_DATA
+ case MPU_READ_CAL_DATA:
+ {
+ int index;
+ unsigned char mpu_gyro_gsensor_kvalue[37];
+
+ for (index = 0;
+ index < sizeof(mpu_gyro_gsensor_kvalue);
+ index++) {
+ mpu_gyro_gsensor_kvalue[index] =
+ gyro_gsensor_kvalue[index];
+ printk(KERN_DEBUG "gyro_gsensor_kvalue[%d] = 0x%x\n",
+ index, gyro_gsensor_kvalue[index]);
+ }
+
+ retval =
+ copy_to_user((unsigned char *) arg,
+ mpu_gyro_gsensor_kvalue,
+ sizeof(mpu_gyro_gsensor_kvalue));
+ }
+ break;
+#endif
+ case MPU_READ_MEMORY:
+ case MPU_WRITE_MEMORY:
+ default:
+ dev_err(&this_client->adapter->dev,
+ "[mpu_err]%s: Unknown cmd %d, arg %lu\n", __func__, cmd,
+ arg);
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void mpu3050_early_suspend(struct early_suspend *h)
+{
+ struct mpu_private_data *mpu = container_of(h,
+ struct
+ mpu_private_data,
+ early_suspend);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ dev_dbg(&this_client->adapter->dev, "%s: %d, %d\n", __func__,
+ h->level, mpu->mldl_cfg.gyro_is_suspended);
+ if (MPU3050_EARLY_SUSPEND_IN_DRIVER)
+ (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
+ accel_adapter, compass_adapter,
+ pressure_adapter, TRUE, TRUE, TRUE, TRUE);
+}
+
+void mpu3050_early_resume(struct early_suspend *h)
+{
+ struct mpu_private_data *mpu = container_of(h,
+ struct
+ mpu_private_data,
+ early_suspend);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ if (MPU3050_EARLY_SUSPEND_IN_DRIVER) {
+ if (pid) {
+ unsigned long sensors = mldl_cfg->requested_sensors;
+ (void) mpu3050_resume(mldl_cfg,
+ this_client->adapter,
+ accel_adapter,
+ compass_adapter,
+ pressure_adapter,
+ sensors & ML_THREE_AXIS_GYRO,
+ sensors & ML_THREE_AXIS_ACCEL,
+ sensors & ML_THREE_AXIS_COMPASS,
+ sensors & ML_THREE_AXIS_PRESSURE);
+ dev_dbg(&this_client->adapter->dev,
+ "%s for pid %d\n", __func__, pid);
+ }
+ }
+ dev_dbg(&this_client->adapter->dev, "%s: %d\n", __func__, h->level);
+}
+#endif
+
+void mpu_shutdown(struct i2c_client *client)
+{
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
+ accel_adapter, compass_adapter, pressure_adapter,
+ TRUE, TRUE, TRUE, TRUE);
+ dev_dbg(&this_client->adapter->dev, "%s\n", __func__);
+}
+
+int mpu_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ if (!mpu->mldl_cfg.gyro_is_suspended) {
+ dev_dbg(&this_client->adapter->dev,
+ "%s: suspending on event %d\n", __func__,
+ mesg.event);
+ (void) mpu3050_suspend(mldl_cfg, this_client->adapter,
+ accel_adapter, compass_adapter,
+ pressure_adapter,
+ TRUE, TRUE, TRUE, TRUE);
+ } else {
+ dev_dbg(&this_client->adapter->dev,
+ "%s: Already suspended %d\n", __func__,
+ mesg.event);
+ }
+
+ return 0;
+}
+
+int mpu_resume(struct i2c_client *client)
+{
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ if (pid) {
+ unsigned long sensors = mldl_cfg->requested_sensors;
+ (void) mpu3050_resume(mldl_cfg, this_client->adapter,
+ accel_adapter,
+ compass_adapter,
+ pressure_adapter,
+ sensors & ML_THREE_AXIS_GYRO,
+ sensors & ML_THREE_AXIS_ACCEL,
+ sensors & ML_THREE_AXIS_COMPASS,
+ sensors & ML_THREE_AXIS_PRESSURE);
+ dev_dbg(&this_client->adapter->dev,
+ "%s for pid %d\n", __func__, pid);
+ }
+
+ return 0;
+}
+
+static const struct file_operations mpu_fops = {
+ .owner = THIS_MODULE,
+ .read = mpu_read,
+#if HAVE_COMPAT_IOCTL
+ .compat_ioctl = mpu_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = mpu_ioctl,
+#endif
+ .open = mpu_open,
+ .release = mpu_release,
+};
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+static struct miscdevice i2c_mpu_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mpu",
+ .fops = &mpu_fops,
+};
+
+void *g_handler;
+int (*g_sensors_reset)(void);
+
+struct class *mpu3050_class;
+struct device *mpu3050_dev;
+
+static ssize_t pwr_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned char b[2] = "";
+ int result;
+
+ unsigned char bma[8] = "";
+
+ result = MLSLSerialRead(g_handler, 0x68,
+ MPUREG_USER_CTRL, 2, b);
+
+ result = MLSLSerialRead(g_handler, 0x18,
+ 0x0F, 3, bma);
+
+ result = sprintf(buf, "MPUREG_USER_CTRL = 0x%x, MPUREG_PWR_MGM = "
+ "0x%x.\n"
+ "BMA register 0x0F = 0x%x, "
+ "BMA register 0x10 = 0x%x, "
+ "BMA register 0x11 = 0x%x\n"
+ "",
+ b[0], b[1],
+ bma[0], bma[1], bma[2]);
+
+ return result;
+}
+
+static ssize_t pwr_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return count;
+}
+
+static DEVICE_ATTR(pwr_reg, 0664, pwr_reg_show, pwr_reg_store);
+
+static ssize_t mpu_debug_flag_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char *s = buf;
+
+ s += sprintf(s, "mpu_debug_flag = 0x%x\n", mpu_debug_flag);
+
+ return s - buf;
+}
+
+static ssize_t mpu_debug_flag_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ mpu_debug_flag = -1;
+ sscanf(buf, "%d", &mpu_debug_flag);
+
+ D("%s: mpu_debug_flag = %d\n", __func__, mpu_debug_flag);
+
+ return count;
+}
+
+static DEVICE_ATTR(mpu_debug_flag, 0664, mpu_debug_flag_show, \
+ mpu_debug_flag_store);
+
+static ssize_t mpu_sensors_reset_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char *s = buf;
+
+ s += sprintf(s, "mpu_sensors_reset = 0x%x\n", mpu_sensors_reset);
+
+ return s - buf;
+}
+
+static ssize_t mpu_sensors_reset_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc = 0;
+
+ mpu_sensors_reset = -1;
+ sscanf(buf, "%d", &mpu_sensors_reset);
+
+ D("%s: mpu_sensors_reset = %d\n", __func__, mpu_sensors_reset);
+
+ if ((mpu_sensors_reset == 1) && g_sensors_reset) {
+ rc = g_sensors_reset();
+ if (rc)
+ E("G-Sensor, Compass, Gyro reset error\n");
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(mpu_sensors_reset, 0664, mpu_sensors_reset_show, \
+ mpu_sensors_reset_store);
+
+
+static ssize_t mpu_lpm_flag_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ char *s = buf;
+
+ s += sprintf(s, "%d", mpu_lpm_flag);
+
+ return s - buf;
+}
+
+static ssize_t mpu_lpm_flag_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mpu_private_data *mpu =
+ (struct mpu_private_data *) i2c_get_clientdata(this_client);
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+
+ mpu_lpm_flag = -1;
+ sscanf(buf, "%d", &mpu_lpm_flag);
+
+ if ((mpu_lpm_flag == 1) && mldl_cfg->pdata->power_LPM)
+ mldl_cfg->pdata->power_LPM(1);
+ else if (mldl_cfg->pdata->power_LPM)
+ mldl_cfg->pdata->power_LPM(0);
+
+ D("%s: mpu_lpm_flag = %d\n", __func__, mpu_lpm_flag);
+
+ return count;
+}
+
+static DEVICE_ATTR(mpu_lpm_flag, 0664, mpu_lpm_flag_show, \
+ mpu_lpm_flag_store);
+
+
+int mpu3050_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct mpu3050_platform_data *pdata;
+ struct mpu_private_data *mpu;
+ struct mldl_cfg *mldl_cfg;
+ int res = 0;
+ struct i2c_adapter *accel_adapter = NULL;
+ struct i2c_adapter *compass_adapter = NULL;
+ struct i2c_adapter *pressure_adapter = NULL;
+
+ dev_dbg(&client->adapter->dev, "%s\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ res = -ENODEV;
+ goto out_check_functionality_failed;
+ }
+
+ mpu = kzalloc(sizeof(struct mpu_private_data), GFP_KERNEL);
+ if (!mpu) {
+ res = -ENOMEM;
+ goto out_alloc_data_failed;
+ }
+
+ i2c_set_clientdata(client, mpu);
+ this_client = client;
+ mldl_cfg = &mpu->mldl_cfg;
+ pdata = (struct mpu3050_platform_data *) client->dev.platform_data;
+ if (!pdata) {
+ dev_warn(&this_client->adapter->dev,
+ "Warning no platform data for mpu3050\n");
+ } else {
+ mldl_cfg->pdata = pdata;
+
+ g_sensors_reset = pdata->g_sensors_reset;
+
+#if defined(CONFIG_MPU_SENSORS_MPU3050_MODULE) || \
+ defined(CONFIG_MPU_SENSORS_MPU6000_MODULE)
+ pdata->accel.get_slave_descr = get_accel_slave_descr;
+ pdata->compass.get_slave_descr = get_compass_slave_descr;
+ pdata->pressure.get_slave_descr = get_pressure_slave_descr;
+#endif
+
+ if (pdata->accel.get_slave_descr) {
+ mldl_cfg->accel =
+ pdata->accel.get_slave_descr();
+ dev_info(&this_client->adapter->dev,
+ "%s: +%s\n", MPU_NAME,
+ mldl_cfg->accel->name);
+ accel_adapter =
+ i2c_get_adapter(pdata->accel.adapt_num);
+ if (pdata->accel.irq > 0) {
+ dev_info(&this_client->adapter->dev,
+ "Installing Accel irq using %d\n",
+ pdata->accel.irq);
+ res = slaveirq_init(accel_adapter,
+ &pdata->accel,
+ "accelirq");
+ if (res)
+ goto out_accelirq_failed;
+ } else {
+ dev_info(&this_client->adapter->dev,
+ "Accel irq not needed\n");
+ }
+ } else {
+ dev_warn(&this_client->adapter->dev,
+ "%s: No Accel Present\n", MPU_NAME);
+ }
+
+ if (pdata->compass.get_slave_descr) {
+ mldl_cfg->compass =
+ pdata->compass.get_slave_descr();
+ dev_info(&this_client->adapter->dev,
+ "%s: +%s\n", MPU_NAME,
+ mldl_cfg->compass->name);
+ compass_adapter =
+ i2c_get_adapter(pdata->compass.adapt_num);
+ if (pdata->compass.irq > 0) {
+ dev_info(&this_client->adapter->dev,
+ "Installing Compass irq using %d\n",
+ pdata->compass.irq);
+ res = slaveirq_init(compass_adapter,
+ &pdata->compass,
+ "compassirq");
+ if (res)
+ goto out_compassirq_failed;
+ } else {
+ dev_info(&this_client->adapter->dev,
+ "Compass irq not needed\n");
+ }
+ } else {
+ dev_warn(&this_client->adapter->dev,
+ "%s: No Compass Present\n", MPU_NAME);
+ }
+
+ if (pdata->pressure.get_slave_descr) {
+ mldl_cfg->pressure =
+ pdata->pressure.get_slave_descr();
+ dev_info(&this_client->adapter->dev,
+ "%s: +%s\n", MPU_NAME,
+ mldl_cfg->pressure->name);
+ pressure_adapter =
+ i2c_get_adapter(pdata->pressure.adapt_num);
+
+ if (pdata->pressure.irq > 0) {
+ dev_info(&this_client->adapter->dev,
+ "Installing Pressure irq using %d\n",
+ pdata->pressure.irq);
+ res = slaveirq_init(pressure_adapter,
+ &pdata->pressure,
+ "pressureirq");
+ if (res)
+ goto out_pressureirq_failed;
+ } else {
+ dev_warn(&this_client->adapter->dev,
+ "WARNING: Pressure irq not assigned\n");
+ }
+ } else {
+ dev_info(&this_client->adapter->dev,
+ "%s: No Pressure Present\n", MPU_NAME);
+ }
+ }
+
+ mldl_cfg->addr = client->addr;
+ res = mpu3050_open(&mpu->mldl_cfg, client->adapter,
+ accel_adapter, compass_adapter, pressure_adapter);
+
+ if (res) {
+ dev_err(&this_client->adapter->dev,
+ "[mpu_err] Unable to open %s %d\n", MPU_NAME, res);
+ res = -ENODEV;
+ goto out_whoami_failed;
+ }
+
+ g_handler = client->adapter;
+
+ res = misc_register(&i2c_mpu_device);
+ if (res < 0) {
+ dev_err(&this_client->adapter->dev,
+ "[mpu_err] ERROR: misc_register returned %d\n", res);
+ goto out_misc_register_failed;
+ }
+
+ if (this_client->irq > 0) {
+ dev_info(&this_client->adapter->dev,
+ "Installing irq using %d\n", this_client->irq);
+ res = mpuirq_init(this_client);
+ if (res)
+ goto out_mpuirq_failed;
+ } else {
+ dev_warn(&this_client->adapter->dev,
+ "WARNING: %s irq not assigned\n", MPU_NAME);
+ }
+
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ mpu->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ mpu->early_suspend.suspend = mpu3050_early_suspend;
+ mpu->early_suspend.resume = mpu3050_early_resume;
+ register_early_suspend(&mpu->early_suspend);
+#endif
+
+ mpu3050_class = class_create(THIS_MODULE, "gyro_sensors");
+ if (IS_ERR(mpu3050_class)) {
+ res = PTR_ERR(mpu3050_class);
+ mpu3050_class = NULL;
+ E("%s, create mpu3050_class fail!\n", __func__);
+ goto out_mpuirq_failed;
+ }
+
+ mpu3050_dev = device_create(mpu3050_class,
+ NULL, 0, "%s", "gyro");
+ if (unlikely(IS_ERR(mpu3050_dev))) {
+ res = PTR_ERR(mpu3050_dev);
+ mpu3050_dev = NULL;
+ E("%s, create mpu3050_dev fail!\n", __func__);
+ goto err_create_mpu_device;
+ }
+
+
+ res = device_create_file(mpu3050_dev, &dev_attr_pwr_reg);
+ if (res) {
+ E("%s, create mpu3050_device_create_file fail!\n", __func__);
+ goto err_create_mpu_device_file;
+ }
+
+
+ res = device_create_file(mpu3050_dev, &dev_attr_mpu_debug_flag);
+ if (res) {
+ E("%s, create mpu3050_device_create_file fail!\n", __func__);
+ goto err_create_mpu_device_mpu_debug_flag_file;
+ }
+
+
+ res = device_create_file(mpu3050_dev, &dev_attr_mpu_sensors_reset);
+ if (res) {
+ E("%s, create mpu3050_device_create_file fail!\n", __func__);
+ goto err_create_mpu_device_sensors_reset_flag_file;
+ }
+
+
+ res = device_create_file(mpu3050_dev, &dev_attr_mpu_lpm_flag);
+ if (res) {
+ E("%s, create mpu3050_device_create_file fail!\n", __func__);
+ goto err_create_mpu_device_mpu_lpm_flag_file;
+ }
+
+ mpu_debug_flag = 0;
+ mpu_sensors_reset = 0;
+ mpu_lpm_flag = 0;
+
+ return res;
+
+err_create_mpu_device_mpu_lpm_flag_file:
+ device_remove_file(mpu3050_dev, &dev_attr_mpu_sensors_reset);
+err_create_mpu_device_sensors_reset_flag_file:
+ device_remove_file(mpu3050_dev, &dev_attr_mpu_debug_flag);
+err_create_mpu_device_mpu_debug_flag_file:
+ device_remove_file(mpu3050_dev, &dev_attr_pwr_reg);
+err_create_mpu_device_file:
+ device_unregister(mpu3050_dev);
+err_create_mpu_device:
+ class_destroy(mpu3050_class);
+out_mpuirq_failed:
+ misc_deregister(&i2c_mpu_device);
+out_misc_register_failed:
+ mpu3050_close(&mpu->mldl_cfg, client->adapter,
+ accel_adapter, compass_adapter, pressure_adapter);
+out_whoami_failed:
+ if (pdata &&
+ pdata->pressure.get_slave_descr &&
+ pdata->pressure.irq)
+ slaveirq_exit(&pdata->pressure);
+out_pressureirq_failed:
+ if (pdata &&
+ pdata->compass.get_slave_descr &&
+ pdata->compass.irq)
+ slaveirq_exit(&pdata->compass);
+out_compassirq_failed:
+ if (pdata &&
+ pdata->accel.get_slave_descr &&
+ pdata->accel.irq)
+ slaveirq_exit(&pdata->accel);
+out_accelirq_failed:
+ kfree(mpu);
+out_alloc_data_failed:
+out_check_functionality_failed:
+ dev_err(&this_client->adapter->dev, "[mpu_err]%s failed %d\n", __func__,
+ res);
+ return res;
+
+}
+
+static int mpu3050_remove(struct i2c_client *client)
+{
+ struct mpu_private_data *mpu = i2c_get_clientdata(client);
+ struct i2c_adapter *accel_adapter;
+ struct i2c_adapter *compass_adapter;
+ struct i2c_adapter *pressure_adapter;
+ struct mldl_cfg *mldl_cfg = &mpu->mldl_cfg;
+ struct mpu3050_platform_data *pdata = mldl_cfg->pdata;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ compass_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->compass.adapt_num);
+ pressure_adapter =
+ i2c_get_adapter(mldl_cfg->pdata->pressure.adapt_num);
+
+ dev_dbg(&client->adapter->dev, "%s\n", __func__);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&mpu->early_suspend);
+#endif
+ mpu3050_close(mldl_cfg, client->adapter,
+ accel_adapter, compass_adapter, pressure_adapter);
+
+ if (client->irq)
+ mpuirq_exit();
+
+ if (pdata &&
+ pdata->pressure.get_slave_descr &&
+ pdata->pressure.irq)
+ slaveirq_exit(&pdata->pressure);
+
+ if (pdata &&
+ pdata->compass.get_slave_descr &&
+ pdata->compass.irq)
+ slaveirq_exit(&pdata->compass);
+
+ if (pdata &&
+ pdata->accel.get_slave_descr &&
+ pdata->accel.irq)
+ slaveirq_exit(&pdata->accel);
+
+ misc_deregister(&i2c_mpu_device);
+ kfree(mpu);
+
+ return 0;
+}
+
+static const struct i2c_device_id mpu3050_id[] = {
+ {MPU_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mpu3050_id);
+
+static struct i2c_driver mpu3050_driver = {
+ .class = I2C_CLASS_HWMON,
+ .probe = mpu3050_probe,
+ .remove = mpu3050_remove,
+ .id_table = mpu3050_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MPU_NAME,
+ },
+ .address_list = normal_i2c,
+ .shutdown = mpu_shutdown,
+ .suspend = mpu_suspend,
+ .resume = mpu_resume,
+
+};
+
+static int __init mpu_init(void)
+{
+ int res = i2c_add_driver(&mpu3050_driver);
+ pid = 0;
+ printk(KERN_DEBUG "%s\n", __func__);
+ if (res)
+ dev_err(&this_client->adapter->dev, "[mpu_err]%s failed\n",
+ __func__);
+ return res;
+}
+
+static void __exit mpu_exit(void)
+{
+ printk(KERN_DEBUG "%s\n", __func__);
+ i2c_del_driver(&mpu3050_driver);
+}
+
+module_init(mpu_init);
+module_exit(mpu_exit);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("User space character device interface for MPU3050");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(MPU_NAME);
diff --git a/drivers/input/misc/mpu3050/mpu-i2c.c b/drivers/input/misc/mpu3050/mpu-i2c.c
new file mode 100644
index 0000000..0953e6a
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mpu-i2c.c
@@ -0,0 +1,252 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include "mpu.h"
+#define MPU_I2C_RETRY_ENABLE 1
+#define MPU_I2C_RETRY_TIMES 10
+#define MPU_I2C_DELAY_TIMES_MS 10
+
+int sensor_i2c_write(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned int len, unsigned char const *data)
+{
+ struct i2c_msg msgs[1];
+ int res;
+ int i;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+
+ msgs[0].addr = address;
+ msgs[0].flags = 0;
+ msgs[0].buf = (unsigned char *) data;
+ msgs[0].len = len;
+
+#if MPU_I2C_RETRY_ENABLE
+ for (i = 0; i < MPU_I2C_RETRY_TIMES; i++) {
+ res = i2c_transfer(i2c_adap, msgs, 1);
+ if (res < 1) {
+ printk(KERN_ERR "I2c Slave address: %x,\
+ sensor_i2c_write fail,\
+ retry:%d\n", address, i);
+ mdelay(MPU_I2C_DELAY_TIMES_MS);
+ } else
+ return 0;
+
+ }
+ return res;
+#else
+ res = i2c_transfer(i2c_adap, msgs, 1);
+ if (res < 1)
+ return res;
+ else
+ return 0;
+#endif
+}
+
+int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned char reg, unsigned char value)
+{
+ unsigned char data[2];
+
+ data[0] = reg;
+ data[1] = value;
+ return sensor_i2c_write(i2c_adap, address, 2, data);
+}
+
+int sensor_i2c_read(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned char reg,
+ unsigned int len, unsigned char *data)
+{
+ struct i2c_msg msgs[2];
+ int res;
+ int i;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+
+ msgs[0].addr = address;
+ msgs[0].flags = 0;
+ msgs[0].buf = ®
+ msgs[0].len = 1;
+
+ msgs[1].addr = address;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].buf = data;
+ msgs[1].len = len;
+
+#if MPU_I2C_RETRY_ENABLE
+ for (i = 0; i < MPU_I2C_RETRY_TIMES; i++) {
+ res = i2c_transfer(i2c_adap, msgs, 2);
+ if (res < 2) {
+ printk(KERN_ERR "I2c Slave address: %x,\
+ sensor_i2c_read fail,\
+ retry:%d\n", address, i);
+ mdelay(MPU_I2C_DELAY_TIMES_MS);
+ } else
+ return 0;
+
+ }
+ return res;
+#else
+ res = i2c_transfer(i2c_adap, msgs, 2);
+ if (res < 2)
+ return res;
+ else
+ return 0;
+#endif
+}
+
+int mpu_memory_read(struct i2c_adapter *i2c_adap,
+ unsigned char mpu_addr,
+ unsigned short mem_addr,
+ unsigned int len, unsigned char *data)
+{
+ unsigned char bank[2];
+ unsigned char addr[2];
+ unsigned char buf;
+
+ struct i2c_msg msgs[4];
+ int ret;
+ int i;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+
+ bank[0] = MPUREG_BANK_SEL;
+ bank[1] = mem_addr >> 8;
+
+ addr[0] = MPUREG_MEM_START_ADDR;
+ addr[1] = mem_addr & 0xFF;
+
+ buf = MPUREG_MEM_R_W;
+
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = bank;
+ msgs[0].len = sizeof(bank);
+
+ msgs[1].addr = mpu_addr;
+ msgs[1].flags = 0;
+ msgs[1].buf = addr;
+ msgs[1].len = sizeof(addr);
+
+ msgs[2].addr = mpu_addr;
+ msgs[2].flags = 0;
+ msgs[2].buf = &buf;
+ msgs[2].len = 1;
+
+ msgs[3].addr = mpu_addr;
+ msgs[3].flags = I2C_M_RD;
+ msgs[3].buf = data;
+ msgs[3].len = len;
+
+#if MPU_I2C_RETRY_ENABLE
+ for (i = 0; i < MPU_I2C_RETRY_TIMES; i++) {
+ ret = i2c_transfer(i2c_adap, msgs, 4);
+ if (ret != 4) {
+ printk(KERN_ERR "I2c Slave address: %x,\
+ mpu_memory_read,\
+ retry:%d\n", mpu_addr, i);
+ mdelay(MPU_I2C_DELAY_TIMES_MS);
+ } else
+ return 0;
+
+ }
+ return ret;
+#else
+ ret = i2c_transfer(i2c_adap, msgs, 4);
+ if (ret != 4)
+ return ret;
+ else
+ return 0;
+#endif
+}
+
+int mpu_memory_write(struct i2c_adapter *i2c_adap,
+ unsigned char mpu_addr,
+ unsigned short mem_addr,
+ unsigned int len, unsigned char const *data)
+{
+ unsigned char bank[2];
+ unsigned char addr[2];
+ unsigned char buf[513];
+
+ struct i2c_msg msgs[3];
+ int ret;
+ int i;
+
+ if (NULL == data || NULL == i2c_adap)
+ return -EINVAL;
+ if (len >= (sizeof(buf) - 1))
+ return -ENOMEM;
+
+ bank[0] = MPUREG_BANK_SEL;
+ bank[1] = mem_addr >> 8;
+
+ addr[0] = MPUREG_MEM_START_ADDR;
+ addr[1] = mem_addr & 0xFF;
+
+ buf[0] = MPUREG_MEM_R_W;
+ memcpy(buf + 1, data, len);
+
+
+ msgs[0].addr = mpu_addr;
+ msgs[0].flags = 0;
+ msgs[0].buf = bank;
+ msgs[0].len = sizeof(bank);
+
+ msgs[1].addr = mpu_addr;
+ msgs[1].flags = 0;
+ msgs[1].buf = addr;
+ msgs[1].len = sizeof(addr);
+
+ msgs[2].addr = mpu_addr;
+ msgs[2].flags = 0;
+ msgs[2].buf = (unsigned char *) buf;
+ msgs[2].len = len + 1;
+
+#if MPU_I2C_RETRY_ENABLE
+ for (i = 0; i < MPU_I2C_RETRY_TIMES; i++) {
+ ret = i2c_transfer(i2c_adap, msgs, 3);
+ if (ret != 3) {
+ printk(KERN_ERR "I2c Slave address: %x,\
+ mpu_memory_write,\
+ retry:%d\n", mpu_addr, i);
+ mdelay(MPU_I2C_DELAY_TIMES_MS);
+ } else
+ return 0;
+
+ }
+ return ret;
+#else
+ ret = i2c_transfer(i2c_adap, msgs, 3);
+ if (ret != 3)
+ return ret;
+ else
+ return 0;
+#endif
+}
+
diff --git a/drivers/input/misc/mpu3050/mpu-i2c.h b/drivers/input/misc/mpu3050/mpu-i2c.h
new file mode 100644
index 0000000..c26aafb
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mpu-i2c.h
@@ -0,0 +1,48 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef __MPU_I2C_H__
+#define __MPU_I2C_H__
+
+#include <linux/i2c.h>
+
+int sensor_i2c_write(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned int len, unsigned char const *data);
+
+int sensor_i2c_write_register(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned char reg, unsigned char value);
+
+int sensor_i2c_read(struct i2c_adapter *i2c_adap,
+ unsigned char address,
+ unsigned char reg,
+ unsigned int len, unsigned char *data);
+
+int mpu_memory_read(struct i2c_adapter *i2c_adap,
+ unsigned char mpu_addr,
+ unsigned short mem_addr,
+ unsigned int len, unsigned char *data);
+
+int mpu_memory_write(struct i2c_adapter *i2c_adap,
+ unsigned char mpu_addr,
+ unsigned short mem_addr,
+ unsigned int len, unsigned char const *data);
+
+#endif
diff --git a/drivers/input/misc/mpu3050/mpuirq.c b/drivers/input/misc/mpu3050/mpuirq.c
new file mode 100644
index 0000000..561d6cf
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mpuirq.c
@@ -0,0 +1,319 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include "mpu.h"
+#include "mpuirq.h"
+#include "mldl_cfg.h"
+#include "mpu-i2c.h"
+
+#define MPUIRQ_NAME "mpuirq"
+
+
+DECLARE_WAIT_QUEUE_HEAD(mpuirq_wait);
+
+struct mpuirq_dev_data {
+ struct work_struct work;
+ struct i2c_client *mpu_client;
+ struct miscdevice *dev;
+ int irq;
+ int pid;
+ int accel_divider;
+ int data_ready;
+ int timeout;
+};
+
+static struct mpuirq_dev_data mpuirq_dev_data;
+static struct mpuirq_data mpuirq_data;
+static char *interface = MPUIRQ_NAME;
+
+static void mpu_accel_data_work_fcn(struct work_struct *work);
+
+static int mpuirq_open(struct inode *inode, struct file *file)
+{
+ dev_dbg(mpuirq_dev_data.dev->this_device,
+ "%s current->pid %d\n", __func__, current->pid);
+ mpuirq_dev_data.pid = current->pid;
+ file->private_data = &mpuirq_dev_data;
+
+
+
+ return 0;
+}
+
+static int mpuirq_release(struct inode *inode, struct file *file)
+{
+ dev_dbg(mpuirq_dev_data.dev->this_device, "mpuirq_release\n");
+ return 0;
+}
+
+static ssize_t mpuirq_read(struct file *file,
+ char *buf, size_t count, loff_t *ppos)
+{
+ int len, err;
+ struct mpuirq_dev_data *p_mpuirq_dev_data = file->private_data;
+
+ if (!mpuirq_dev_data.data_ready) {
+ wait_event_interruptible_timeout(mpuirq_wait,
+ mpuirq_dev_data.
+ data_ready,
+ mpuirq_dev_data.timeout);
+ }
+
+ if (mpuirq_dev_data.data_ready && NULL != buf
+ && count >= sizeof(mpuirq_data)) {
+ err = copy_to_user(buf, &mpuirq_data, sizeof(mpuirq_data));
+ mpuirq_data.data_type = 0;
+ } else {
+ return 0;
+ }
+ if (err != 0) {
+ dev_err(p_mpuirq_dev_data->dev->this_device,
+ "Copy to user returned %d\n", err);
+ return -EFAULT;
+ }
+ mpuirq_dev_data.data_ready = 0;
+ len = sizeof(mpuirq_data);
+ return len;
+}
+
+unsigned int mpuirq_poll(struct file *file, struct poll_table_struct *poll)
+{
+ int mask = 0;
+
+ poll_wait(file, &mpuirq_wait, poll);
+ if (mpuirq_dev_data.data_ready)
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+}
+
+static long mpuirq_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int data;
+
+ switch (cmd) {
+ case MPUIRQ_SET_TIMEOUT:
+ mpuirq_dev_data.timeout = arg;
+ break;
+
+ case MPUIRQ_GET_INTERRUPT_CNT:
+ data = mpuirq_data.interruptcount - 1;
+ if (mpuirq_data.interruptcount > 1)
+ mpuirq_data.interruptcount = 1;
+
+ if (copy_to_user((int *) arg, &data, sizeof(int)))
+ return -EFAULT;
+ break;
+ case MPUIRQ_GET_IRQ_TIME:
+ if (copy_to_user((int *) arg, &mpuirq_data.irqtime,
+ sizeof(mpuirq_data.irqtime)))
+ return -EFAULT;
+ mpuirq_data.irqtime = 0;
+ break;
+ case MPUIRQ_SET_FREQUENCY_DIVIDER:
+ mpuirq_dev_data.accel_divider = arg;
+ break;
+ case MPUIRQ_GET_DEBUG_FLAG:
+ if (copy_to_user((int *) arg, &mpu_debug_flag, sizeof(int)))
+ return -EFAULT;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static void mpu_accel_data_work_fcn(struct work_struct *work)
+{
+ struct mpuirq_dev_data *mpuirq_dev_data =
+ (struct mpuirq_dev_data *) work;
+ struct mldl_cfg *mldl_cfg =
+ (struct mldl_cfg *)
+ i2c_get_clientdata(mpuirq_dev_data->mpu_client);
+ struct i2c_adapter *accel_adapter;
+ unsigned char wbuff[16];
+ unsigned char rbuff[16];
+ int ii;
+
+ accel_adapter = i2c_get_adapter(mldl_cfg->pdata->accel.adapt_num);
+ mldl_cfg->accel->read(accel_adapter,
+ mldl_cfg->accel,
+ &mldl_cfg->pdata->accel, rbuff);
+
+
+
+ if (EXT_SLAVE_BIG_ENDIAN == mldl_cfg->accel->endian) {
+ for (ii = 0; ii < 3; ii++) {
+ wbuff[2 * ii + 1] = rbuff[2 * ii + 1];
+ wbuff[2 * ii + 2] = rbuff[2 * ii + 0];
+ }
+ } else {
+ memcpy(wbuff + 1, rbuff, mldl_cfg->accel->len);
+ }
+
+ wbuff[7] = 0;
+ wbuff[8] = 1;
+
+ mpu_memory_write(mpuirq_dev_data->mpu_client->adapter,
+ mldl_cfg->addr, 0x0108, 8, wbuff);
+}
+
+static irqreturn_t mpuirq_handler(int irq, void *dev_id)
+{
+ static int mycount;
+ struct timeval irqtime;
+ mycount++;
+
+ mpuirq_data.interruptcount++;
+
+
+
+ mpuirq_dev_data.data_ready = 1;
+
+ do_gettimeofday(&irqtime);
+ mpuirq_data.irqtime = (((long long) irqtime.tv_sec) << 32);
+ mpuirq_data.irqtime += irqtime.tv_usec;
+
+ if ((mpuirq_dev_data.accel_divider >= 0) &&
+ (0 == (mycount % (mpuirq_dev_data.accel_divider + 1)))) {
+ schedule_work((struct work_struct
+ *) (&mpuirq_dev_data));
+ }
+
+ wake_up_interruptible(&mpuirq_wait);
+
+ return IRQ_HANDLED;
+
+}
+
+const struct file_operations mpuirq_fops = {
+ .owner = THIS_MODULE,
+ .read = mpuirq_read,
+ .poll = mpuirq_poll,
+
+#if HAVE_COMPAT_IOCTL
+ .compat_ioctl = mpuirq_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = mpuirq_ioctl,
+#endif
+ .open = mpuirq_open,
+ .release = mpuirq_release,
+};
+
+static struct miscdevice mpuirq_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = MPUIRQ_NAME,
+ .fops = &mpuirq_fops,
+};
+
+int mpuirq_init(struct i2c_client *mpu_client)
+{
+
+ int res;
+ struct mldl_cfg *mldl_cfg =
+ (struct mldl_cfg *) i2c_get_clientdata(mpu_client);
+
+
+ INIT_WORK((struct work_struct *) &mpuirq_dev_data,
+ mpu_accel_data_work_fcn);
+ mpuirq_dev_data.mpu_client = mpu_client;
+
+ dev_info(&mpu_client->adapter->dev,
+ "Module Param interface = %s\n", interface);
+
+ mpuirq_dev_data.irq = mpu_client->irq;
+ mpuirq_dev_data.pid = 0;
+ mpuirq_dev_data.accel_divider = -1;
+ mpuirq_dev_data.data_ready = 0;
+ mpuirq_dev_data.timeout = 0;
+ mpuirq_dev_data.dev = &mpuirq_device;
+
+ if (mpuirq_dev_data.irq) {
+ unsigned long flags;
+ if (BIT_ACTL_LOW ==
+ ((mldl_cfg->pdata->int_config) & BIT_ACTL))
+ flags = IRQF_TRIGGER_FALLING;
+ else
+ flags = IRQF_TRIGGER_RISING;
+
+ res =
+ request_irq(mpuirq_dev_data.irq, mpuirq_handler, flags,
+ interface, &mpuirq_dev_data.irq);
+ if (res) {
+ dev_err(&mpu_client->adapter->dev,
+ "myirqtest: cannot register IRQ %d\n",
+ mpuirq_dev_data.irq);
+ } else {
+ res = misc_register(&mpuirq_device);
+ if (res < 0) {
+ dev_err(&mpu_client->adapter->dev,
+ "misc_register returned %d\n",
+ res);
+ free_irq(mpuirq_dev_data.irq,
+ &mpuirq_dev_data.irq);
+ }
+ }
+
+ } else {
+ res = 0;
+ }
+
+ return res;
+}
+
+void mpuirq_exit(void)
+{
+
+ if (mpuirq_dev_data.irq > 0)
+ free_irq(mpuirq_dev_data.irq, &mpuirq_dev_data.irq);
+
+ flush_scheduled_work();
+
+ dev_info(mpuirq_device.this_device, "Unregistering %s\n",
+ MPUIRQ_NAME);
+ misc_deregister(&mpuirq_device);
+
+ return;
+}
+
+module_param(interface, charp, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(interface, "The Interface name");
diff --git a/drivers/input/misc/mpu3050/mpuirq.h b/drivers/input/misc/mpu3050/mpuirq.h
new file mode 100644
index 0000000..54c2e88
--- /dev/null
+++ b/drivers/input/misc/mpu3050/mpuirq.h
@@ -0,0 +1,45 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef __MPUIRQ__
+#define __MPUIRQ__
+
+#ifdef __KERNEL__
+#include <linux/i2c-dev.h>
+#endif
+
+#define MPUIRQ_ENABLE_DEBUG (1)
+#define MPUIRQ_GET_INTERRUPT_CNT (2)
+#define MPUIRQ_GET_IRQ_TIME (3)
+#define MPUIRQ_GET_LED_VALUE (4)
+#define MPUIRQ_SET_TIMEOUT (5)
+#define MPUIRQ_SET_ACCEL_INFO (6)
+#define MPUIRQ_SET_FREQUENCY_DIVIDER (7)
+#define MPUIRQ_GET_DEBUG_FLAG (8)
+
+extern int mpu_debug_flag;
+
+#ifdef __KERNEL__
+
+void mpuirq_exit(void);
+int mpuirq_init(struct i2c_client *mpu_client);
+
+#endif
+
+#endif
diff --git a/drivers/input/misc/mpu3050/slaveirq.c b/drivers/input/misc/mpu3050/slaveirq.c
new file mode 100644
index 0000000..d985c26
--- /dev/null
+++ b/drivers/input/misc/mpu3050/slaveirq.c
@@ -0,0 +1,262 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/irq.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/poll.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+
+#include "mpu.h"
+#include "slaveirq.h"
+#include "mldl_cfg.h"
+#include "mpu-i2c.h"
+
+
+struct slaveirq_dev_data {
+ struct miscdevice dev;
+ struct i2c_client *slave_client;
+ struct mpuirq_data data;
+ wait_queue_head_t slaveirq_wait;
+ int irq;
+ int pid;
+ int data_ready;
+ int timeout;
+};
+
+static int slaveirq_open(struct inode *inode, struct file *file)
+{
+ struct slaveirq_dev_data *data =
+ container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+ dev_dbg(data->dev.this_device,
+ "%s current->pid %d\n", __func__, current->pid);
+ data->pid = current->pid;
+ return 0;
+}
+
+static int slaveirq_release(struct inode *inode, struct file *file)
+{
+ struct slaveirq_dev_data *data =
+ container_of(file->private_data, struct slaveirq_dev_data, dev);
+ dev_dbg(data->dev.this_device, "slaveirq_release\n");
+ return 0;
+}
+
+static ssize_t slaveirq_read(struct file *file,
+ char *buf, size_t count, loff_t *ppos)
+{
+ int len, err;
+ struct slaveirq_dev_data *data =
+ container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+ if (!data->data_ready) {
+ wait_event_interruptible_timeout(data->slaveirq_wait,
+ data->data_ready,
+ data->timeout);
+ }
+
+ if (data->data_ready && NULL != buf
+ && count >= sizeof(data->data)) {
+ err = copy_to_user(buf, &data->data, sizeof(data->data));
+ data->data.data_type = 0;
+ } else {
+ return 0;
+ }
+ if (err != 0) {
+ dev_err(data->dev.this_device,
+ "Copy to user returned %d\n", err);
+ return -EFAULT;
+ }
+ data->data_ready = 0;
+ len = sizeof(data->data);
+ return len;
+}
+
+unsigned int slaveirq_poll(struct file *file, struct poll_table_struct *poll)
+{
+ int mask = 0;
+ struct slaveirq_dev_data *data =
+ container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+ poll_wait(file, &data->slaveirq_wait, poll);
+ if (data->data_ready)
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+}
+
+static long slaveirq_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int tmp;
+ struct slaveirq_dev_data *data =
+ container_of(file->private_data, struct slaveirq_dev_data, dev);
+
+ switch (cmd) {
+ case SLAVEIRQ_SET_TIMEOUT:
+ data->timeout = arg;
+ break;
+
+ case SLAVEIRQ_GET_INTERRUPT_CNT:
+ tmp = data->data.interruptcount - 1;
+ if (data->data.interruptcount > 1)
+ data->data.interruptcount = 1;
+
+ if (copy_to_user((int *) arg, &tmp, sizeof(int)))
+ return -EFAULT;
+ break;
+ case SLAVEIRQ_GET_IRQ_TIME:
+ if (copy_to_user((int *) arg, &data->data.irqtime,
+ sizeof(data->data.irqtime)))
+ return -EFAULT;
+ data->data.irqtime = 0;
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static irqreturn_t slaveirq_handler(int irq, void *dev_id)
+{
+ struct slaveirq_dev_data *data = (struct slaveirq_dev_data *)dev_id;
+ static int mycount;
+ struct timeval irqtime;
+ mycount++;
+
+ data->data.interruptcount++;
+
+
+
+ data->data_ready = 1;
+
+ do_gettimeofday(&irqtime);
+ data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
+ data->data.irqtime += irqtime.tv_usec;
+ data->data.data_type |= 1;
+
+ wake_up_interruptible(&data->slaveirq_wait);
+
+ return IRQ_HANDLED;
+
+}
+
+static const struct file_operations slaveirq_fops = {
+ .owner = THIS_MODULE,
+ .read = slaveirq_read,
+ .poll = slaveirq_poll,
+
+#if HAVE_COMPAT_IOCTL
+ .compat_ioctl = slaveirq_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = slaveirq_ioctl,
+#endif
+ .open = slaveirq_open,
+ .release = slaveirq_release,
+};
+
+int slaveirq_init(struct i2c_adapter *slave_adapter,
+ struct ext_slave_platform_data *pdata,
+ char *name)
+{
+
+ int res;
+ struct slaveirq_dev_data *data;
+
+ if (!pdata->irq)
+ return -EINVAL;
+
+ pdata->irq_data = kzalloc(sizeof(*data),
+ GFP_KERNEL);
+ data = (struct slaveirq_dev_data *) pdata->irq_data;
+ if (!data)
+ return -ENOMEM;
+
+ data->dev.minor = MISC_DYNAMIC_MINOR;
+ data->dev.name = name;
+ data->dev.fops = &slaveirq_fops;
+ data->irq = pdata->irq;
+ data->pid = 0;
+ data->data_ready = 0;
+ data->timeout = 0;
+
+ init_waitqueue_head(&data->slaveirq_wait);
+
+ res = request_irq(data->irq, slaveirq_handler, IRQF_TRIGGER_RISING,
+ data->dev.name, data);
+
+ if (res) {
+ dev_err(&slave_adapter->dev,
+ "myirqtest: cannot register IRQ %d\n",
+ data->irq);
+ goto out_request_irq;
+ }
+
+ res = misc_register(&data->dev);
+ if (res < 0) {
+ dev_err(&slave_adapter->dev,
+ "misc_register returned %d\n",
+ res);
+ goto out_misc_register;
+ }
+
+ return res;
+
+out_misc_register:
+ free_irq(data->irq, data);
+out_request_irq:
+ kfree(pdata->irq_data);
+ pdata->irq_data = NULL;
+
+ return res;
+}
+
+void slaveirq_exit(struct ext_slave_platform_data *pdata)
+{
+ struct slaveirq_dev_data *data = pdata->irq_data;
+
+ if (!pdata->irq_data || data->irq <= 0)
+ return;
+
+ dev_info(data->dev.this_device, "Unregistering %s\n",
+ data->dev.name);
+
+ free_irq(data->irq, data);
+ misc_deregister(&data->dev);
+ kfree(pdata->irq_data);
+ pdata->irq_data = NULL;
+}
diff --git a/drivers/input/misc/mpu3050/slaveirq.h b/drivers/input/misc/mpu3050/slaveirq.h
new file mode 100644
index 0000000..ca9c7e4
--- /dev/null
+++ b/drivers/input/misc/mpu3050/slaveirq.h
@@ -0,0 +1,46 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef __SLAVEIRQ__
+#define __SLAVEIRQ__
+
+#ifdef __KERNEL__
+#include <linux/i2c-dev.h>
+#endif
+
+#include "mpu.h"
+#include "mpuirq.h"
+
+#define SLAVEIRQ_ENABLE_DEBUG (1)
+#define SLAVEIRQ_GET_INTERRUPT_CNT (2)
+#define SLAVEIRQ_GET_IRQ_TIME (3)
+#define SLAVEIRQ_GET_LED_VALUE (4)
+#define SLAVEIRQ_SET_TIMEOUT (5)
+#define SLAVEIRQ_SET_SLAVE_INFO (6)
+
+#ifdef __KERNEL__
+
+void slaveirq_exit(struct ext_slave_platform_data *pdata);
+int slaveirq_init(struct i2c_adapter *slave_adapter,
+ struct ext_slave_platform_data *pdata,
+ char *name);
+
+#endif
+
+#endif
diff --git a/drivers/input/misc/mpu3050/timerirq.c b/drivers/input/misc/mpu3050/timerirq.c
new file mode 100644
index 0000000..ce2b153
--- /dev/null
+++ b/drivers/input/misc/mpu3050/timerirq.c
@@ -0,0 +1,316 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/signal.h>
+#include <linux/miscdevice.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/poll.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+
+#include "mpu.h"
+#include "mltypes.h"
+#include "timerirq.h"
+
+struct timerirq_data {
+ int pid;
+ int data_ready;
+ int run;
+ int timeout;
+ unsigned long period;
+ struct mpuirq_data data;
+ struct completion timer_done;
+ wait_queue_head_t timerirq_wait;
+ struct timer_list timer;
+ struct miscdevice *dev;
+};
+
+static struct miscdevice *timerirq_dev_data;
+
+static void timerirq_handler(unsigned long arg)
+{
+ struct timerirq_data *data = (struct timerirq_data *)arg;
+ struct timeval irqtime;
+
+
+ data->data.interruptcount++;
+
+ data->data_ready = 1;
+
+ do_gettimeofday(&irqtime);
+ data->data.irqtime = (((long long) irqtime.tv_sec) << 32);
+ data->data.irqtime += irqtime.tv_usec;
+ data->data.data_type |= 1;
+
+ wake_up_interruptible(&data->timerirq_wait);
+
+ if (data->run)
+ mod_timer(&data->timer,
+ jiffies + msecs_to_jiffies(data->period));
+ else
+ complete(&data->timer_done);
+}
+
+static int start_timerirq(struct timerirq_data *data)
+{
+ dev_dbg(data->dev->this_device,
+ "%s current->pid %d\n", __func__, current->pid);
+
+
+ if (data->run)
+ return 0;
+
+
+ if (!data->period)
+ return -EINVAL;
+
+ if (data->period > 200)
+ data->period = 200;
+
+ printk(KERN_DEBUG "[GSNR][MPU3050][TIMERIRQ]%s: data->period = %lu\n",
+ __func__, data->period);
+
+ data->run = TRUE;
+ data->data_ready = FALSE;
+
+ return mod_timer(&data->timer,
+ jiffies + msecs_to_jiffies(data->period));
+}
+
+static int stop_timerirq(struct timerirq_data *data)
+{
+ int rc = -1;
+
+ dev_dbg(data->dev->this_device,
+ "%s current->pid %lx\n", __func__, (unsigned long)data);
+
+ printk(KERN_DEBUG "[GSNR][MPU3050][TIMERIRQ]%s: data->period = %lu, "
+ "data->run = %d\n",
+ __func__, data->period, data->run);
+
+ if (data->run) {
+ data->run = FALSE;
+ mod_timer(&data->timer, jiffies + 1);
+ wait_for_completion(&data->timer_done);
+
+ rc = del_timer_sync(&(data->timer));
+ }
+ return 0;
+}
+
+static int timerirq_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *dev_data = file->private_data;
+ struct timerirq_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->dev = dev_data;
+ file->private_data = data;
+ data->pid = current->pid;
+ init_waitqueue_head(&data->timerirq_wait);
+
+ dev_dbg(data->dev->this_device,
+ "%s current->pid %d\n", __func__, current->pid);
+
+ init_completion(&data->timer_done);
+ setup_timer(&data->timer, timerirq_handler, (unsigned long)data);
+
+ printk(KERN_DEBUG "[TIMERIRQ]%s: current->pid %d\n",
+ __func__, current->pid);
+
+ return 0;
+}
+
+static int timerirq_release(struct inode *inode, struct file *file)
+{
+ struct timerirq_data *data = file->private_data;
+ int rc = -1;
+
+ printk(KERN_DEBUG "[TIMERIRQ] %s: data->run = %d\n",
+ __func__, data->run);
+
+
+
+ if (data->run)
+ stop_timerirq(data);
+
+ rc = del_timer_sync(&(data->timer));
+ printk(KERN_DEBUG "[TIMERIRQ]%s: del_timer_sync"
+ "() return = %d\n", __func__, rc);
+
+ kfree(data);
+ return 0;
+}
+
+static ssize_t timerirq_read(struct file *file,
+ char *buf, size_t count, loff_t *ppos)
+{
+ int len, err;
+ struct timerirq_data *data = file->private_data;
+
+ if (!data->data_ready) {
+ wait_event_interruptible_timeout(data->timerirq_wait,
+ data->data_ready,
+ data->timeout);
+ }
+
+ if (data->data_ready && NULL != buf
+ && count >= sizeof(data->data)) {
+ err = copy_to_user(buf, &data->data, sizeof(data->data));
+ data->data.data_type = 0;
+ } else {
+ return 0;
+ }
+ if (err != 0) {
+ dev_err(data->dev->this_device,
+ "Copy to user returned %d\n", err);
+ return -EFAULT;
+ }
+ data->data_ready = 0;
+ len = sizeof(data->data);
+ return len;
+}
+
+unsigned int timerirq_poll(struct file *file, struct poll_table_struct *poll)
+{
+ int mask = 0;
+ struct timerirq_data *data = file->private_data;
+
+ poll_wait(file, &data->timerirq_wait, poll);
+ if (data->data_ready)
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+}
+
+static long timerirq_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int tmp;
+ struct timerirq_data *data = file->private_data;
+
+ dev_dbg(data->dev->this_device,
+ "%s current->pid %d, %d, %ld\n",
+ __func__, current->pid, cmd, arg);
+
+ if (!data)
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIMERIRQ_SET_TIMEOUT:
+ data->timeout = arg;
+ break;
+ case TIMERIRQ_GET_INTERRUPT_CNT:
+ tmp = data->data.interruptcount - 1;
+ if (data->data.interruptcount > 1)
+ data->data.interruptcount = 1;
+
+ if (copy_to_user((int *) arg, &tmp, sizeof(int)))
+ return -EFAULT;
+ break;
+ case TIMERIRQ_START:
+ data->period = arg;
+ retval = start_timerirq(data);
+ break;
+ case TIMERIRQ_STOP:
+ retval = stop_timerirq(data);
+ break;
+ default:
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static const struct file_operations timerirq_fops = {
+ .owner = THIS_MODULE,
+ .read = timerirq_read,
+ .poll = timerirq_poll,
+
+#if HAVE_COMPAT_IOCTL
+ .compat_ioctl = timerirq_ioctl,
+#endif
+#if HAVE_UNLOCKED_IOCTL
+ .unlocked_ioctl = timerirq_ioctl,
+#endif
+ .open = timerirq_open,
+ .release = timerirq_release,
+};
+
+static int __init timerirq_init(void)
+{
+
+ int res;
+ static struct miscdevice *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ timerirq_dev_data = data;
+ data->minor = MISC_DYNAMIC_MINOR;
+ data->name = "timerirq";
+ data->fops = &timerirq_fops;
+
+ res = misc_register(data);
+ if (res < 0) {
+ dev_err(data->this_device,
+ "misc_register returned %d\n",
+ res);
+ return res;
+ }
+
+ return res;
+}
+module_init(timerirq_init);
+
+static void __exit timerirq_exit(void)
+{
+ struct miscdevice *data = timerirq_dev_data;
+
+ dev_info(data->this_device, "Unregistering %s\n",
+ data->name);
+
+ printk(KERN_DEBUG "[TIMERIRQ]%s: Unregistering %s\n",
+ __func__, data->name);
+
+ misc_deregister(data);
+ kfree(data);
+
+ timerirq_dev_data = NULL;
+}
+module_exit(timerirq_exit);
+
+MODULE_AUTHOR("Invensense Corporation");
+MODULE_DESCRIPTION("Timer IRQ device driver.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("timerirq");
diff --git a/drivers/input/misc/mpu3050/timerirq.h b/drivers/input/misc/mpu3050/timerirq.h
new file mode 100644
index 0000000..a38b490
--- /dev/null
+++ b/drivers/input/misc/mpu3050/timerirq.h
@@ -0,0 +1,28 @@
+/*
+ $License:
+ Copyright (C) 2010 InvenSense Corporation, All Rights Reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ $
+ */
+
+#ifndef __TIMERIRQ__
+#define __TIMERIRQ__
+
+#define TIMERIRQ_SET_TIMEOUT (5)
+#define TIMERIRQ_GET_INTERRUPT_CNT (7)
+#define TIMERIRQ_START (8)
+#define TIMERIRQ_STOP (9)
+
+#endif