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/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);