summaryrefslogtreecommitdiff
path: root/drivers/input/sensor/mmc328x_msensor
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/input/sensor/mmc328x_msensor
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/input/sensor/mmc328x_msensor')
-rwxr-xr-xdrivers/input/sensor/mmc328x_msensor/Makefile4
-rwxr-xr-xdrivers/input/sensor/mmc328x_msensor/mecs.c433
-rwxr-xr-xdrivers/input/sensor/mmc328x_msensor/mecs.h60
-rwxr-xr-xdrivers/input/sensor/mmc328x_msensor/mmc328x.c505
-rwxr-xr-xdrivers/input/sensor/mmc328x_msensor/mmc328x.h91
5 files changed, 1093 insertions, 0 deletions
diff --git a/drivers/input/sensor/mmc328x_msensor/Makefile b/drivers/input/sensor/mmc328x_msensor/Makefile
new file mode 100755
index 00000000..bdf4598d
--- /dev/null
+++ b/drivers/input/sensor/mmc328x_msensor/Makefile
@@ -0,0 +1,4 @@
+s_wmt_msensor_mmc328x-objs += mmc328x.o
+obj-m += s_wmt_msensor_mmc328x.o
+s_wmt_generic_mecs-objs += mecs.o
+obj-m += s_wmt_generic_mecs.o \ No newline at end of file
diff --git a/drivers/input/sensor/mmc328x_msensor/mecs.c b/drivers/input/sensor/mmc328x_msensor/mecs.c
new file mode 100755
index 00000000..335ad266
--- /dev/null
+++ b/drivers/input/sensor/mmc328x_msensor/mecs.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2010 MEMSIC, Inc.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <asm/uaccess.h>
+//#include <linux/export.h>
+#include <linux/module.h>
+#include "mecs.h"
+
+#define DEBUG 0
+
+#define ECS_DATA_DEV_NAME "ecompass_data"
+#define ECS_CTRL_DEV_NAME "ecompass_ctrl"
+
+static int ecs_ctrl_open(struct inode *inode, struct file *file);
+static int ecs_ctrl_release(struct inode *inode, struct file *file);
+static int ecs_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+
+static DECLARE_WAIT_QUEUE_HEAD(open_wq);
+
+static atomic_t open_count;
+static atomic_t open_flag;
+static atomic_t reserve_open_flag;
+
+static atomic_t a_flag;
+static atomic_t m_flag;
+static atomic_t o_flag;
+
+static short ecompass_delay = 0;
+
+
+static struct input_dev *ecs_data_device;
+
+static struct file_operations ecs_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = ecs_ctrl_open,
+ .release = ecs_ctrl_release,
+ .unlocked_ioctl = ecs_ctrl_ioctl,
+};
+
+static struct miscdevice ecs_ctrl_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = ECS_CTRL_DEV_NAME,
+ .fops = &ecs_ctrl_fops,
+};
+
+static int ecs_ctrl_open(struct inode *inode, struct file *file)
+{
+#if 1
+ atomic_set(&reserve_open_flag, 1);
+ atomic_set(&open_flag, 1);
+ atomic_set(&open_count, 1);
+ wake_up(&open_wq);
+
+ return 0;
+#else
+ int ret = -1;
+
+ if (atomic_cmpxchg(&open_count, 0, 1) == 0) {
+ if (atomic_cmpxchg(&open_flag, 0, 1) == 0) {
+ atomic_set(&reserve_open_flag, 1);
+ wake_up(&open_wq);
+ ret = 0;
+ }
+ }
+
+ return ret;
+#endif
+}
+
+static int ecs_ctrl_release(struct inode *inode, struct file *file)
+{
+ atomic_set(&reserve_open_flag, 0);
+ atomic_set(&open_flag, 0);
+ atomic_set(&open_count, 0);
+ wake_up(&open_wq);
+
+ return 0;
+}
+
+static int ecs_ctrl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *pa = (void __user *)arg;
+ short flag;
+ short delay;
+ int parms[4];
+ int ypr[12];
+ unsigned int uval = 0;
+
+ switch (cmd) {
+ case ECOMPASS_IOC_SET_MODE:
+ break;
+ case ECOMPASS_IOC_SET_DELAY:
+ if (copy_from_user(&delay, pa, sizeof(delay)))
+ return -EFAULT;
+ ecompass_delay = delay;
+ break;
+ case ECOMPASS_IOC_GET_DELAY:
+ delay = ecompass_delay;
+ if (copy_to_user(pa, &delay, sizeof(delay)))
+ return -EFAULT;
+ break;
+
+ case ECOMPASS_IOC_SET_AFLAG:
+ if (copy_from_user(&flag, pa, sizeof(flag)))
+ return -EFAULT;
+ if (flag < 0 || flag > 1)
+ return -EINVAL;
+ atomic_set(&a_flag, flag);
+ break;
+ case ECOMPASS_IOC_GET_AFLAG:
+ flag = atomic_read(&a_flag);
+ if (copy_to_user(pa, &flag, sizeof(flag)))
+ return -EFAULT;
+ break;
+ case ECOMPASS_IOC_SET_MFLAG:
+ if (copy_from_user(&flag, pa, sizeof(flag)))
+ return -EFAULT;
+ if (flag < 0 || flag > 1)
+ return -EINVAL;
+ atomic_set(&m_flag, flag);
+ break;
+ case ECOMPASS_IOC_GET_MFLAG:
+ flag = atomic_read(&m_flag);
+ if (copy_to_user(pa, &flag, sizeof(flag)))
+ return -EFAULT;
+ break;
+ case ECOMPASS_IOC_SET_OFLAG:
+ if (copy_from_user(&flag, pa, sizeof(flag)))
+ return -EFAULT;
+ if (flag < 0 || flag > 1)
+ return -EINVAL;
+ atomic_set(&o_flag, flag);
+ break;
+ case ECOMPASS_IOC_GET_OFLAG:
+ flag = atomic_read(&o_flag);
+ if (copy_to_user(pa, &flag, sizeof(flag)))
+ return -EFAULT;
+ break;
+
+ case ECOMPASS_IOC_SET_APARMS:
+ if (copy_from_user(parms, pa, sizeof(parms)))
+ return -EFAULT;
+ /* acceleration x-axis */
+ input_set_abs_params(ecs_data_device, ABS_X,
+ parms[0], parms[1], parms[2], parms[3]);
+ /* acceleration y-axis */
+ input_set_abs_params(ecs_data_device, ABS_Y,
+ parms[0], parms[1], parms[2], parms[3]);
+ /* acceleration z-axis */
+ input_set_abs_params(ecs_data_device, ABS_Z,
+ parms[0], parms[1], parms[2], parms[3]);
+ break;
+ case ECOMPASS_IOC_GET_APARMS:
+ break;
+ case ECOMPASS_IOC_SET_MPARMS:
+ if (copy_from_user(parms, pa, sizeof(parms)))
+ return -EFAULT;
+ /* magnetic raw x-axis */
+ input_set_abs_params(ecs_data_device, ABS_HAT0X,
+ parms[0], parms[1], parms[2], parms[3]);
+ /* magnetic raw y-axis */
+ input_set_abs_params(ecs_data_device, ABS_HAT0Y,
+ parms[0], parms[1], parms[2], parms[3]);
+ /* magnetic raw z-axis */
+ input_set_abs_params(ecs_data_device, ABS_BRAKE,
+ parms[0], parms[1], parms[2], parms[3]);
+ break;
+ case ECOMPASS_IOC_GET_MPARMS:
+ break;
+ case ECOMPASS_IOC_SET_OPARMS_YAW:
+ if (copy_from_user(parms, pa, sizeof(parms)))
+ return -EFAULT;
+ /* orientation yaw */
+ input_set_abs_params(ecs_data_device, ABS_RX,
+ parms[0], parms[1], parms[2], parms[3]);
+ break;
+ case ECOMPASS_IOC_GET_OPARMS_YAW:
+ break;
+ case ECOMPASS_IOC_SET_OPARMS_PITCH:
+ if (copy_from_user(parms, pa, sizeof(parms)))
+ return -EFAULT;
+ /* orientation pitch */
+ input_set_abs_params(ecs_data_device, ABS_RY,
+ parms[0], parms[1], parms[2], parms[3]);
+ break;
+ case ECOMPASS_IOC_GET_OPARMS_PITCH:
+ break;
+ case ECOMPASS_IOC_SET_OPARMS_ROLL:
+ if (copy_from_user(parms, pa, sizeof(parms)))
+ return -EFAULT;
+ /* orientation roll */
+ input_set_abs_params(ecs_data_device, ABS_RZ,
+ parms[0], parms[1], parms[2], parms[3]);
+ break;
+ case ECOMPASS_IOC_GET_OPARMS_ROLL:
+ break;
+
+ case ECOMPASS_IOC_SET_YPR:
+ if (copy_from_user(ypr, pa, sizeof(ypr)))
+ return -EFAULT;
+ /* Report acceleration sensor information */
+ if (atomic_read(&a_flag)) {
+ input_report_abs(ecs_data_device, ABS_X, ypr[0]);
+ input_report_abs(ecs_data_device, ABS_Y, ypr[1]);
+ input_report_abs(ecs_data_device, ABS_Z, ypr[2]);
+ input_report_abs(ecs_data_device, ABS_WHEEL, ypr[3]);
+ }
+
+ /* Report magnetic sensor information */
+ if (atomic_read(&m_flag)) {
+ input_report_abs(ecs_data_device, ABS_HAT0X, ypr[4]);
+ input_report_abs(ecs_data_device, ABS_HAT0Y, ypr[5]);
+ input_report_abs(ecs_data_device, ABS_BRAKE, ypr[6]);
+ input_report_abs(ecs_data_device, ABS_GAS, ypr[7]);
+ }
+
+ /* Report orientation information */
+ if (atomic_read(&o_flag)) {
+ input_report_abs(ecs_data_device, ABS_RX, ypr[8]);
+ input_report_abs(ecs_data_device, ABS_RY, ypr[9]);
+ input_report_abs(ecs_data_device, ABS_RZ, ypr[10]);
+ input_report_abs(ecs_data_device, ABS_RUDDER, ypr[11]);
+ }
+
+ input_sync(ecs_data_device);
+ break;
+
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = 0;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static ssize_t ecs_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ sprintf(buf, "ecompass_ctrl");//!!!
+ ret = strlen(buf) + 1;
+
+ return ret;
+}
+
+static DEVICE_ATTR(ecs_ctrl, S_IRUGO, ecs_ctrl_show, NULL);
+
+//**********************
+static struct input_dev *g_input;
+struct timer_list mytimer;
+static void rep_pwer(long var)
+{
+ static int i = 0;
+ i++;
+#if 0
+ input_report_abs(g_input, ABS_X,i);
+ input_report_abs(g_input, ABS_Y, i);
+ input_report_abs(g_input, ABS_Z, i);
+ //input_report_abs(ecs_data_device, ABS_GAS, 2);
+ input_sync(g_input);
+#endif
+
+ input_report_abs(ecs_data_device, ABS_HAT0X,i);
+ input_report_abs(ecs_data_device, ABS_HAT0Y, i);
+ input_report_abs(ecs_data_device, ABS_BRAKE, i);
+ input_report_abs(ecs_data_device, ABS_GAS, 2);
+ input_sync(ecs_data_device);
+ //printk("<<<<memscid timer\n");
+ mod_timer(&mytimer, jiffies + HZ/10);
+}
+//**********************************
+
+static int __init ecompass_init(void)
+{
+ int res = 0;
+
+ pr_info("ecompass driver: init\n");
+
+ //*******************here want to report KEY_POWER using timer*** to test suspend & resume
+ init_timer(&mytimer);
+ mytimer.function = rep_pwer;
+ mytimer.expires = jiffies + 2*HZ;
+ mytimer.data = 100;
+ // add_timer(&mytimer);
+ printk("<<<<%s add timer ok!\n", __FUNCTION__);
+
+
+ int err=0;
+ g_input=input_allocate_device();
+ if (!g_input)
+ return -ENOMEM;
+ else
+ printk(KERN_INFO "input device allocate Success !!\n");
+ /* Setup input device */
+ set_bit(EV_ABS, g_input->evbit);
+ /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */
+ input_set_abs_params(g_input, ABS_HAT0X, -5144576, 5144576, 0, 0);
+ input_set_abs_params(g_input, ABS_HAT0Y, -5144576, 5144576, 0, 0);
+ input_set_abs_params(g_input, ABS_BRAKE, -5144576, 5144576, 0, 0);
+
+ /* Set InputDevice Name */
+ g_input->name = "ecompass_data";
+
+ /* Register */
+ //err = input_register_device(g_input);
+ //*****************************************2013-4-13
+
+ ecs_data_device = input_allocate_device();
+ if (!ecs_data_device) {
+ res = -ENOMEM;
+ pr_err("%s: failed to allocate input device\n", __FUNCTION__);
+ goto out;
+ }
+
+ set_bit(EV_ABS, ecs_data_device->evbit);
+
+ /* 32768 == 1g, range -4g ~ +4g */
+ /* acceleration x-axis */
+ input_set_abs_params(ecs_data_device, ABS_X,
+ -32768*4, 32768*4, 0, 0);
+ /* acceleration y-axis */
+ input_set_abs_params(ecs_data_device, ABS_Y,
+ -32768*4, 32768*4, 0, 0);
+ /* acceleration z-axis */
+ input_set_abs_params(ecs_data_device, ABS_Z,
+ -32768*4, 32768*4, 0, 0);
+ /* acceleration status, 0 ~ 3 */
+ input_set_abs_params(ecs_data_device, ABS_WHEEL,
+ 0, 100, 0, 0);
+
+ /* 32768 == 1gauss, range -4gauss ~ +4gauss */
+ /* magnetic raw x-axis */
+ input_set_abs_params(ecs_data_device, ABS_HAT0X,
+ -32768*4, 32768*4, 0, 0);
+ /* magnetic raw y-axis */
+ input_set_abs_params(ecs_data_device, ABS_HAT0Y,
+ -32768*4, 32768*4, 0, 0);
+ /* magnetic raw z-axis */
+ input_set_abs_params(ecs_data_device, ABS_BRAKE,
+ -32768*4, 32768*4, 0, 0);
+ /* magnetic raw status, 0 ~ 3 */
+ input_set_abs_params(ecs_data_device, ABS_GAS,
+ 0, 100, 0, 0);
+
+ /* 65536 == 360degree */
+ /* orientation yaw, 0 ~ 360 */
+ input_set_abs_params(ecs_data_device, ABS_RX,
+ 0, 65536, 0, 0);
+ /* orientation pitch, -180 ~ 180 */
+ input_set_abs_params(ecs_data_device, ABS_RY,
+ -65536/2, 65536/2, 0, 0);
+ /* orientation roll, -90 ~ 90 */
+ input_set_abs_params(ecs_data_device, ABS_RZ,
+ -65536/4, 65536/4, 0, 0);
+ /* orientation status, 0 ~ 3 */
+ input_set_abs_params(ecs_data_device, ABS_RUDDER,
+ 0, 100, 0, 0);
+
+ ecs_data_device->name = ECS_DATA_DEV_NAME;
+#if 1
+ res = input_register_device(ecs_data_device);
+ if (res) {
+ pr_err("%s: unable to register input device: %s\n",
+ __FUNCTION__, ecs_data_device->name);
+ goto out_free_input;
+ }
+#endif
+
+ res = misc_register(&ecs_ctrl_device);
+ if (res) {
+ pr_err("%s: ecs_ctrl_device register failed\n", __FUNCTION__);
+ goto out_free_input;
+ }
+ res = device_create_file(ecs_ctrl_device.this_device, &dev_attr_ecs_ctrl);
+ if (res) {
+ pr_err("%s: device_create_file failed\n", __FUNCTION__);
+ goto out_deregister_misc;
+ }
+
+ return 0;
+
+out_deregister_misc:
+ misc_deregister(&ecs_ctrl_device);
+out_free_input:
+ input_free_device(ecs_data_device);
+out:
+ return res;
+}
+
+static void __exit ecompass_exit(void)
+{
+ pr_info("ecompass driver: exit\n");
+ device_remove_file(ecs_ctrl_device.this_device, &dev_attr_ecs_ctrl);
+ misc_deregister(&ecs_ctrl_device);
+ input_free_device(ecs_data_device);
+}
+
+module_init(ecompass_init);
+module_exit(ecompass_exit);
+
+MODULE_DESCRIPTION("MEMSIC eCompass Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/sensor/mmc328x_msensor/mecs.h b/drivers/input/sensor/mmc328x_msensor/mecs.h
new file mode 100755
index 00000000..c328e585
--- /dev/null
+++ b/drivers/input/sensor/mmc328x_msensor/mecs.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 MEMSIC, Inc.
+ *
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Definitions for ECOMPASS magnetic sensor chip.
+ */
+#ifndef __ECOMPASS_H__
+#define __ECOMPASS_H__
+
+#include <linux/ioctl.h>
+
+/* Use 'e' as magic number */
+#define ECOMPASS_IOM 'e'
+
+/* IOCTLs for ECOMPASS device */
+#define ECOMPASS_IOC_SET_MODE _IOW(ECOMPASS_IOM, 0x00, short)
+#define ECOMPASS_IOC_SET_DELAY _IOW(ECOMPASS_IOM, 0x01, short)
+#define ECOMPASS_IOC_GET_DELAY _IOR(ECOMPASS_IOM, 0x02, short)
+
+#define ECOMPASS_IOC_SET_AFLAG _IOW(ECOMPASS_IOM, 0x10, short)
+#define ECOMPASS_IOC_GET_AFLAG _IOR(ECOMPASS_IOM, 0x11, short)
+#define ECOMPASS_IOC_SET_MFLAG _IOW(ECOMPASS_IOM, 0x12, short)
+#define ECOMPASS_IOC_GET_MFLAG _IOR(ECOMPASS_IOM, 0x13, short)
+#define ECOMPASS_IOC_SET_OFLAG _IOW(ECOMPASS_IOM, 0x14, short)
+#define ECOMPASS_IOC_GET_OFLAG _IOR(ECOMPASS_IOM, 0x15, short)
+
+#define ECOMPASS_IOC_SET_APARMS _IOW(ECOMPASS_IOM, 0x20, int[4])
+#define ECOMPASS_IOC_GET_APARMS _IOR(ECOMPASS_IOM, 0x21, int[4])
+#define ECOMPASS_IOC_SET_MPARMS _IOW(ECOMPASS_IOM, 0x22, int[4])
+#define ECOMPASS_IOC_GET_MPARMS _IOR(ECOMPASS_IOM, 0x23, int[4])
+#define ECOMPASS_IOC_SET_OPARMS_YAW _IOW(ECOMPASS_IOM, 0x24, int[4])
+#define ECOMPASS_IOC_GET_OPARMS_YAW _IOR(ECOMPASS_IOM, 0x25, int[4])
+#define ECOMPASS_IOC_SET_OPARMS_PITCH _IOW(ECOMPASS_IOM, 0x26, int[4])
+#define ECOMPASS_IOC_GET_OPARMS_PITCH _IOR(ECOMPASS_IOM, 0x27, int[4])
+#define ECOMPASS_IOC_SET_OPARMS_ROLL _IOW(ECOMPASS_IOM, 0x28, int[4])
+#define ECOMPASS_IOC_GET_OPARMS_ROLL _IOR(ECOMPASS_IOM, 0x29, int[4])
+
+#define ECOMPASS_IOC_SET_YPR _IOW(ECOMPASS_IOM, 0x30, int[12])
+
+#define WMTGSENSOR_IOCTL_MAGIC 0x09
+#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int)
+#endif /* __ECOMPASS_H__ */
+
diff --git a/drivers/input/sensor/mmc328x_msensor/mmc328x.c b/drivers/input/sensor/mmc328x_msensor/mmc328x.c
new file mode 100755
index 00000000..4148b5f1
--- /dev/null
+++ b/drivers/input/sensor/mmc328x_msensor/mmc328x.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2011 MEMSIC, Inc.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/sysctl.h>
+#include <asm/uaccess.h>
+#include <linux/input.h>
+//#include <linux/mmc328x.h>
+#include "mmc328x.h"
+#define DEBUG 0
+#define MAX_FAILURE_COUNT 3
+#define READMD 0
+
+#define MMC328X_DELAY_TM 10 /* ms */
+#define MMC328X_DELAY_RM 10 /* ms */
+#define MMC328X_DELAY_STDN 1 /* ms */
+#define MMC328X_DELAY_RRM 1 /* ms */
+
+#define MMC328X_RETRY_COUNT 3
+#define MMC328X_RRM_INTV 100
+
+
+//******************************* move from memsicd 2013-4-26
+#define MMC328X_OFFSET_X 4096
+#define MMC328X_OFFSET_Y 4096
+#define MMC328X_OFFSET_Z 4096
+//******************************************
+
+#define MMC328X_DEV_NAME "mmc328x"
+#define CONFIG_SENSORS_MMC328xMA_MAG //add rambo 2013-4-20
+struct i2c_client *g_client;
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static u32 read_idx = 0;
+
+static struct i2c_client *this_client;
+
+static struct wmt_msensor_data l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .samp = 5,
+ .xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },
+ .sensor_proc = NULL,
+ .isdbg = 0,
+ .sensor_samp = 10, // 1 sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ .offset={0,0,0},
+};
+
+static int get_axisset(void)
+{
+ char varbuf[64];
+ int n;
+ int varlen;
+
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+ if (wmt_getsyspara("wmt.io.msensor328x", varbuf, &varlen)) {
+ printk("Can't get gsensor config in u-boot!!!!\n");
+ //return -1;
+ } else {
+ n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d",
+
+ &(l_sensorconfig.xyz_axis[0][0]),
+ &(l_sensorconfig.xyz_axis[0][1]),
+ &(l_sensorconfig.xyz_axis[1][0]),
+ &(l_sensorconfig.xyz_axis[1][1]),
+ &(l_sensorconfig.xyz_axis[2][0]),
+ &(l_sensorconfig.xyz_axis[2][1])
+
+ );
+ if (n != 6) {
+ printk("gsensor format is error in u-boot!!!\n");
+ return -1;
+ }
+ l_sensorconfig.sensor_samp = l_sensorconfig.samp;
+
+ printk("get the sensor config: %d:%d:%d:%d:%d:%d\n",
+
+ l_sensorconfig.xyz_axis[0][0],
+ l_sensorconfig.xyz_axis[0][1],
+ l_sensorconfig.xyz_axis[1][0],
+ l_sensorconfig.xyz_axis[1][1],
+ l_sensorconfig.xyz_axis[2][0],
+ l_sensorconfig.xyz_axis[2][1]
+ );
+ }
+ return 0;
+}
+
+
+static int mmc328x_i2c_rx_data(char *buf, int len)
+{
+ uint8_t i;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = buf,
+ },
+ {
+ .addr = this_client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = buf,
+ }
+ };
+
+ for (i = 0; i < MMC328X_RETRY_COUNT; i++) {
+ if (i2c_transfer(this_client->adapter, msgs, 2) >= 0) {
+ break;
+ }
+ mdelay(10);
+ }
+
+ if (i >= MMC328X_RETRY_COUNT) {
+ pr_err("%s: retry over %d\n", __FUNCTION__, MMC328X_RETRY_COUNT);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int mmc328x_i2c_tx_data(char *buf, int len)
+{
+ uint8_t i;
+ struct i2c_msg msg[] = {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = len,
+ .buf = buf,
+ }
+ };
+
+ for (i = 0; i < MMC328X_RETRY_COUNT; i++) {
+ if (i2c_transfer(this_client->adapter, msg, 1) >= 0) {
+ break;
+ }
+ mdelay(10);
+ }
+
+ if (i >= MMC328X_RETRY_COUNT) {
+ pr_err("%s: retry over %d\n", __FUNCTION__, MMC328X_RETRY_COUNT);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int mmc328x_open(struct inode *inode, struct file *file)
+{
+ return nonseekable_open(inode, file);
+}
+
+static int mmc328x_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int mmc328x_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *pa = (void __user *)arg;
+ unsigned char data[16] = {0};
+ int vec[3] = {0};
+ int tmp[3] = {0};
+
+ int MD_times = 0;
+
+ switch (cmd) {
+ case MMC328X_IOC_TM:
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_TM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ return -EFAULT;
+ }
+ /* wait TM done for coming data read */
+ msleep(MMC328X_DELAY_TM);
+ break;
+ case MMC328X_IOC_RM:
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_RM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ return -EFAULT;
+ }
+ /* wait external capacitor charging done for next SET*/
+ msleep(MMC328X_DELAY_RM);
+ break;
+ case MMC328X_IOC_RRM:
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_RRM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ return -EFAULT;
+ }
+ /* wait external capacitor charging done for next RRM */
+ msleep(MMC328X_DELAY_RM);
+ break;
+ case MMC328X_IOC_READ:
+ data[0] = MMC328X_REG_DATA;
+ if (mmc328x_i2c_rx_data(data, 6) < 0) {
+ return -EFAULT;
+ }
+ tmp[0] = data[1] << 8 | data[0];
+ tmp[1] = data[3] << 8 | data[2];
+ tmp[2] = data[5] << 8 | data[4];
+ tmp[2] = 8192 - tmp[2] ;
+ //add 2013-4-26
+ tmp[0] -= MMC328X_OFFSET_X;
+ tmp[1] -= MMC328X_OFFSET_Y;
+ tmp[2] -= MMC328X_OFFSET_Z;
+ //add end
+ vec[0] = tmp[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1];
+
+ vec[1] = tmp[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1];
+
+ vec[2] = tmp[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1];
+
+ #if DEBUG
+ printk("[X - %04x] [Y - %04x] [Z - %04x]\n",
+ vec[0], vec[1], vec[2]);
+ #endif
+ if (copy_to_user(pa, vec, sizeof(vec))) {
+ return -EFAULT;
+ }
+ break;
+ case MMC328X_IOC_READXYZ:
+ /* do RM every MMC328X_RRM_INTV times read */
+ if (!(read_idx % MMC328X_RRM_INTV)) {
+#ifdef CONFIG_SENSORS_MMC328xMA_MAG
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_RRM;
+ mmc328x_i2c_tx_data(data, 2);
+ msleep(MMC328X_DELAY_RRM);
+#endif
+ /* RM */
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_RM;
+ /* not check return value here, assume it always OK */
+ mmc328x_i2c_tx_data(data, 2);
+ /* wait external capacitor charging done for next RM */
+ msleep(MMC328X_DELAY_RM);
+ }
+ read_idx++;
+
+ /* send TM cmd before read */
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_TM;
+ /* not check return value here, assume it always OK */
+ mmc328x_i2c_tx_data(data, 2);
+ /* wait TM done for coming data read */
+ msleep(MMC328X_DELAY_TM);
+#if READMD
+ /* Read MD */
+ data[0] = MMC328X_REG_DS;
+ if (mmc328x_i2c_rx_data(data, 1) < 0) {
+ return -EFAULT;
+ }
+ while (!(data[0] & 0x01)) {
+ msleep(1);
+ /* Read MD again*/
+ data[0] = MMC328X_REG_DS;
+ if (mmc328x_i2c_rx_data(data, 1) < 0) {
+ return -EFAULT;
+ }
+
+ if (data[0] & 0x01) break;
+ MD_times++;
+ if (MD_times > 2) {
+ #if DEBUG
+ printk("TM not work!!");
+ #endif
+ return -EFAULT;
+ }
+ }
+#endif
+ /* read xyz raw data */
+ data[0] = MMC328X_REG_DATA;
+ if (mmc328x_i2c_rx_data(data, 6) < 0) {
+ return -EFAULT;
+ }
+ tmp[0] = data[1] << 8 | data[0];
+ tmp[1] = data[3] << 8 | data[2];
+ tmp[2] = data[5] << 8 | data[4];
+ tmp[2] = 8192 - tmp[2];
+ //add 2013-4-26
+ tmp[0] -= MMC328X_OFFSET_X;
+ tmp[1] -= MMC328X_OFFSET_Y;
+ tmp[2] -= MMC328X_OFFSET_Z;
+ //add
+ vec[0] = tmp[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1];
+
+ vec[1] = tmp[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1];
+
+ vec[2] = tmp[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1];
+
+
+
+ #if DEBUG
+ printk("[X - %04x] [Y - %04x] [Z - %04x]\n",
+ vec[0], vec[1], vec[2]);
+ #endif
+ if (copy_to_user(pa, vec, sizeof(vec))) {
+ return -EFAULT;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static ssize_t mmc328x_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ sprintf(buf, "MMC328X");//!!!
+ ret = strlen(buf) + 1;
+
+ return ret;
+}
+
+static DEVICE_ATTR(mmc328x, S_IRUGO, mmc328x_show, NULL);
+
+static struct file_operations mmc328x_fops = {
+ .owner = THIS_MODULE,
+ .open = mmc328x_open,
+ .release = mmc328x_release,
+ .unlocked_ioctl = mmc328x_ioctl,
+};
+
+static struct miscdevice mmc328x_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = MMC328X_DEV_NAME,
+ .fops = &mmc328x_fops,
+};
+
+static int mmc328x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ unsigned char data[16] = {0};
+ int res = 0;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("%s: functionality check failed\n", __FUNCTION__);
+ res = -ENODEV;
+ goto out;
+ }
+ this_client = client;
+
+ res = misc_register(&mmc328x_device);//
+ if (res) {
+ pr_err("%s: mmc328x_device register failed\n", __FUNCTION__);
+ goto out;
+ }
+ res = device_create_file(&client->dev, &dev_attr_mmc328x);//
+ if (res) {
+ pr_err("%s: device_create_file failed\n", __FUNCTION__);
+ goto out_deregister;
+ }
+
+ /* send RM/RRM cmd to mag sensor first of all */
+#ifdef CONFIG_SENSORS_MMC328xMA_MAG
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_RRM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ }
+ msleep(MMC328X_DELAY_RRM);
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_TM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ }
+ msleep(5*MMC328X_DELAY_TM);
+#endif
+
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_RM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ /* assume RM always success */
+ }
+#ifndef CONFIG_SENSORS_MMC328xMA_MAG
+ /* wait external capacitor charging done for next RM */
+ msleep(MMC328X_DELAY_RM);
+#else
+ msleep(10*MMC328X_DELAY_RM);
+ data[0] = MMC328X_REG_CTRL;
+ data[1] = MMC328X_CTRL_TM;
+ if (mmc328x_i2c_tx_data(data, 2) < 0) {
+ }
+#endif
+
+ return 0;
+
+out_deregister:
+ misc_deregister(&mmc328x_device);
+out:
+ return res;
+}
+
+static int mmc328x_remove(struct i2c_client *client)
+{
+ device_remove_file(&client->dev, &dev_attr_mmc328x);
+ misc_deregister(&mmc328x_device);
+
+ return 0;
+}
+
+static const struct i2c_device_id mmc328x_id[] = {
+ { MMC328X_I2C_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver mmc328x_driver = {
+ .probe = mmc328x_probe,
+ .remove = mmc328x_remove,
+ .id_table = mmc328x_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MMC328X_I2C_NAME,
+ },
+};
+
+//****************************add by rambo to create i2c client 2013-4-18
+static struct i2c_board_info mmc328x_board_info =
+{
+ .type = MMC328X_I2C_NAME,
+ .addr = MMC328X_I2C_ADDR,
+};
+
+//******************************************
+
+static int __init mmc328x_init(void)
+{
+ int ret;
+ pr_info("mmc328x driver: init\n");
+
+ ret = get_axisset();
+ struct i2c_adapter *adapter;
+ adapter = i2c_get_adapter(0);
+ if (!adapter)
+ {
+ printk("<<<<<%s i2c get adapter fail!\n", __FUNCTION__);
+ return -1;
+ }
+ g_client = i2c_new_device(adapter, &mmc328x_board_info);
+ if (!g_client)
+ {
+ printk("<<<<%s i2c new device fail!\n", __FUNCTION__);
+ i2c_put_adapter(adapter);
+ return -1;
+ }
+ i2c_put_adapter(adapter);
+
+ return i2c_add_driver(&mmc328x_driver);
+}
+
+static void __exit mmc328x_exit(void)
+{
+ if (g_client != NULL)
+ {
+ i2c_unregister_device(g_client);
+ }
+ pr_info("mmc328x driver: exit\n");
+ i2c_del_driver(&mmc328x_driver);
+}
+
+module_init(mmc328x_init);
+module_exit(mmc328x_exit);
+
+MODULE_DESCRIPTION("MEMSIC MMC328X Magnetic Sensor Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/sensor/mmc328x_msensor/mmc328x.h b/drivers/input/sensor/mmc328x_msensor/mmc328x.h
new file mode 100755
index 00000000..f272ea1d
--- /dev/null
+++ b/drivers/input/sensor/mmc328x_msensor/mmc328x.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 MEMSIC, Inc.
+ *
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+ * Definitions for mmc328x magnetic sensor chip.
+ */
+#ifndef __MMC328X_H__
+#define __MMC328X_H__
+
+#include <linux/ioctl.h>
+
+#define MMC328X_I2C_NAME "mmc328x"
+
+/*
+ * This address comes must match the part# on your target.
+ * Address to the sensor part# support as following list:
+ * MMC3280MS - 0110000b
+ * MMC3281MS - 0110001b
+ * MMC3282MS - 0110010b
+ * MMC3283MS - 0110011b
+ * MMC3284MS - 0110100b
+ * MMC3285MS - 0110101b
+ * MMC3286MS - 0110110b
+ * MMC3287MS - 0110111b
+ * Please refer to sensor datasheet for detail.
+ */
+ struct wmt_msensor_data{
+ // for control
+ int int_gpio; //0-3
+ int op;
+ int samp;
+ int xyz_axis[3][2]; // (axis,direction)
+ struct proc_dir_entry* sensor_proc;
+ struct input_dev *input_dev;
+ //struct work_struct work;
+ struct delayed_work work; // for polling
+ struct workqueue_struct *queue;
+ int isdbg;
+ int sensor_samp; //
+ int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor
+ int test_pass;
+ int offset[3];
+ struct i2c_client *client;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend earlysuspend;
+#endif
+
+};
+#define MMC328X_I2C_ADDR 0x30
+
+/* MMC328X register address */
+#define MMC328X_REG_CTRL 0x07
+#define MMC328X_REG_DATA 0x00
+#define MMC328X_REG_DS 0x06
+
+/* MMC328X control bit */
+#define MMC328X_CTRL_TM 0x01
+#define MMC328X_CTRL_RM 0x20
+#define MMC328X_CTRL_RRM 0x40
+#define MMC328X_CTRL_NOBOOST 0x10
+
+/* Use 'm' as magic number */
+#define MMC328X_IOM 'm'
+
+/* IOCTLs for MMC328X device */
+#define MMC328X_IOC_TM _IO (MMC328X_IOM, 0x00)
+#define MMC328X_IOC_RM _IO (MMC328X_IOM, 0x01)
+#define MMC328X_IOC_READ _IOR(MMC328X_IOM, 0x02, int[3])
+#define MMC328X_IOC_READXYZ _IOR(MMC328X_IOM, 0x03, int[3])
+#define MMC328X_IOC_RRM _IO (MMC328X_IOM, 0x04)
+#define MMC328X_IOC_NOBOOST _IO (MMC328X_IOM, 0x05)
+
+#endif /* __MMC328X_H__ */
+