diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/sensor')
73 files changed, 35149 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/input/sensor/Kconfig b/ANDROID_3.4.5/drivers/input/sensor/Kconfig new file mode 100755 index 00000000..cff1aa40 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/Kconfig @@ -0,0 +1,224 @@ +# +# WMT Sensor configuration +# +menuconfig INPUT_SENSOR + bool "WMT Sensor" + default y + help + Say Y here, and a list of supported sensor will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_SENSOR + +config WMT_SENSOR_KXTE9 + tristate "KXTE9 G-Sensor Support" + depends on ARCH_WMT + default n + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_mc3230. +config WMT_SENSOR_KIONIX + tristate "KIONIX G-Sensor Support" + depends on ARCH_WMT + default n + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_kionix. +config WMT_SENSOR_MC3XXX + tristate "Mcube G-Sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_mc3xxx. + +config WMT_SENSOR_DMARD08 + tristate "DMARD08 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard08. +config WMT_SENSOR_DMARD06 + tristate "DMARD06 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard06. +config WMT_SENSOR_DMARD10 + tristate "DMARD10 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard10. +config WMT_SENSOR_DMARD09 + tristate "DMARD09 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmard09. +config WMT_SENSOR_MXC622X + tristate "MXC622X G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_mxc622x. +config WMT_SENSOR_MMA7660 + tristate "MMA7660 G-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_mma7660. +config WMT_SENSOR_MMC328x + tristate "MMC328x M-Sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with m-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_mmc328x. +config WMT_SENSOR_ISL29023 + tristate "ISL29023 Light sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with l-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_isl29023. +config WMT_SENSOR_CM3232 + tristate "CM3232 Light sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with l-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_cm3232. +config WMT_SENSOR_STK3310 + tristate "STK3310 Light sensor Support" + depends on ARCH_WMT + default y + help + Say Y here if you have an WMT based board with l-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_stk3310. +config WMT_GYRO_L3G4200D + tristate "L3G4200D Gyroscope Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with ST L3g4200d + gyroscope attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gyro_l3g4200d. + +config WMT_SENSOR_US5182 + tristate "US5182 Light&Promixity sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with l&p-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_lsensor_us5182. + +config WMT_SENSOR_MMA8452Q + tristate "MMA8452Q G-Sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_mma8542. + +config WMT_SENSOR_STK8312 + tristate "STK8312 G-Sensor Support" + depends on ARCH_WMT + default m + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called s_wmt_gsensor_STK8312. + +endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/Makefile new file mode 100755 index 00000000..cc06e871 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/Makefile @@ -0,0 +1,26 @@ +#
+# Makefile for the Sensor driver
+#
+
+# Each configuration option enables a list of files.
+
+#obj-$(CONFIG_INPUT_SENSOR) += gsensor.o
+obj-y += sensor.o
+obj-$(CONFIG_WMT_SENSOR_KXTE9) += kxte9_gsensor/
+obj-$(CONFIG_WMT_SENSOR_MC3XXX) += mc3xxx_gsensor/
+obj-$(CONFIG_WMT_SENSOR_DMARD08) += dmard08_gsensor/
+obj-$(CONFIG_WMT_SENSOR_DMARD06) += dmard06_gsensor/
+obj-$(CONFIG_WMT_SENSOR_MMA7660) += mma7660_gsensor/
+obj-$(CONFIG_WMT_SENSOR_ISL29023) += isl29023_lsensor/
+obj-$(CONFIG_WMT_SENSOR_CM3232) += cm3232/ +obj-$(CONFIG_WMT_SENSOR_CM3232) += stk3310/ +obj-$(CONFIG_WMT_SENSOR_DMARD10) += dmard10_gsensor/
+obj-$(CONFIG_WMT_SENSOR_DMARD09) += dmard09_gsensor/
+obj-$(CONFIG_WMT_SENSOR_MXC622X) += mxc622x_gsensor/ +obj-$(CONFIG_WMT_SENSOR_MMC328x) += mmc328x_msensor/
+#obj-$(CONFIG_WMT_SENSOR_CM3232) += cm3232/cm3232.o
+obj-$(CONFIG_WMT_GYRO_L3G4200D) += l3g4200d_gyro/
+obj-$(CONFIG_WMT_SENSOR_US5182) += us5182_lpsensor/
+obj-$(CONFIG_WMT_SENSOR_MMA8452Q) += mma8452q_gsensor/
+obj-$(CONFIG_WMT_SENSOR_STK8312) += stk8312_gsensor/
+obj-$(CONFIG_WMT_SENSOR_KIONIX) += kionix_gsensor/
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig new file mode 100755 index 00000000..9bf96e92 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Kconfig @@ -0,0 +1,50 @@ +# +# WMT Sensor configuration +# +menuconfig INPUT_SENSOR + bool "WMT Sensor" + help + Say Y here, and a list of supported sensor will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_SENSOR + + +config WMT_SENSOR_KXTI9 + tristate "KXTI9 G-Sensor Support" + depends on ARCH_WMT + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_kxti9. + +config WMT_SENSOR_DMT08 + tristate "DMT08 G-Sensor Support" + depends on ARCH_WMT + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmt08. + +config WMT_SENSOR_DMT10 + tristate "DMT10 G-Sensor Support" + depends on ARCH_WMT + help + Say Y here if you have an WMT based board with g-sensor + attached to it. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called sensor_dmt10. +endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile new file mode 100755 index 00000000..ee1a0ac5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for the Sensor driver +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_INPUT_SENSOR) += gsensor.o + +obj-$(CONFIG_WMT_SENSOR_KXTI9) += kxti9_gsensor/ + +obj-$(CONFIG_WMT_SENSOR_DMT08) += dmt08_gsensor/ + +obj-$(CONFIG_WMT_SENSOR_DMT10) += dmt10_gsensor/ diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile new file mode 100755 index 00000000..6edce54a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the DMARD06 Sensor driver +# + +sensor_dmt08-objs := dmt08.o +obj-$(CONFIG_WMT_SENSOR_DMT08) += sensor_dmt08.o diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c new file mode 100755 index 00000000..2ed5f502 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.c @@ -0,0 +1,870 @@ +/* + * @file drivers/misc/dmt0308.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.31 + * @date 2012/3/27 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/cdev.h> +#include <linux/wakelock.h> +#include <asm/uaccess.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/serio.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <mach/hardware.h> +#include <asm/io.h> +#include <linux/miscdevice.h> +#include <mach/gpio.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/syscalls.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include "dmt08.h" +#include "../gsensor.h" + +wait_queue_head_t open_wq; +atomic_t active; +static unsigned int interval; +struct mutex DMT_mutex; +struct delayed_work work; +struct work_struct irq_work; +atomic_t delay; + +static struct gsensor_conf gs_conf; + +void gsensor_write_offset_to_file(void); +void gsensor_read_offset_from_file(void); +char OffsetFileName[] = "/data/misc/dmt/offset.txt"; +static int Device_First_Time_Opened_flag=1; +//************************************************* +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +#define CHIP_ENABLE 137 +#if (defined(CONFIG_SENSORS_DMARD03) || defined(CONFIG_SENSORS_DMARD03_MODULE)) +static char const *const GSENSOR_DEVICE_NAME = "dmard03"; +#elif (defined(CONFIG_SENSORS_DMARD08) || defined(CONFIG_SENSORS_DMARD08_MODULE) || defined(CONFIG_WMT_SENSOR_DMT08)) +static char const *const GSENSOR_DEVICE_NAME = "dmard08"; +#endif + +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static ssize_t device_write(struct file*, const char*, size_t, loff_t*); +static ssize_t device_read(struct file*, char*, size_t, loff_t*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +//static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +//static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client); +static inline void device_i2c_correct_accel_sign(s16 *val); +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz); +void device_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb); + +struct input_dev *input; + +static int DMT_GetOpenStatus(void) +{ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + printk("%s:start active=%d\n",__func__,active.counter); +#endif + wait_event_interruptible(open_wq, (atomic_read(&active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(void) +{ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + printk("%s:start active=%d\n",__func__,active.counter); +#endif + wait_event_interruptible(open_wq, (atomic_read(&active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(int en) +{ + unsigned long dmt_delay; + if(en) + { + dmt_delay = msecs_to_jiffies(atomic_read(&delay)); + if(dmt_delay < 1) + dmt_delay = 1; + //printk("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&work,dmt_delay); + } + else + cancel_delayed_work_sync(&work); +} + +static ssize_t DMT_enable_acc_show( struct device *dev, struct device_attribute *attr, char *buf) +{ + buf="show"; + return 1; +} + +static ssize_t DMT_enable_acc_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count) +{ + int en; +#if DMT_DEBUG_DATA + printk("%s:buf=%x %x\n",__func__,buf[0],buf[1]); +#endif + if(buf[0]!= 0x30 && buf[0]!= 0x31) + { + printk("%s:illegle data !!\n",__func__); + return 0; + } + en= (buf[0]-0x30 > 0) ? 1:0; + DMT_sysfs_update_active_status(en); + return 1; +} + +static ssize_t DMT_delay_acc_show( struct device *dev, struct device_attribute *attr, char *buf){ + return 1; +} + +static ssize_t DMT_delay_acc_store( struct device *dev, struct device_attribute *attr,char const *buf, size_t count) +{ + int error; + unsigned long data; + error = strict_strtoul(buf, 10, &data); + if(error) { + pr_err("%s strict_strtoul error\n", __FUNCTION__); + return -1; + } + mutex_lock(&DMT_mutex); + interval=(unsigned int)data; + mutex_unlock(&DMT_mutex); + atomic_set(&delay, (unsigned int) data); +#if DMT_DEBUG_DATA + printk("Driver attribute set delay =%lu\n",data); +#endif + return 1; +} + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0755, DMT_enable_acc_show, DMT_enable_acc_store), + __ATTR(delay_acc, 0755, DMT_delay_acc_show, DMT_delay_acc_store), + __ATTR_NULL, +}; + +static int create_device_attributes(struct device *dev, struct device_attribute *attrs) +{ + int i; + int err = 0; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +int input_init(void) +{ + int err=0; + input=input_allocate_device(); + if (!input) + return -ENOMEM; + else + printk("input device allocate Success !!\n"); + /* Setup input device */ + set_bit(EV_ABS, input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16*/ + input_set_abs_params(input, ABS_X, -1024, 1024, 0, 0); + input_set_abs_params(input, ABS_Y, -1024, 1024, 0, 0); + input_set_abs_params(input, ABS_Z, -1024, 1024, 0, 0); + + /* Set name */ + input->name = "g-sensor"; + + /* Register */ + err = input_register_device(input); + if (err) { + input_free_device(input); + return err; + } + atomic_set(&active, 0); +#if DMT_DEBUG_DATA + printk("in driver ,active=%d\n",active.counter); +#endif + init_waitqueue_head(&open_wq); + + return err; +} + +typedef union { + struct { + s16 x; + s16 y; + s16 z; + } u; + s16 v[SENSOR_DATA_SIZE]; +} raw_data; +static raw_data offset; + +struct dev_data { + dev_t devno; + struct cdev cdev; + struct class *class; + struct i2c_client *client; +}; +static struct dev_data dev; + +s16 sensorlayout[3][3] = { +#if defined(CONFIG_GSEN_LAYOUT_PAT_1) + { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_2) + { 0, 1, 0}, {-1, 0, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_3) + {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_4) + { 0,-1, 0}, { 1, 0, 0}, { 0, 0, 1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_5) + {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_6) + { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_7) + { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, +#elif defined(CONFIG_GSEN_LAYOUT_PAT_8) + { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, +#endif +}; + +void gsensor_read_accel_avg(int num_avg, raw_data *avg_p ) +{ + long xyz_acc[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + int i, j; + + //initialize the accumulation buffer + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < num_avg; i++) + { + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_acc[j] += xyz[j]; + } + + // calculate averages + for(i = 0; i < SENSOR_DATA_SIZE; i++) + avg_p->v[i] = (s16) (xyz_acc[i] / num_avg); +} +/* calc delta offset */ +int gsensor_calculate_offset(int gAxis,raw_data avg) +{ + switch(gAxis) + { + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z + DEFAULT_SENSITIVITY; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE: + offset.u.x = avg.u.x + DEFAULT_SENSITIVITY; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z ; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z - DEFAULT_SENSITIVITY; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE: + offset.u.x = avg.u.x - DEFAULT_SENSITIVITY; + offset.u.y = avg.u.y ; + offset.u.z = avg.u.z ; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y + DEFAULT_SENSITIVITY; + offset.u.z = avg.u.z ; + break; + case CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE: + offset.u.x = avg.u.x ; + offset.u.y = avg.u.y - DEFAULT_SENSITIVITY; + offset.u.z = avg.u.z ; + break; + default: + return -ENOTTY; + } + return 0; +} + +void gsensor_calibrate(int side){ + raw_data avg; + int avg_num = 16; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + // get acceleration average reading + gsensor_read_accel_avg(avg_num, &avg); + // calculate and set the offset + gsensor_calculate_offset(side, avg); +} + +void ce_on(void){ + //omap_mux_set_gpio(OMAP_PIN_INPUT_PULLUP, CHIP_ENABLE); +} + +void ce_off(void){ + //omap_mux_set_gpio(OMAP_PIN_INPUT_PULLDOWN, CHIP_ENABLE); +} + +void gsensor_reset(void){ + ce_off(); + msleep(300); + ce_on(); +} + +void gsensor_set_offset(int val[3]) +{ + int i; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = (s16) val[i]; +} + +static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + return 0; +} + +static int device_i2c_resume(struct i2c_client *client) +{ + return 0; +} + +static void device_i2c_shutdown(struct i2c_client *client) +{ + flush_delayed_work_sync(&work); + cancel_delayed_work_sync(&work); +} + +struct file_operations dmt_g_sensor_fops = { + .owner = THIS_MODULE, + .read = device_read, + .write = device_write, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static const struct i2c_device_id device_i2c_ids[] = { + {DEVICE_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, device_i2c_ids); + +static struct i2c_driver device_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, + .shutdown = device_i2c_shutdown, + .id_table = device_i2c_ids, +}; + +static int device_open(struct inode *inode, struct file *filp){ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + //Device_First_Time_Opened_flag + if(Device_First_Time_Opened_flag) + { + Device_First_Time_Opened_flag=0; + //gsensor_read_offset_from_file(); + } + return 0; +} + +static ssize_t device_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + return 0; +} + +static ssize_t device_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + s16 xyz[SENSOR_DATA_SIZE]; + int i; + + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + //offset compensation + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz[i] -= offset.v[i]; + + if(copy_to_user(buf, &xyz, count)) + return -EFAULT; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + PRINT_X_Y_Z(xyz[0], xyz[1], xyz[2]); +#endif + + return count; +} + +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + //check type and number + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > SENSOR_MAXNR) return -ENOTTY; + + //check user space pointer is valid + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) + { + case SENSOR_RESET: + //gsensor_reset(); + printk("RUN RESET"); + return ret; + + case SENSOR_CALIBRATION: + // get orientation info + if(copy_from_user(&intBuf, (int*)arg, sizeof(int))) return -EFAULT; + gsensor_calibrate(intBuf[0]); + // write in to file + gsensor_write_offset_to_file(); + + // return the offset + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + // get offset from file + gsensor_read_offset_from_file(); + + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + gsensor_set_offset(intBuf); + // write in to file + gsensor_write_offset_to_file(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) + { + printk("%s:copy_from_user(&intBuf, (int*)arg, sizeof(intBuf)) ERROR, -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(input, ABS_X, intBuf[0]); + input_report_abs(input, ABS_Y, intBuf[1]); + input_report_abs(input, ABS_Z, intBuf[2]); + input_sync(input); + //printk("%s:SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",__func__,intBuf[0],intBuf[1],intBuf[2]); + + return 1; + case SENSOR_GET_OPEN_STATUS: + //printk("%s:Going into DMT_GetOpenStatus()\n",__func__); + DMT_GetOpenStatus(); + //printk("%s:DMT_GetOpenStatus() finished\n",__func__); + return 1; + break; + case SENSOR_GET_CLOSE_STATUS: + //printk("%s:Going into DMT_GetCloseStatus()\n",__func__); + DMT_GetCloseStatus(); + //printk("%s:DMT_GetCloseStatus() finished\n",__func__); + return 1; + break; + case SENSOR_GET_DELAY: + + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return 1; + break; + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp) +{ + printk("Close device\n"); + return 0; +} + +static int device_i2c_xyz_read_reg(struct i2c_client *client,u8 *buffer, int length) +{ + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = 1, .buf = buffer,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = buffer,}, + }; +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + return i2c_transfer(client->adapter, msg, 2); +} + +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz_p) +{ + u8 buffer[6]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int i, j; + + //get xyz high/low bytes, 0x02~0x07 + buffer[0] = 2; + device_i2c_xyz_read_reg(client, buffer, 6); + + //merge to 11-bits value + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + device_i2c_merge_register_values(client, (xyzTmp + i), buffer[2*i], buffer[2*i + 1]); + //transfer to the default layout + for(j = 0; j < 3; j++) + xyz_p[i] += sensorlayout[i][j] * xyzTmp[j]; + } +} + +void device_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb) +{ + *val = (((u16)msb) << 3) | (u16)lsb; + device_i2c_correct_accel_sign(val); +} + +static inline void device_i2c_correct_accel_sign(s16 *val) +{ + *val<<= (sizeof(s16) * BITS_PER_BYTE - 11); + *val>>= (sizeof(s16) * BITS_PER_BYTE - 11); +} + +static void DMT_work_func(struct work_struct *fakework) +{ + int i; + static int firsttime=0; + s16 xyz[SENSOR_DATA_SIZE]; + unsigned long t=atomic_read(&delay); + unsigned long dmt_delay = msecs_to_jiffies(t); + if(!firsttime) + { + //gsensor_read_offset_from_file(); + firsttime=1; + } + + //dmt_delay/=1000; + +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + printk("t=%lu ,dmt_delay=%lu\n",t,dmt_delay); +#endif + + device_i2c_read_xyz(dev.client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz[i] -= offset.v[i]; + +#if DMT_DEBUG_DATA + printk("x: %d, y: %d, z: %d\n", xyz[0], xyz[1], xyz[2]); +#endif + input_report_abs(input, ABS_X, xyz[gs_conf.xyz_axis[ABS_X][0]]*gs_conf.xyz_axis[ABS_X][1]); + input_report_abs(input, ABS_Y, xyz[gs_conf.xyz_axis[ABS_Y][0]]*gs_conf.xyz_axis[ABS_Y][1]); + input_report_abs(input, ABS_Z, xyz[gs_conf.xyz_axis[ABS_Z][0]]*gs_conf.xyz_axis[ABS_Z][1]); + input_sync(input); + + if(dmt_delay<1) + dmt_delay=1; + + schedule_delayed_work(&work, dmt_delay); +} + + +static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) +{ + u8 buffer[4]; + int i; + + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = 0; + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + printk("%s, functionality check failed\n", __func__); + return -1; + } + + gsensor_reset(); + + buffer[0] = CONTROL_REGISTERS; + device_i2c_xyz_read_reg(client, buffer, 4); + if( buffer[0] == 0x00 && buffer[1] == 0x00 && buffer[2] == 0x88 && buffer[3] == 0x08) + { + printk(KERN_INFO "i2c Read 0x08 = %d!\n",buffer[0]); + printk(KERN_INFO "i2c Read 0x09 = %d!\n",buffer[1]); + printk(KERN_INFO "i2c Read 0x0a = %d!\n",buffer[2]); + printk(KERN_INFO "i2c Read 0x0b = %d!\n",buffer[3]); + printk(KERN_INFO "@@@ %s DMT_DEVICE_NAME registered I2C driver!\n",__FUNCTION__); + dev.client = client; + } + else + { + printk(KERN_INFO "err : i2c Read 0x08 = %d!\n",buffer[0]); + printk(KERN_INFO "err : i2c Read 0x09 = %d!\n",buffer[1]); + printk(KERN_INFO "err : i2c Read 0x0a = %d!\n",buffer[2]); + printk(KERN_INFO "err : i2c Read 0x0b = %d!\n",buffer[3]); + dev.client = NULL; + return -1; + } +#if DMT_DEBUG_DATA + IN_FUNC_MSG; + //check sensorlayout[i][j] + for(i = 0; i < 3; ++i) + { + for(j = 0; j < 3; j++) + printk("%d",sensorlayout[i][j]); + printk("\n"); + } +#endif + return 0; +} + +static int __devexit device_i2c_remove(struct i2c_client *client) +{ +#if DMT_DEBUG_DATA + IN_FUNC_MSG; +#endif + return 0; +} + +int dmt08_enable(int en) +{ + printk(KERN_DEBUG "%s: enable = %d\n", __func__, en); + DMT_sysfs_update_active_status(en); + return 0; +} + +int dmt08_setDelay(int mdelay) +{ + printk(KERN_DEBUG "%s: delay = %d\n", __func__, mdelay); + atomic_set(&delay, mdelay); + return 0; +} + +int dmt08_getLSG(int *lsg) +{ + *lsg = 256; + return 0; +} + +struct gsensor_data dmt08_gs_data = { + .i2c_addr = DMT08_I2C_ADDR, + .enable = dmt08_enable, + .setDelay = dmt08_setDelay, + .getLSG = dmt08_getLSG, +}; + +static int __init device_init(void) +{ + int err=-1; + struct device *device; + int ret = 0; + IN_FUNC_MSG; + + if (get_gsensor_conf(&gs_conf)) + return -1; + + if (gs_conf.op != 1) + return -1; + + printk("G-Sensor dmt08 init\n"); + + if (gsensor_register(&dmt08_gs_data)) + return -1; + + if (gsensor_i2c_register_device() < 0) + return -1; + + atomic_set(&delay, 200); + + ret = alloc_chrdev_region(&dev.devno, 0, 1, GSENSOR_DEVICE_NAME); + if(ret) + { + printk("%s, can't allocate chrdev\n", __func__); + return ret; + } + printk("%s, register chrdev(%d, %d)\n", __func__, MAJOR(dev.devno), MINOR(dev.devno)); + + cdev_init(&dev.cdev, &dmt_g_sensor_fops); + dev.cdev.owner = THIS_MODULE; + ret = cdev_add(&dev.cdev, dev.devno, 1); + if(ret < 0) + { + printk("%s, add character device error, ret %d\n", __func__, ret); + return ret; + } + dev.class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if(IS_ERR(dev.class)) + { + printk("%s, create class, error\n", __func__); + return ret; + } + device=device_create(dev.class, NULL, dev.devno, NULL, GSENSOR_DEVICE_NAME); + + mutex_init(&DMT_mutex); + + INIT_DELAYED_WORK(&work, DMT_work_func); + printk("DMT: INIT_DELAYED_WORK\n"); + + err=input_init(); + if(err) + { + printk("%s:input_init fail, error code= %d\n", __func__, err); + } + + err = create_device_attributes(device,DMT_attributes); + + return i2c_add_driver(&device_i2c_driver); +} + + +static void __exit device_exit(void) +{ + IN_FUNC_MSG; + input_unregister_device(input); + input_free_device(input); + cdev_del(&dev.cdev); + unregister_chrdev_region(dev.devno, 1); + device_destroy(dev.class, dev.devno); + class_destroy(dev.class); + i2c_del_driver(&device_i2c_driver); +} + + +void gsensor_write_offset_to_file(void) +{ + char data[18]; + unsigned int orgfs; + long lfile=-1; + spinlock_t lock; //add by yang + spin_lock_init(&lock); //add by yang + sprintf(data,"%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); + + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile=sys_open(OffsetFileName,O_WRONLY|O_CREAT, 0777); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + } + else + { + spin_lock(&lock); //add by yang + sys_write(lfile, data,18); + sys_close(lfile); + spin_unlock(&lock); //add by yang + } + set_fs(orgfs); +} + +void gsensor_read_offset_from_file(void) +{ + unsigned int orgfs; + char data[18]; + long lfile=-1; + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile = sys_open(OffsetFileName, O_RDONLY, 0); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + strcpy(data,"00000 00000 00000"); + + } + else + { + sys_read(lfile, data, 18); + sys_close(lfile); + } + sscanf(data,"%hd %hd %hd",&offset.u.x,&offset.u.y,&offset.u.z); + printk("%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); + set_fs(orgfs); +} + +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h new file mode 100755 index 00000000..5a1ac3b7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt08_gsensor/dmt08.h @@ -0,0 +1,105 @@ +/* + * @file include/linux/dmt.h + * @brief DMARD05 & DMARD06 & DMARD07 g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.31 + * @date 2012/3/27 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ +#ifndef DMT_H +#define DMT_H + +#if (defined(CONFIG_SENSORS_DMARD05) || defined(CONFIG_SENSORS_DMARD05_MODULE)) +#define DEVICE_I2C_NAME "dmard05" +#define DEFAULT_SENSITIVITY 64 +#define WHO_AM_I_VALUE 0x05 +#define X_OUT 0x41 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#elif (defined(CONFIG_SENSORS_DMARD06) || defined(CONFIG_SENSORS_DMARD06_MODULE)) +#define DEVICE_I2C_NAME "dmard06" +#define DEFAULT_SENSITIVITY 32 +#define WHO_AM_I_VALUE 0x06 +#define X_OUT 0x41 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#elif (defined(CONFIG_SENSORS_DMARD07) || defined(CONFIG_SENSORS_DMARD07_MODULE)) +#define DEVICE_I2C_NAME "dmard07" +#define DEFAULT_SENSITIVITY 64 +#define WHO_AM_I_VALUE 0x07 +#define X_OUT 0x41 +#define SW_RESET 0x53 +#define WHO_AM_I 0x0f +#elif (defined(CONFIG_SENSORS_DMARD03) || defined(CONFIG_SENSORS_DMARD03_MODULE)) +#define DEVICE_I2C_NAME "dmard03" +#define DEFAULT_SENSITIVITY 256 +#define CONTROL_REGISTERS 0x08 +#elif (defined(CONFIG_SENSORS_DMARD08) || defined(CONFIG_SENSORS_DMARD08_MODULE) || defined(CONFIG_WMT_SENSOR_DMT08)) +#define DEVICE_I2C_NAME "g-sensor" +#define DEFAULT_SENSITIVITY 256 +#define CONTROL_REGISTERS 0x08 +#define DMT08_I2C_ADDR 0x1c +#endif + +//#define DMT_DEBUG_DATA 1 +#define DMT_DEBUG_DATA 0 + +#if DMT_DEBUG_DATA +#define IN_FUNC_MSG printk(KERN_INFO "@DMT@ In %s\n", __func__) +#define PRINT_X_Y_Z(x, y, z) printk(KERN_INFO "@DMT@ X/Y/Z axis: %04d , %04d , %04d\n", (x), (y), (z)) +#define PRINT_OFFSET(x, y, z) printk(KERN_INFO "@offset@ X/Y/Z axis: %04d , %04d , %04d\n",offset.x,offset.y,offset.z); +#else +#define IN_FUNC_MSG +#define PRINT_X_Y_Z(x, y, z) +#define PRINT_OFFSET(x, y, z) +#endif + +//g-senor layout configuration, choose one of the following configuration +#define CONFIG_GSEN_LAYOUT_PAT_1 +//#define CONFIG_GSEN_LAYOUT_PAT_2 +//#define CONFIG_GSEN_LAYOUT_PAT_3 +//#define CONFIG_GSEN_LAYOUT_PAT_4 +//#define CONFIG_GSEN_LAYOUT_PAT_5 +//#define CONFIG_GSEN_LAYOUT_PAT_6 +//#define CONFIG_GSEN_LAYOUT_PAT_7 +//#define CONFIG_GSEN_LAYOUT_PAT_8 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_DATA_SIZE 3 + +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) + +#define SENSOR_MAXNR 8 + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile new file mode 100755 index 00000000..de723bf5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the DMARD10 Sensor driver +# + +sensor_dmt10-objs := dmt10.o +obj-$(CONFIG_WMT_SENSOR_DMT10) += sensor_dmt10.o diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c new file mode 100755 index 00000000..e8e7b288 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.c @@ -0,0 +1,950 @@ +/* + * @file drivers/misc/dmt10.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.03 + * + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * V1.00 D10 First Release date 2012/09/21 + * V1.01 static struct dmt_data s_dmt Refresh to device_i2c_probe date 2012/11/23 + * V1.02 0x0D cck : adjustment 204.8KHz core clock date 2012/11/30 + * V1.03 write TCGYZ & TCGX : set value to 0x00 date 2012/12/10 + * + * @DMT Package version D10_General_driver v1.4 + * + */ +#include "dmt10.h" +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/wakelock.h> +#include <asm/uaccess.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/clk.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/string.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include "../gsensor.h" + +static struct gsensor_conf gs_conf; + +static unsigned int interval; +void gsensor_write_offset_to_file(void); +void gsensor_read_offset_from_file(void); +char OffsetFileName[] = "/data/misc/dmt/offset.txt"; /* FILE offset.txt */ +static raw_data offset; +static struct dmt_data *s_dmt; +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client); +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz); +static int device_i2c_rxdata(struct i2c_client *client, unsigned char *rxDat, int length); +static int device_i2c_txdata(struct i2c_client *client, unsigned char *txData, int length); + +static int DMT_GetOpenStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(struct dmt_data *dmt , int en){ + unsigned long dmt_delay; + if(en){ + dmt_delay = msecs_to_jiffies(atomic_read(&dmt->delay)); + if(dmt_delay < 1) + dmt_delay = 1; + + GSE_LOG("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&dmt->delaywork,dmt_delay); + } + else + cancel_delayed_work_sync(&dmt->delaywork); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value){ + long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + return true; +} +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + return true; +} + +static ssize_t dmt_sysfs_enable_show( + struct dmt_data *dmt, char *buf, int pos) +{ + char str[2][16]={"ACC enable OFF","ACC enable ON"}; + int flag; + flag=atomic_read(&dmt->enable); + return sprintf(buf, "%s\n", str[flag]); +} + +static ssize_t dmt_sysfs_enable_store( + struct dmt_data *dmt, char const *buf, size_t count, int pos) +{ + int en = 0; + if (NULL == buf) + return -EINVAL; + GSE_LOG("buf=%x %x\n", buf[0], buf[1]); + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return count; +} + +/***** Acceleration ***/ +static ssize_t DMT_enable_acc_show(struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_enable_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t DMT_enable_acc_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count){ + return dmt_sysfs_enable_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/***** sysfs delay **************************************************/ +static ssize_t dmt_sysfs_delay_show( struct dmt_data *dmt, char *buf, int pos){ + return sprintf(buf, "%d\n", atomic_read(&dmt->delay)); +} + +static ssize_t dmt_sysfs_delay_store( struct dmt_data *dmt, char const *buf, size_t count, int pos){ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + atomic_set(&dmt->delay, (unsigned int) val); + GSE_LOG("Driver attribute set delay =%lld\n", val); + + return count; +} + +/***** Accelerometer ***/ +static ssize_t DMT_delay_acc_show( struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_delay_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t DMT_delay_acc_store( struct device *dev, struct device_attribute *attr,char const *buf, size_t count){ + return dmt_sysfs_delay_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0755, DMT_enable_acc_show, DMT_enable_acc_store), + __ATTR(delay_acc, 0755, DMT_delay_acc_show, DMT_delay_acc_store), + __ATTR_NULL, +}; + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const GSENSOR_DEVICE_NAME = "dmard10"; +static char const *const device_link_name = "i2c"; +static dev_t const dmt_device_dev_t = MKDEV(MISC_MAJOR, 240); + +/***** dmt sysfs functions ******************************************/ +static int create_device_attributes(struct device *dev, struct device_attribute *attrs){ + int i; + int err = 0; + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_sysfs_interfaces(struct dmt_data *dmt) +{ + int err; + + if (NULL == dmt) + return -EINVAL; + + err = 0; + dmt->class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if (IS_ERR(dmt->class)) { + err = PTR_ERR(dmt->class); + goto exit_class_create_failed; + } + + dmt->class_dev = device_create( + dmt->class, + NULL, + dmt_device_dev_t, + dmt, + GSENSOR_DEVICE_NAME); + if (IS_ERR(dmt->class_dev)) { + err = PTR_ERR(dmt->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &dmt->class_dev->kobj, + &dmt->client->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + dmt->class_dev, + DMT_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; +#if 0 + err = create_device_binary_attributes( + &dmt->class_dev->kobj, + dmt_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; +#endif + + return err; + +#if 0 +exit_device_binary_attributes_create_failed: + remove_device_attributes(dmt->class_dev, dmt_attributes); +#endif +exit_device_attributes_create_failed: + sysfs_remove_link(&dmt->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(dmt->class, dmt_device_dev_t); +exit_class_device_create_failed: + dmt->class_dev = NULL; + class_destroy(dmt->class); +exit_class_create_failed: + dmt->class = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct dmt_data *dmt) +{ + if (NULL == dmt) + return; + + if (NULL != dmt->class_dev) { + + remove_device_attributes( + dmt->class_dev, + DMT_attributes); + sysfs_remove_link( + &dmt->class_dev->kobj, + device_link_name); + dmt->class_dev = NULL; + } + if (NULL != dmt->class) { + device_destroy( + dmt->class, + dmt_device_dev_t); + class_destroy(dmt->class); + dmt->class = NULL; + } +} + +int input_init(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int err=0; + dmt->input=input_allocate_device(); + if (!dmt->input){ + GSE_ERR("input device allocate ERROR !!\n"); + return -ENOMEM; + } + else + GSE_LOG("input device allocate Success !!\n"); + /* Setup input device */ + set_bit(EV_ABS, dmt->input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(dmt->input, ABS_X, -1024, 1024, 0, 0); + input_set_abs_params(dmt->input, ABS_Y, -1024, 1024, 0, 0); + input_set_abs_params(dmt->input, ABS_Z, -1024, 1024, 0, 0); + /* Set InputDevice Name */ + dmt->input->name = INPUT_NAME_ACC; + /* Register */ + err = input_register_device(dmt->input); + if (err) { + GSE_ERR("input_register_device ERROR !!\n"); + input_free_device(dmt->input); + return err; + } + GSE_LOG("input_register_device SUCCESS %d !! \n",err); + + return err; +} + +int gsensor_calibrate(void) +{ + //struct dmt_data *dmt = i2c_get_clientdata(client); + raw_data avg; + int i, j; + long xyz_acc[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + + offset.u.x=0; + offset.u.y=0; + offset.u.z=0; + /* initialize the accumulation buffer */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < AVG_NUM; i++) { + device_i2c_read_xyz(s_dmt->client, (s16 *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; ++j) + xyz_acc[j] += xyz[j]; + } + /* calculate averages */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + avg.v[i] = (s16) (xyz_acc[i] / AVG_NUM); + + if(avg.v[2] < 0){ + offset.u.x = avg.v[0] ; + offset.u.y = avg.v[1] ; + offset.u.z = avg.v[2] + DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE; + } + else{ + offset.u.x = avg.v[0] ; + offset.u.y = avg.v[1] ; + offset.u.z = avg.v[2] - DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE; + } + return 0; +} + +int gsensor_reset(struct i2c_client *client){ + unsigned char buffer[7], buffer2[2]; + /* 1. check D10 , VALUE_STADR = 0x55 , VALUE_STAINT = 0xAA */ + buffer[0] = REG_STADR; + buffer2[0] = REG_STAINT; + + device_i2c_rxdata(client, buffer, 2); + device_i2c_rxdata(client, buffer2, 2); + + if( buffer[0] == VALUE_STADR || buffer2[0] == VALUE_STAINT){ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d\n", buffer[0], buffer2[0]); + } + else{ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d \n", buffer[0], buffer2[0]); + return -1; + } + /* 2. Powerdown reset */ + buffer[0] = REG_PD; + buffer[1] = VALUE_PD_RST; + device_i2c_txdata(client, buffer, 2); + /* 3. ACTR => Standby mode => Download OTP to parameter reg => Standby mode => Reset data path => Standby mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_ReadOTP; + buffer[3] = MODE_Standby; + buffer[4] = MODE_ResetDataPath; + buffer[5] = MODE_Standby; + device_i2c_txdata(client, buffer, 6); + /* 4. OSCA_EN = 1 ,TSTO = b'000(INT1 = normal, TEST0 = normal) */ + buffer[0] = REG_MISC2; + buffer[1] = VALUE_MISC2_OSCA_EN; + device_i2c_txdata(client, buffer, 2); + /* 5. AFEN = 1(AFE will powerdown after ADC) */ + buffer[0] = REG_AFEM; + buffer[1] = VALUE_AFEM_AFEN_Normal; + buffer[2] = VALUE_CKSEL_ODR_100_204; + buffer[3] = VALUE_INTC; + buffer[4] = VALUE_TAPNS_Ave_2; + buffer[5] = 0x00; // DLYC, no delay timing + buffer[6] = 0x07; // INTD=1 (push-pull), INTA=1 (active high), AUTOT=1 (enable T) + device_i2c_txdata(client, buffer, 7); + /* 6. write TCGYZ & TCGX */ + buffer[0] = REG_WDAL; // REG:0x01 + buffer[1] = 0x00; // set TC of Y,Z gain value + buffer[2] = 0x00; // set TC of X gain value + buffer[3] = 0x03; // Temperature coefficient of X,Y,Z gain + device_i2c_txdata(client, buffer, 4); + + buffer[0] = REG_ACTR; // REG:0x00 + buffer[1] = MODE_Standby; // Standby + buffer[2] = MODE_WriteOTPBuf; // WriteOTPBuf + buffer[3] = MODE_Standby; // Standby + device_i2c_txdata(client, buffer, 4); + //buffer[0] = REG_TCGYZ; + //device_i2c_rxdata(client, buffer, 2); + //GSE_LOG(" TCGYZ = %d, TCGX = %d \n", buffer[0], buffer[1]); + + /* 7. Activation mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Active; + device_i2c_txdata(client, buffer, 2); + return 0; +} + +void gsensor_set_offset(int val[3]){ + int i; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = (s16) val[i]; +} + +struct file_operations dmt_g_sensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static struct miscdevice dmt_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = DEVICE_I2C_NAME, + .fops = &dmt_g_sensor_fops, +}; + +static int sensor_close_dev(struct i2c_client *client){ + char buffer[3]; + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_Off; + GSE_FUN(); + return device_i2c_txdata(client,buffer, 3); +} + +static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg){ + GSE_FUN(); + return sensor_close_dev(client); +} + +static int device_i2c_resume(struct i2c_client *client){ + GSE_FUN(); + return gsensor_reset(client); +} + +static void device_i2c_shutdown(struct i2c_client *client) +{ + struct dmt_data *dmt = i2c_get_clientdata(client); + flush_delayed_work_sync(&dmt->delaywork); + cancel_delayed_work_sync(&dmt->delaywork); +} + +static int __devexit device_i2c_remove(struct i2c_client *client){ + return 0; +} + +static const struct i2c_device_id device_i2c_ids[] = { + {DEVICE_I2C_NAME, 0}, + {} +}; + +//MODULE_DEVICE_TABLE(i2c, device_i2c_ids); + +static struct i2c_driver device_i2c_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = DEVICE_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = device_i2c_ids, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), + .shutdown = device_i2c_shutdown, +#ifndef CONFIG_ANDROID_POWER + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, +#endif + +}; + +static int device_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + //struct i2c_client *client = (struct i2c_client*)filp->private_data; + //struct dmt_data *dmt = (struct dmt_data*)i2c_get_clientdata(client); + + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + /* check type */ + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + + /* check user space pointer is valid */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) + { + case SENSOR_RESET: + gsensor_reset(s_dmt->client); + return ret; + + case SENSOR_CALIBRATION: + /* get orientation info */ + //if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) return -EFAULT; + gsensor_calibrate(); + GSE_LOG("Sensor_calibration:%d %d %d\n",offset.u.x,offset.u.y,offset.u.z); + /* save file */ + gsensor_write_offset_to_file(); + + /* return the offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + /* get data from file */ + gsensor_read_offset_from_file(); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + gsensor_set_offset(intBuf); + /* write in to file */ + gsensor_write_offset_to_file(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + device_i2c_read_xyz(s_dmt->client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) { + GSE_LOG("%s:copy_from_user(&intBuf, (int*)arg, sizeof(intBuf)) ERROR, -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(s_dmt->input, ABS_X, intBuf[0]); + input_report_abs(s_dmt->input, ABS_Y, -intBuf[1]); + input_report_abs(s_dmt->input, ABS_Z, -intBuf[2]); + input_sync(s_dmt->input); + GSE_LOG(KERN_INFO "%s:SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",__func__,intBuf[0],intBuf[1],intBuf[2]); + return 1; + + case SENSOR_GET_OPEN_STATUS: + GSE_LOG(KERN_INFO "%s:Going into DMT_GetOpenStatus()\n",__func__); + DMT_GetOpenStatus(s_dmt->client); + GSE_LOG(KERN_INFO "%s:DMT_GetOpenStatus() finished\n",__func__); + return 1; + break; + + case SENSOR_GET_CLOSE_STATUS: + GSE_LOG(KERN_INFO "%s:Going into DMT_GetCloseStatus()\n",__func__); + DMT_GetCloseStatus(s_dmt->client); + GSE_LOG(KERN_INFO "%s:DMT_GetCloseStatus() finished\n",__func__); + return 1; + break; + + case SENSOR_GET_DELAY: + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return 1; + break; + + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp) +{ + return 0; +} + +/***** I2C I/O function ***********************************************/ +static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length) +{ + struct i2c_msg msgs[] = + { + {.addr = client->addr, .flags = 0, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = rxData,}, + }; + //unsigned char addr = rxData[0]; + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "RxData: len=%02x, addr=%02x, data=%02x\n", + //length, addr, rxData[0]); + + return 0; +} + +static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length) +{ + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = length, .buf = txData,}, + }; + + if (i2c_transfer(client->adapter, msg, 1) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "TxData: len=%02x, addr=%02x data=%02x\n", + //length, txData[0], txData[1]); + return 0; +} +/* 1g = 128 becomes 1g = 1024 */ +static inline void device_i2c_correct_accel_sign(s16 *val){ + *val<<= 3; +} + +void device_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb){ + *val = (((u16)msb) << 8) | (u16)lsb; + device_i2c_correct_accel_sign(val); +} + +void device_i2c_read_xyz(struct i2c_client *client, s16 *xyz_p){ + u8 buffer[11]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int i, j; + /* get xyz high/low bytes, 0x12 */ + buffer[0] = REG_STADR; + device_i2c_rxdata(client, buffer, 10); + + /* merge to 10-bits value */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + device_i2c_merge_register_values(client, (xyzTmp + i), buffer[2*(i+1)+1], buffer[2*(i+1)]); + /* transfer to the default layout */ + for(j = 0; j < 3; j++) + xyz_p[i] += sensorlayout[i][j] * xyzTmp[j]; + } + GSE_LOG("xyz_p: %04d , %04d , %04d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +} + +static void DMT_work_func(struct work_struct *delaywork) +{ + struct dmt_data *dmt = container_of(delaywork, struct dmt_data, delaywork.work); + int i; + static int firsttime=0; + s16 xyz[SENSOR_DATA_SIZE]; + + unsigned long t=atomic_read(&dmt->delay); + unsigned long dmt_delay = msecs_to_jiffies(t); + if(!firsttime){ + //gsensor_read_offset_from_file(); + firsttime=1; + } + + GSE_LOG("t=%lu , dmt_delay=%lu\n", t, dmt_delay); + device_i2c_read_xyz(dmt->client, (s16 *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz[i] -= offset.v[i]; + + GSE_LOG("@DMTRaw@ X/Y/Z axis: %04d , %04d , %04d\n", xyz[0], xyz[1], xyz[2]); + GSE_LOG("@Offset@ X/Y/Z axis: %04d , %04d , %04d\n", offset.u.x, offset.u.y, offset.u.z); + input_report_abs(dmt->input, ABS_X, xyz[gs_conf.xyz_axis[ABS_X][0]]*gs_conf.xyz_axis[ABS_X][1]); + input_report_abs(dmt->input, ABS_Y, xyz[gs_conf.xyz_axis[ABS_Y][0]]*gs_conf.xyz_axis[ABS_Y][1]); + input_report_abs(dmt->input, ABS_Z, xyz[gs_conf.xyz_axis[ABS_Z][0]]*gs_conf.xyz_axis[ABS_Z][1]); + input_sync(dmt->input); + + if(dmt_delay < 1) + dmt_delay = 1; + schedule_delayed_work(&dmt->delaywork, dmt_delay); +} + +static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id){ + int i, ret = 0; + //struct dmt_data *s_dmt; + + GSE_FUN(); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = 0; + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){ + GSE_ERR("check_functionality failed.\n"); + ret = -ENODEV; + goto exit0; + } + + /* Allocate memory for driver data */ + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + ret = -ENOMEM; + goto exit1; + } + + /***** I2C initialization *****/ + s_dmt->client = client; + /* set client data */ + i2c_set_clientdata(client, s_dmt); + ret = gsensor_reset(client); + if (ret < 0) + goto exit2; + + /***** input *****/ + ret = input_init(client); + if (ret){ + GSE_ERR("input_init fail, error code= %d\n",ret); + goto exit3; + } + + /**** initialize variables in dmt_data *****/ + init_waitqueue_head(&s_dmt->open_wq); + atomic_set(&s_dmt->active, 0); + atomic_set(&s_dmt->enable, 0); + atomic_set(&s_dmt->delay, 0); + mutex_init(&s_dmt->sensor_mutex); + /***** misc *****/ + /* we have been register miscdevice in device_init, and + * marked by Eason 2013/2/4*/ + /*ret = misc_register(&dmt_device); + if (ret){ + GSE_ERR("dmt_dev register failed"); + goto exit5; + }*/ + + /***** sysfs *****/ + ret = create_sysfs_interfaces(s_dmt); + if (ret < 0){ + GSE_ERR("create sysfs failed."); + goto exit6; + } + + INIT_DELAYED_WORK(&s_dmt->delaywork, DMT_work_func); + GSE_LOG("DMT: INIT_DELAYED_WORK\n"); + return 0; + +exit6: + //misc_deregister(&dmt_device); +exit5: + input_unregister_device(s_dmt->input); +exit3: + kfree(s_dmt); +exit2: +exit1: +exit0: + return ret; +} + +int dmt10_enable(int en) +{ + printk(KERN_DEBUG "%s: enable = %d\n", __func__, en); + DMT_sysfs_update_active_status(s_dmt,en); + return 0; +} + +int dmt10_setDelay(int mdelay) +{ + printk(KERN_DEBUG "%s: delay = %d\n", __func__, mdelay); + atomic_set(&s_dmt->delay, mdelay); + return 0; +} + +int dmt10_getLSG(int *lsg) +{ + *lsg = 1024; + return 0; +} + +struct gsensor_data dmt10_gs_data = { + .i2c_addr = DMT10_I2C_ADDR, + .enable = dmt10_enable, + .setDelay = dmt10_setDelay, + .getLSG = dmt10_getLSG, +}; + +static int __init device_init(void){ + int ret = 0; + + if (get_gsensor_conf(&gs_conf)) + return -1; + + if (gs_conf.op != 3) + return -1; + printk("G-Sensor dmt10 init\n"); + + if (gsensor_register(&dmt10_gs_data)) + return -1; + + if (gsensor_i2c_register_device() < 0) + return -1; + + return i2c_add_driver(&device_i2c_driver); +} + +static void __exit device_exit(void){ + i2c_del_driver(&device_i2c_driver); +} + +void gsensor_write_offset_to_file(void){ + char data[18]; + unsigned int orgfs; + struct file *fp; + + sprintf(data,"%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + fp = filp_open(OffsetFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("filp_open %s error!!.\n",OffsetFileName); + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",OffsetFileName); + fp->f_op->write(fp,data,18, &fp->f_pos); + filp_close(fp,NULL); + } + set_fs(orgfs); +} + +void gsensor_read_offset_from_file(void){ + unsigned int orgfs; + char data[18]; + struct file *fp; + int ux,uy,uz; + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + + fp = filp_open(OffsetFileName, O_RDWR , 0); + GSE_FUN(); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + offset.u.x=0;offset.u.y=0;offset.u.z=0; +#if AUTO_CALIBRATION + /* get acceleration average reading */ + gsensor_calibrate(); + gsensor_write_offset_to_file(); +#endif + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",OffsetFileName); + fp->f_op->read(fp,data,18, &fp->f_pos); + GSE_LOG("filp_read result %s\n",data); + sscanf(data,"%d %d %d",&ux,&uy,&uz); + offset.u.x=ux; + offset.u.y=uy; + offset.u.z=uz; + filp_close(fp,NULL); + } + set_fs(orgfs); +} +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h new file mode 100755 index 00000000..61343657 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/dmt10_gsensor/dmt10.h @@ -0,0 +1,187 @@ +/* + * @file include/linux/dmt10.h + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.02 + * @date 2012/12/10 + * + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * @DMT Package version D10_General_driver v1.4 + * + * + */ +#ifndef DMT10_H +#define DMT10_H +#include <linux/types.h> +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/syscalls.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/delay.h> + +#define AUTO_CALIBRATION 0 + +#define DMT_DEBUG_DATA 0 +#define GSE_TAG "[DMT_Gsensor]" +#if DMT_DEBUG_DATA +#define GSE_ERR(fmt, args...) printk(KERN_ERR GSE_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define GSE_LOG(fmt, args...) printk(KERN_INFO GSE_TAG fmt, ##args) +#define GSE_FUN(f) printk(KERN_INFO GSE_TAG" %s: %s: %i\n", __FILE__, __func__, __LINE__) +#define DMT_DATA(dev, ...) dev_dbg((dev), ##__VA_ARGS__) +#else +#define GSE_ERR(fmt, args...) +#define GSE_LOG(fmt, args...) +#define GSE_FUN(f) +#define DMT_DATA(dev, format, ...) +#endif + +#define DMT10_I2C_ADDR 0x18 + + +#define INPUT_NAME_ACC "g-sensor" /* Input Device Name */ +#define DEVICE_I2C_NAME "g-sensor" /* Device name for DMARD10 misc. device */ +#define REG_ACTR 0x00 +#define REG_WDAL 0x01 +#define REG_TAPNS 0x0f +#define REG_MISC2 0x1f +#define REG_AFEM 0x0c +#define REG_CKSEL 0x0d +#define REG_INTC 0x0e +#define REG_STADR 0x12 +#define REG_STAINT 0x1C +#define REG_PD 0x21 +#define REG_TCGYZ 0x26 +#define REG_X_OUT 0x41 + +#define MODE_Off 0x00 +#define MODE_ResetAtOff 0x01 +#define MODE_Standby 0x02 +#define MODE_ResetAtStandby 0x03 +#define MODE_Active 0x06 +#define MODE_Trigger 0x0a +#define MODE_ReadOTP 0x12 +#define MODE_WriteOTP 0x22 +#define MODE_WriteOTPBuf 0x42 +#define MODE_ResetDataPath 0x82 + +#define VALUE_STADR 0x55 +#define VALUE_STAINT 0xAA +#define VALUE_AFEM_AFEN_Normal 0x8f// AFEN set 1 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_AFEM_Normal 0x0f// AFEN set 0 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_INTC 0x00// INTC[6:5]=b'00 +#define VALUE_INTC_Interrupt_En 0x20// INTC[6:5]=b'01 (Data ready interrupt enable, active high at INT0) +#define VALUE_CKSEL_ODR_0_204 0x04// ODR[3:0]=b'0000 (0.78125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_1_204 0x14// ODR[3:0]=b'0001 (1.5625Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_3_204 0x24// ODR[3:0]=b'0010 (3.125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_6_204 0x34// ODR[3:0]=b'0011 (6.25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_12_204 0x44// ODR[3:0]=b'0100 (12.5Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_25_204 0x54// ODR[3:0]=b'0101 (25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_50_204 0x64// ODR[3:0]=b'0110 (50Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_100_204 0x74// ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) + +#define VALUE_TAPNS_NoFilter 0x00 // TAP1/TAP2 NO FILTER +#define VALUE_TAPNS_Ave_2 0x11 // TAP1/TAP2 Average 2 +#define VALUE_TAPNS_Ave_4 0x22 // TAP1/TAP2 Average 4 +#define VALUE_TAPNS_Ave_8 0x33 // TAP1/TAP2 Average 8 +#define VALUE_TAPNS_Ave_16 0x44 // TAP1/TAP2 Average 16 +#define VALUE_TAPNS_Ave_32 0x55 // TAP1/TAP2 Average 32 +#define VALUE_MISC2_OSCA_EN 0x08 +#define VALUE_PD_RST 0x52 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 +#define SENSOR_DATA_SIZE 3 +#define DEFAULT_SENSITIVITY 1024 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) +#define SENSOR_MAXNR 8 + +/* g-senor layout configuration, choose one of the following configuration */ +#define CONFIG_GSEN_LAYOUT_PAT_1 1 +#define CONFIG_GSEN_LAYOUT_PAT_2 0 +#define CONFIG_GSEN_LAYOUT_PAT_3 0 +#define CONFIG_GSEN_LAYOUT_PAT_4 0 +#define CONFIG_GSEN_LAYOUT_PAT_5 0 +#define CONFIG_GSEN_LAYOUT_PAT_6 0 +#define CONFIG_GSEN_LAYOUT_PAT_7 0 +#define CONFIG_GSEN_LAYOUT_PAT_8 0 + +s16 sensorlayout[3][3] = { +#if CONFIG_GSEN_LAYOUT_PAT_1 + { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_2 + { 0, 1, 0}, {-1, 0, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_3 + {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_4 + { 0,-1, 0}, { 1, 0, 0}, { 0, 0, 1}, +#elif CONFIG_GSEN_LAYOUT_PAT_5 + {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, +#elif CONFIG_GSEN_LAYOUT_PAT_6 + { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, +#elif CONFIG_GSEN_LAYOUT_PAT_7 + { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, +#elif CONFIG_GSEN_LAYOUT_PAT_8 + { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, +#endif +}; + +typedef union { + struct { + s16 x; + s16 y; + s16 z; + } u; + s16 v[SENSOR_DATA_SIZE]; +} raw_data; + +struct dmt_data { + dev_t devno; + struct cdev cdev; + struct device *class_dev; + struct class *class; + struct input_dev *input; + struct i2c_client *client; + struct delayed_work delaywork; + struct work_struct work; + struct mutex sensor_mutex; + wait_queue_head_t open_wq; + atomic_t active; + atomic_t delay; + atomic_t enable; +}; + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define DMT_NUM_SENSORS 3 +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c new file mode 100755 index 00000000..bd0b16af --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.c @@ -0,0 +1,180 @@ +/*++ +Copyright (c) 2012 WonderMedia Technologies, Inc. All Rights Reserved. +This PROPRIETARY SOFTWARE is the property of WonderMedia Technologies, Inc. +and may contain trade secrets and/or other confidential information of +WonderMedia Technologies, Inc. This file shall not be disclosed to any +third party, in whole or in part, without prior written consent of +WonderMedia. + +THIS PROPRIETARY SOFTWARE AND ANY RELATED DOCUMENTATION ARE PROVIDED +AS IS, WITH ALL FAULTS, AND WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS +OR IMPLIED, AND WonderMedia TECHNOLOGIES, INC. DISCLAIMS ALL EXPRESS +OR IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +QUIET ENJOYMENT OR NON-INFRINGEMENT. +--*/ + +#include <linux/i2c.h> +#include <linux/input.h> +#include <asm/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include "gsensor.h" + +#define GSENSOR_I2C_NAME "g-sensor" + +#ifdef CONFIG_WMT_SENSOR_DMT08 +#define GSENSOR_I2C_ADDR 0x1c +#elif defined CONFIG_WMT_SENSOR_KXTI9 +#define GSENSOR_I2C_ADDR 0x0f +#endif + +struct gsensor_data *gs_data; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +struct i2c_board_info gsensor_i2c_board_info = { + .type = GSENSOR_I2C_NAME, + .flags = 0x00, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +int gsensor_i2c_register_device (void) +{ + struct i2c_board_info *gsensor_i2c_bi; + struct i2c_adapter *adapter = NULL; + struct i2c_client *client = NULL; + gsensor_i2c_bi = &gsensor_i2c_board_info; + adapter = i2c_get_adapter(0);/*in bus 0*/ + + if (NULL == adapter) { + printk("can not get i2c adapter, client address error\n"); + return -1; + } + gsensor_i2c_bi->addr = gs_data->i2c_addr; + client = i2c_new_device(adapter, gsensor_i2c_bi); + if (client == NULL) { + printk("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +/* + * Get the configure of sensor from u-boot. + * Return: 0--success, other--error. + */ +int get_gsensor_conf(struct gsensor_conf *gs_conf) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.gsensor", varbuf, &varlen)) { + printk("wmt.io.gsensor not defined!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d", + &gs_conf->op, + &gs_conf->samp, + &(gs_conf->xyz_axis[0][0]), + &(gs_conf->xyz_axis[0][1]), + &(gs_conf->xyz_axis[1][0]), + &(gs_conf->xyz_axis[1][1]), + &(gs_conf->xyz_axis[2][0]), + &(gs_conf->xyz_axis[2][1])); + printk(KERN_INFO "wmt.io.gsensor = %d:%d:%d:%d:%d:%d:%d:%d\n", + gs_conf->op, + gs_conf->samp, + gs_conf->xyz_axis[0][0], + gs_conf->xyz_axis[0][1], + gs_conf->xyz_axis[1][0], + gs_conf->xyz_axis[1][1], + gs_conf->xyz_axis[2][0], + gs_conf->xyz_axis[2][1]); + if (n != 8) { + printk("wmt.io.gsensor format is incorrect!\n"); + return -1; + } + + if (gs_conf->op <= 0) { + printk(KERN_INFO "wmt.io.gsensor is disabled\n"); + return -1; + } + } + return 0; +} + +static long gsensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int flag; + + if (!gs_data) + return -1; + + switch (cmd) { + case WMT_IOCTL_APP_SET_AFLAG: + if (copy_from_user(&flag, argp, sizeof(flag))) + return -EFAULT; + else { + if (flag < 0 || flag > 1) + return -EINVAL; + gs_data->enable(flag); + } + break; + case WMT_IOCTL_APP_GET_AFLAG: + if (copy_to_user(argp, &flag, sizeof(flag))) + return -EFAULT; + break; + case WMT_IOCTL_APP_SET_DELAY: + if (copy_from_user(&flag, argp, sizeof(flag))) + return -EFAULT; + else + gs_data->setDelay(flag); + + break; + case WMT_IOCTL_APP_GET_DELAY: + if (copy_to_user(argp, &flag, sizeof(flag))) + return -EFAULT; + break; + case WMT_IOCTL_APP_GET_LSG: + gs_data->getLSG(&flag); + if (copy_to_user(argp, &flag, sizeof(flag))) + return -EFAULT; + break; + default: + return -ENOTTY; + } + return 0; +} + +struct file_operations gsensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = gsensor_ioctl, +}; + +struct miscdevice gsensor_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "g-sensor", + .fops = &gsensor_fops, +}; + +int gsensor_register(struct gsensor_data *data) +{ + int err=-1; + + gs_data = data; + err = misc_register(&gsensor_device); + if (err) + printk(KERN_ERR "%s: gsensor misc register failed\n", __func__); + return err; +} + +EXPORT_SYMBOL_GPL(gsensor_i2c_register_device); +EXPORT_SYMBOL_GPL(get_gsensor_conf); +EXPORT_SYMBOL_GPL(gsensor_register); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h new file mode 100755 index 00000000..db644d77 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/gsensor.h @@ -0,0 +1,43 @@ +/*++ +Copyright (c) 2012 WonderMedia Technologies, Inc. All Rights Reserved. +This PROPRIETARY SOFTWARE is the property of WonderMedia Technologies, Inc. +and may contain trade secrets and/or other confidential information of +WonderMedia Technologies, Inc. This file shall not be disclosed to any +third party, in whole or in part, without prior written consent of +WonderMedia. + +THIS PROPRIETARY SOFTWARE AND ANY RELATED DOCUMENTATION ARE PROVIDED +AS IS, WITH ALL FAULTS, AND WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS +OR IMPLIED, AND WonderMedia TECHNOLOGIES, INC. DISCLAIMS ALL EXPRESS +OR IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +QUIET ENJOYMENT OR NON-INFRINGEMENT. +--*/ + +#ifndef __GSENSOR_H__ +#define __GSENSOR_H__ + +#define IOCTL_WMT 0x01 +#define WMT_IOCTL_APP_SET_AFLAG _IOW(IOCTL_WMT, 0x01, int) +#define WMT_IOCTL_APP_SET_DELAY _IOW(IOCTL_WMT, 0x02, int) +#define WMT_IOCTL_APP_GET_AFLAG _IOW(IOCTL_WMT, 0x03, int) +#define WMT_IOCTL_APP_GET_DELAY _IOW(IOCTL_WMT, 0x04, int) +#define WMT_IOCTL_APP_GET_LSG _IOW(IOCTL_WMT, 0x05, int) + +struct gsensor_conf { + int op; + int samp; + int xyz_axis[3][2]; +}; + +struct gsensor_data { + int i2c_addr; + int (*enable) (int en); + int (*setDelay) (int mdelay); + int (*getLSG) (int *lsg); +}; + +extern int gsensor_i2c_register_device (void); +extern int get_gsensor_conf(struct gsensor_conf *gs_conf); +extern int gsensor_register(struct gsensor_data *gs_data); + +#endif
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile new file mode 100755 index 00000000..3df5b74c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the KXTI9 Sensor driver +# + +sensor_kxti9-objs := kxti9.o +obj-$(CONFIG_WMT_SENSOR_KXTI9) += sensor_kxti9.o diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c new file mode 100755 index 00000000..c385842e --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.c @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 2009 Kionix, Inc. + * Written by Chris Hudson <chudson@kionix.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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/err.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/uaccess.h> +#include <linux/workqueue.h> +#ifdef KXTI9_INT_MODE +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#endif +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include "kxti9.h" +#include "../gsensor.h" + +#define NAME "g-sensor" +#define G_MAX 2048 //8000 +/* OUTPUT REGISTERS */ +#define XOUT_L 0x06 +#define INT_SRC_REG1 0x15 +#define INT_STATUS_REG 0x16 +#define TILT_POS_CUR 0x10 +#define INT_REL 0x1A +#define WHO_AM_I 0x0F +/* CONTROL REGISTERS */ +#define DATA_CTRL 0x21 +#define CTRL_REG1 0x1B +#define INT_CTRL1 0x1E +#define CTRL_REG3 0x1D +#define TILT_TIMER 0x28 +#define WUF_TIMER 0x29 +#define WUF_THRESH 0x5A +#define TDT_TIMER 0x2B +/* CONTROL REGISTER 1 BITS */ +#define PC1_OFF 0x00 +#define PC1_ON 0x80 +/* INTERRUPT SOURCE 2 BITS */ +#define TPS 0x01 +#define TDTS0 0x04 +#define TDTS1 0x08 +/* INPUT_ABS CONSTANTS */ +#define FUZZ 0 //32 +#define FLAT 0 //32 +/* RESUME STATE INDICES */ +#define RES_DATA_CTRL 0 +#define RES_CTRL_REG1 1 +#define RES_INT_CTRL1 2 +#define RES_TILT_TIMER 3 +#define RES_CTRL_REG3 4 +#define RES_WUF_TIMER 5 +#define RES_WUF_THRESH 6 +#define RES_TDT_TIMER 7 +#define RES_TDT_H_THRESH 8 +#define RES_TDT_L_THRESH 9 +#define RES_TAP_TIMER 10 +#define RES_TOTAL_TIMER 11 +#define RES_LAT_TIMER 12 +#define RES_WIN_TIMER 13 +#define RESUME_ENTRIES 14 + +static struct gsensor_conf gs_conf; +static struct kxti9_data *gs_ti9; + +extern int gsensor_i2c_register_device (void); + +struct kxti9_platform_data kxti9_pdata = { + .min_interval = 1, + .poll_interval = 200,//1000, + + .g_range = KXTI9_G_2G, + .shift_adj = SHIFT_ADJ_2G, + + .axis_map_x = 0, + .axis_map_y = 1, + .axis_map_z = 2, + + .negate_x = 0, + .negate_y = 0, + .negate_z = 0, + + .data_odr_init = ODR12_5F, +#ifdef KXTI9_INT_MODE + .ctrl_reg1_init = KXTI9_G_8G | RES_12BIT | TDTE | WUFE | TPE, + .int_ctrl_init = KXTI9_IEN | KXTI9_IEA | KXTI9_IEL, +#else + .ctrl_reg1_init = KXTI9_G_2G | RES_12BIT, + .int_ctrl_init = 0, +#endif + .tilt_timer_init = 0x03, + .engine_odr_init = OTP12_5 | OWUF50 | OTDT400, + .wuf_timer_init = 0x16, + .wuf_thresh_init = 0x28, + .tdt_timer_init = 0x78, + .tdt_h_thresh_init = 0xFF, + .tdt_l_thresh_init = 0x14, + .tdt_tap_timer_init = 0x53, + .tdt_total_timer_init = 0x24, + .tdt_latency_timer_init = 0x10, + .tdt_window_timer_init = 0xA0, +}; + +/* + * The following table lists the maximum appropriate poll interval for each + * available output data rate. + */ +struct { + unsigned int cutoff; + u8 mask; +} kxti9_odr_table[] = { + { + 3, ODR800F}, { + 5, ODR400F}, { + 10, ODR200F}, { + 20, ODR100F}, { + 40, ODR50F}, { + 80, ODR25F}, { + 0, ODR12_5F}, +}; + +struct kxti9_data { + struct i2c_client *client; + struct kxti9_platform_data *pdata; + struct mutex lock; + struct delayed_work input_work; + struct input_dev *input_dev; +#ifdef KXTI9_INT_MODE + struct work_struct irq_work; +#endif + + int hw_initialized; + atomic_t enabled; + u8 resume[RESUME_ENTRIES]; + int res_interval; +#ifdef KXTI9_INT_MODE + int irq; +#endif +}; + +static int kxti9_i2c_read(struct kxti9_data *ti9, u8 addr, u8 *data, int len) +{ + int err; + + struct i2c_msg msgs[] = { + { + .addr = ti9->client->addr, + .flags = ti9->client->flags & I2C_M_TEN, + .len = 1, + .buf = &addr, + }, + { + .addr = ti9->client->addr, + .flags = (ti9->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = data, + }, + }; + err = i2c_transfer(ti9->client->adapter, msgs, 2); + + if (err != 2) + dev_err(&ti9->client->dev, "read transfer error\n"); + else + err = 0; + + return err; +} + +static int kxti9_i2c_write(struct kxti9_data *ti9, u8 addr, u8 *data, int len) +{ + int err; + int i; + u8 buf[len + 1]; + + struct i2c_msg msgs[] = { + { + .addr = ti9->client->addr, + .flags = ti9->client->flags & I2C_M_TEN, + .len = len + 1, + .buf = buf, + }, + }; + + buf[0] = addr; + for (i = 0; i < len; i++) { + buf[i + 1] = data[i]; + } + + err = i2c_transfer(ti9->client->adapter, msgs, 1); + + if (err != 1) + dev_err(&ti9->client->dev, "write transfer error\n"); + else + err = 0; + + return err; +} + +static int kxti9_verify(struct kxti9_data *ti9) +{ + int err; + u8 buf; + + err = kxti9_i2c_read(ti9, WHO_AM_I, &buf, 1); + /*** DEBUG OUTPUT - REMOVE ***/ + dev_info(&ti9->client->dev, "WHO_AM_I = 0x%02x\n", buf); + /*** <end> DEBUG OUTPUT - REMOVE ***/ + if (err < 0) + dev_err(&ti9->client->dev, "read err int source\n"); + if (buf != 0x04 && buf != 0x08) // jakie add 0x8 for kxtj9 + err = -1; + return err; +} + +int kxti9_update_g_range(struct kxti9_data *ti9, u8 new_g_range) +{ + int err; + u8 shift; + u8 buf; + + switch (new_g_range) { + case KXTI9_G_2G: + shift = SHIFT_ADJ_2G; + break; + case KXTI9_G_4G: + shift = SHIFT_ADJ_4G; + break; + case KXTI9_G_8G: + shift = SHIFT_ADJ_8G; + break; + default: + dev_err(&ti9->client->dev, "invalid g range request\n"); + return -EINVAL; + } + if (shift != ti9->pdata->shift_adj) { + if (ti9->pdata->shift_adj > shift) + ti9->resume[RES_WUF_THRESH] >>= + (ti9->pdata->shift_adj - shift); + if (ti9->pdata->shift_adj < shift) + ti9->resume[RES_WUF_THRESH] <<= + (shift - ti9->pdata->shift_adj); + + if (atomic_read(&ti9->enabled)) { + buf = PC1_OFF; + err = kxti9_i2c_write(ti9, CTRL_REG1, &buf, 1); + if (err < 0) + return err; + buf = ti9->resume[RES_WUF_THRESH]; + err = kxti9_i2c_write(ti9, WUF_THRESH, &buf, 1); + if (err < 0) + return err; + buf = (ti9->resume[RES_CTRL_REG1] & 0xE7) | new_g_range; + err = kxti9_i2c_write(ti9, CTRL_REG1, &buf, 1); + if (err < 0) + return err; + ti9->resume[RES_CTRL_REG1] = buf; + ti9->pdata->shift_adj = shift; + } + } + return 0; +} + +int kxti9_update_odr(struct kxti9_data *ti9, int poll_interval) +{ + int err = -1; + int i; + u8 config; + + /* Convert the poll interval into an output data rate configuration + * that is as low as possible. The ordering of these checks must be + * maintained due to the cascading cut off values - poll intervals are + * checked from shortest to longest. At each check, if the next slower + * ODR cannot support the current poll interval, we stop searching */ + for (i = 0; i < ARRAY_SIZE(kxti9_odr_table); i++) { + config = kxti9_odr_table[i].mask; + if (poll_interval < kxti9_odr_table[i].cutoff) + break; + } + + if (atomic_read(&ti9->enabled)) { + err = kxti9_i2c_write(ti9, DATA_CTRL, &config, 1); + if (err < 0) + return err; + /* + * Latch on input_dev - indicates that kxti9_input_init passed + * and this workqueue is available + */ + if (ti9->input_dev) { + cancel_delayed_work_sync(&ti9->input_work); + schedule_delayed_work(&ti9->input_work, + msecs_to_jiffies(poll_interval)); + } + } + ti9->resume[RES_DATA_CTRL] = config; + + return 0; +} + +static int kxti9_hw_init(struct kxti9_data *ti9) +{ + int err = -1; + u8 buf[7]; + + buf[0] = PC1_OFF; + err = kxti9_i2c_write(ti9, CTRL_REG1, buf, 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, DATA_CTRL, &ti9->resume[RES_DATA_CTRL], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, CTRL_REG3, &ti9->resume[RES_CTRL_REG3], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, TILT_TIMER, &ti9->resume[RES_TILT_TIMER], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, WUF_TIMER, &ti9->resume[RES_WUF_TIMER], 1); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, WUF_THRESH, &ti9->resume[RES_WUF_THRESH], 1); + if (err < 0) + return err; + buf[0] = ti9->resume[RES_TDT_TIMER]; + buf[1] = ti9->resume[RES_TDT_H_THRESH]; + buf[2] = ti9->resume[RES_TDT_L_THRESH]; + buf[3] = ti9->resume[RES_TAP_TIMER]; + buf[4] = ti9->resume[RES_TOTAL_TIMER]; + buf[5] = ti9->resume[RES_LAT_TIMER]; + buf[6] = ti9->resume[RES_WIN_TIMER]; + err = kxti9_i2c_write(ti9, TDT_TIMER, buf, 7); + if (err < 0) + return err; + err = kxti9_i2c_write(ti9, INT_CTRL1, &ti9->resume[RES_INT_CTRL1], 1); + if (err < 0) + return err; + buf[0] = (ti9->resume[RES_CTRL_REG1] | PC1_ON); + err = kxti9_i2c_write(ti9, CTRL_REG1, buf, 1); + if (err < 0) + return err; + ti9->resume[RES_CTRL_REG1] = buf[0]; + ti9->hw_initialized = 1; + + return 0; +} + +static void kxti9_device_power_off(struct kxti9_data *ti9) +{ + int err; + u8 buf = PC1_OFF; + + err = kxti9_i2c_write(ti9, CTRL_REG1, &buf, 1); + if (err < 0) + dev_err(&ti9->client->dev, "soft power off failed\n"); +#ifdef KXTI9_INT_MODE + disable_irq(ti9->irq); +#endif + if (ti9->pdata->power_off) + ti9->pdata->power_off(); + ti9->hw_initialized = 0; +} + +static int kxti9_device_power_on(struct kxti9_data *ti9) +{ + int err; + + if (ti9->pdata->power_on) { + err = ti9->pdata->power_on(); + if (err < 0) + return err; + } +#ifdef KXTI9_INT_MODE + enable_irq(ti9->irq); +#endif + if (!ti9->hw_initialized) { + msleep(100); + err = kxti9_hw_init(ti9); + if (err < 0) { + kxti9_device_power_off(ti9); + return err; + } + } + + return 0; +} + +#ifdef KXTI9_INT_MODE +static irqreturn_t kxti9_isr(int irq, void *dev) +{ + struct kxti9_data *ti9 = dev; + + disable_irq_nosync(irq); + schedule_work(&ti9->irq_work); + + return IRQ_HANDLED; +} +#endif + +static u8 kxti9_resolve_dir(struct kxti9_data *ti9, u8 dir) +{ + switch (dir) { + case 0x20: /* -X */ + if (ti9->pdata->negate_x) + dir = 0x10; + if (ti9->pdata->axis_map_y == 0) + dir >>= 2; + if (ti9->pdata->axis_map_z == 0) + dir >>= 4; + break; + case 0x10: /* +X */ + if (ti9->pdata->negate_x) + dir = 0x20; + if (ti9->pdata->axis_map_y == 0) + dir >>= 2; + if (ti9->pdata->axis_map_z == 0) + dir >>= 4; + break; + case 0x08: /* -Y */ + if (ti9->pdata->negate_y) + dir = 0x04; + if (ti9->pdata->axis_map_x == 1) + dir <<= 2; + if (ti9->pdata->axis_map_z == 1) + dir >>= 2; + break; + case 0x04: /* +Y */ + if (ti9->pdata->negate_y) + dir = 0x08; + if (ti9->pdata->axis_map_x == 1) + dir <<= 2; + if (ti9->pdata->axis_map_z == 1) + dir >>= 2; + break; + case 0x02: /* -Z */ + if (ti9->pdata->negate_z) + dir = 0x01; + if (ti9->pdata->axis_map_x == 2) + dir <<= 4; + if (ti9->pdata->axis_map_y == 2) + dir <<= 2; + break; + case 0x01: /* +Z */ + if (ti9->pdata->negate_z) + dir = 0x02; + if (ti9->pdata->axis_map_x == 2) + dir <<= 4; + if (ti9->pdata->axis_map_y == 2) + dir <<= 2; + break; + default: + return -EINVAL; + } + + return dir; +} + +static int kxti9_get_acceleration_data(struct kxti9_data *ti9, int *xyz) +{ + int err; + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + u8 acc_data[6]; + /* x,y,z hardware values */ + int hw_d[3]; + + err = kxti9_i2c_read(ti9, XOUT_L, acc_data, 6); + if (err < 0) + return err; + + hw_d[0] = (int) (((acc_data[1]) << 8) | acc_data[0]); + hw_d[1] = (int) (((acc_data[3]) << 8) | acc_data[2]); + hw_d[2] = (int) (((acc_data[5]) << 8) | acc_data[4]); + + hw_d[0] = (hw_d[0] & 0x8000) ? ((hw_d[0] | 0xFFFF0000) + 1) : (hw_d[0]); + hw_d[1] = (hw_d[1] & 0x8000) ? ((hw_d[1] | 0xFFFF0000) + 1) : (hw_d[1]); + hw_d[2] = (hw_d[2] & 0x8000) ? ((hw_d[2] | 0xFFFF0000) + 1) : (hw_d[2]); + + hw_d[0] >>= 4; + hw_d[1] >>= 4; + hw_d[2] >>= 4; + + xyz[0] = ((ti9->pdata->negate_x) ? (-hw_d[ti9->pdata->axis_map_x]) + : (hw_d[ti9->pdata->axis_map_x])); + xyz[1] = ((ti9->pdata->negate_y) ? (-hw_d[ti9->pdata->axis_map_y]) + : (hw_d[ti9->pdata->axis_map_y])); + xyz[2] = ((ti9->pdata->negate_z) ? (-hw_d[ti9->pdata->axis_map_z]) + : (hw_d[ti9->pdata->axis_map_z])); + + /*** DEBUG OUTPUT - REMOVE ***/ + //dev_info(&ti9->client->dev, "x:%d y:%d z:%d\n", xyz[0], xyz[1], xyz[2]); + /*** <end> DEBUG OUTPUT - REMOVE ***/ + + return err; +} + +static void kxti9_report_values(struct kxti9_data *ti9, int *xyz) +{ + input_report_abs(ti9->input_dev, ABS_X, xyz[gs_conf.xyz_axis[ABS_X][0]]*gs_conf.xyz_axis[ABS_X][1]); + input_report_abs(ti9->input_dev, ABS_Y, xyz[gs_conf.xyz_axis[ABS_Y][0]]*gs_conf.xyz_axis[ABS_Y][1]); + input_report_abs(ti9->input_dev, ABS_Z, xyz[gs_conf.xyz_axis[ABS_Z][0]]*gs_conf.xyz_axis[ABS_Z][1]); + input_sync(ti9->input_dev); +} + +#ifdef KXTI9_INT_MODE +static void kxti9_irq_work_func(struct work_struct *work) +{ +/* + * int_status output: + * [INT_SRC_REG2][INT_SRC_REG1][TILT_POS_PRE][TILT_POS_CUR] + * INT_SRC_REG1, TILT_POS_PRE, and TILT_POS_CUR directions are translated + * based on platform data variables. + */ + + int err; + int int_status = 0; + u8 status; + u8 buf[2]; + + struct kxti9_data *ti9 + = container_of(work, struct kxti9_data, irq_work); + + err = kxti9_i2c_read(ti9, INT_STATUS_REG, &status, 1); + if (err < 0) + dev_err(&ti9->client->dev, "read err int source\n"); + int_status = status << 24; + if ((status & TPS) > 0) { + err = kxti9_i2c_read(ti9, TILT_POS_CUR, buf, 2); + if (err < 0) + dev_err(&ti9->client->dev, "read err tilt dir\n"); + int_status |= kxti9_resolve_dir(ti9, buf[0]); + int_status |= kxti9_resolve_dir(ti9, buf[1]) << 8; + /*** DEBUG OUTPUT - REMOVE ***/ + dev_info(&ti9->client->dev, "IRQ TILT [%x]\n", + kxti9_resolve_dir(ti9, buf[0])); + /*** <end> DEBUG OUTPUT - REMOVE ***/ + } + if (((status & TDTS0) | (status & TDTS1)) > 0) { + err = kxti9_i2c_read(ti9, INT_SRC_REG1, buf, 1); + if (err < 0) + dev_err(&ti9->client->dev, "read err tap dir\n"); + int_status |= (kxti9_resolve_dir(ti9, buf[0])) << 16; + /*** DEBUG OUTPUT - REMOVE ***/ + dev_info(&ti9->client->dev, "IRQ TAP%d [%x]\n", + ((status & TDTS1) ? (2) : (1)), kxti9_resolve_dir(ti9, buf[0])); + /*** <end> DEBUG OUTPUT - REMOVE ***/ + } + /*** DEBUG OUTPUT - REMOVE ***/ + if ((status & 0x02) > 0) { + if (((status & TDTS0) | (status & TDTS1)) > 0) + dev_info(&ti9->client->dev, "IRQ WUF + TAP\n"); + else + dev_info(&ti9->client->dev, "IRQ WUF\n"); + } + /*** <end> DEBUG OUTPUT - REMOVE ***/ + if (int_status & 0x2FFF) { + input_report_abs(ti9->input_dev, ABS_MISC, int_status); + input_sync(ti9->input_dev); + } + err = kxti9_i2c_read(ti9, INT_REL, buf, 1); + if (err < 0) + dev_err(&ti9->client->dev, + "error clearing interrupt status: %d\n", err); + + enable_irq(ti9->irq); +} +#endif + +static int kxti9_enable(struct kxti9_data *ti9) +{ + int err; + int int_status = 0; + u8 buf; + + if (!atomic_cmpxchg(&ti9->enabled, 0, 1)) { + err = kxti9_device_power_on(ti9); + err = kxti9_i2c_read(ti9, INT_REL, &buf, 1); + if (err < 0) { + dev_err(&ti9->client->dev, + "error clearing interrupt: %d\n", err); + atomic_set(&ti9->enabled, 0); + return err; + } + if ((ti9->resume[RES_CTRL_REG1] & TPE) > 0) { + err = kxti9_i2c_read(ti9, TILT_POS_CUR, &buf, 1); + if (err < 0) { + dev_err(&ti9->client->dev, + "read err current tilt\n"); + int_status |= kxti9_resolve_dir(ti9, buf); + input_report_abs(ti9->input_dev, ABS_MISC, int_status); + input_sync(ti9->input_dev); + } + } + schedule_delayed_work(&ti9->input_work, + msecs_to_jiffies(ti9->res_interval)); + } + + return 0; +} + +static int kxti9_disable(struct kxti9_data *ti9) +{ + if (atomic_cmpxchg(&ti9->enabled, 1, 0)) { + cancel_delayed_work_sync(&ti9->input_work); + kxti9_device_power_off(ti9); + } + + return 0; +} + +static void kxti9_input_work_func(struct work_struct *work) +{ + struct kxti9_data *ti9 = container_of((struct delayed_work *)work, + struct kxti9_data, input_work); + int xyz[3] = { 0 }; + + mutex_lock(&ti9->lock); + + if (kxti9_get_acceleration_data(ti9, xyz) == 0) + kxti9_report_values(ti9, xyz); + + schedule_delayed_work(&ti9->input_work, + msecs_to_jiffies(ti9->res_interval)); + + mutex_unlock(&ti9->lock); +} + +int kxti9_input_open(struct input_dev *input) +{ + struct kxti9_data *ti9 = input_get_drvdata(input); + + return kxti9_enable(ti9); +} + +void kxti9_input_close(struct input_dev *dev) +{ + struct kxti9_data *ti9 = input_get_drvdata(dev); + + kxti9_disable(ti9); +} + +static int kxti9_input_init(struct kxti9_data *ti9) +{ + int err; + + INIT_DELAYED_WORK(&ti9->input_work, kxti9_input_work_func); + ti9->input_dev = input_allocate_device(); + if (!ti9->input_dev) { + err = -ENOMEM; + dev_err(&ti9->client->dev, "input device allocate failed\n"); + goto err0; + } + //ti9->input_dev->open = kxti9_input_open; + //ti9->input_dev->close = kxti9_input_close; + + input_set_drvdata(ti9->input_dev, ti9); + + set_bit(EV_ABS, ti9->input_dev->evbit); + set_bit(ABS_MISC, ti9->input_dev->absbit); + + input_set_abs_params(ti9->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(ti9->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(ti9->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + ti9->input_dev->name = "g-sensor"; + + err = input_register_device(ti9->input_dev); + if (err) { + dev_err(&ti9->client->dev, + "unable to register input polled device %s: %d\n", + ti9->input_dev->name, err); + goto err1; + } + + return 0; +err1: + input_free_device(ti9->input_dev); +err0: + return err; +} + +static void kxti9_input_cleanup(struct kxti9_data *ti9) +{ + input_unregister_device(ti9->input_dev); +} + +/* sysfs */ +static ssize_t kxti9_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", ti9->res_interval); +} + +static ssize_t kxti9_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + ti9->res_interval = max(val, ti9->pdata->min_interval); + kxti9_update_odr(ti9, ti9->res_interval); + + return count; +} + +static ssize_t kxti9_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", atomic_read(&ti9->enabled)); +} + +static ssize_t kxti9_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + kxti9_enable(ti9); + else + kxti9_disable(ti9); + return count; +} + +static ssize_t kxti9_tilt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + u8 tilt; + + if (ti9->resume[RES_CTRL_REG1] & TPE) { + kxti9_i2c_read(ti9, TILT_POS_CUR, &tilt, 1); + return sprintf(buf, "%d\n", kxti9_resolve_dir(ti9, tilt)); + } else { + return sprintf(buf, "%d\n", 0); + } +} + +static ssize_t kxti9_tilt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + ti9->resume[RES_CTRL_REG1] |= TPE; + else + ti9->resume[RES_CTRL_REG1] &= (~TPE); + kxti9_i2c_write(ti9, CTRL_REG1, &ti9->resume[RES_CTRL_REG1], 1); + return count; +} + +static ssize_t kxti9_wake_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + u8 val = ti9->resume[RES_CTRL_REG1] & WUFE; + if (val) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t kxti9_wake_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + ti9->resume[RES_CTRL_REG1] |= WUFE; + else + ti9->resume[RES_CTRL_REG1] &= (~WUFE); + kxti9_i2c_write(ti9, CTRL_REG1, &ti9->resume[RES_CTRL_REG1], 1); + return count; +} + +static ssize_t kxti9_tap_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + u8 val = ti9->resume[RES_CTRL_REG1] & TDTE; + if (val) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t kxti9_tap_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + if (val) + ti9->resume[RES_CTRL_REG1] |= TDTE; + else + ti9->resume[RES_CTRL_REG1] &= (~TDTE); + kxti9_i2c_write(ti9, CTRL_REG1, &ti9->resume[RES_CTRL_REG1], 1); + return count; +} + +static ssize_t kxti9_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct kxti9_data *ti9 = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl = 0x00; + if (val) + ctrl = 0xCA; + kxti9_i2c_write(ti9, 0x3A, &ctrl, 1); + return count; +} + +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kxti9_delay_show, kxti9_delay_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kxti9_enable_show, + kxti9_enable_store); +static DEVICE_ATTR(tilt, S_IRUGO|S_IWUSR, kxti9_tilt_show, kxti9_tilt_store); +static DEVICE_ATTR(wake, S_IRUGO|S_IWUSR, kxti9_wake_show, kxti9_wake_store); +static DEVICE_ATTR(tap, S_IRUGO|S_IWUSR, kxti9_tap_show, kxti9_tap_store); +static DEVICE_ATTR(selftest, S_IWUSR, NULL, kxti9_selftest_store); + +static struct attribute *kxti9_attributes[] = { + &dev_attr_delay.attr, + &dev_attr_enable.attr, + &dev_attr_tilt.attr, + &dev_attr_wake.attr, + &dev_attr_tap.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group kxti9_attribute_group = { + .attrs = kxti9_attributes +}; +/* /sysfs */ +static int __devinit kxti9_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = -1; + struct kxti9_data *ti9 = kzalloc(sizeof(*ti9), GFP_KERNEL); + gs_ti9 = ti9; + if (ti9 == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + err = -ENOMEM; + goto err0; + } + /* + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL; exiting\n"); + err = -ENODEV; + goto err0; + } + */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "client not i2c capable\n"); + err = -ENODEV; + goto err0; + } + mutex_init(&ti9->lock); + mutex_lock(&ti9->lock); + ti9->client = client; + i2c_set_clientdata(client, ti9); + +#ifdef KXTI9_INT_MODE + INIT_WORK(&ti9->irq_work, kxti9_irq_work_func); +#endif + ti9->pdata = kmalloc(sizeof(*ti9->pdata), GFP_KERNEL); + if (ti9->pdata == NULL) + goto err1; + + err = sysfs_create_group(&client->dev.kobj, &kxti9_attribute_group); + if (err) + goto err1; + + //memcpy(ti9->pdata, client->dev.platform_data, sizeof(*ti9->pdata)); + memcpy(ti9->pdata, &kxti9_pdata, sizeof(*ti9->pdata)); + + if (ti9->pdata->init) { + err = ti9->pdata->init(); + if (err < 0) + goto err2; + } + +#ifdef KXTI9_INT_MODE + ti9->irq = gpio_to_irq(ti9->pdata->gpio); +#endif + + memset(ti9->resume, 0, ARRAY_SIZE(ti9->resume)); + ti9->resume[RES_DATA_CTRL] = ti9->pdata->data_odr_init; + ti9->resume[RES_CTRL_REG1] = ti9->pdata->ctrl_reg1_init; + ti9->resume[RES_INT_CTRL1] = ti9->pdata->int_ctrl_init; + ti9->resume[RES_TILT_TIMER] = ti9->pdata->tilt_timer_init; + ti9->resume[RES_CTRL_REG3] = ti9->pdata->engine_odr_init; + ti9->resume[RES_WUF_TIMER] = ti9->pdata->wuf_timer_init; + ti9->resume[RES_WUF_THRESH] = ti9->pdata->wuf_thresh_init; + ti9->resume[RES_TDT_TIMER] = ti9->pdata->tdt_timer_init; + ti9->resume[RES_TDT_H_THRESH] = ti9->pdata->tdt_h_thresh_init; + ti9->resume[RES_TDT_L_THRESH] = ti9->pdata->tdt_l_thresh_init; + ti9->resume[RES_TAP_TIMER] = ti9->pdata->tdt_tap_timer_init; + ti9->resume[RES_TOTAL_TIMER] = ti9->pdata->tdt_total_timer_init; + ti9->resume[RES_LAT_TIMER] = ti9->pdata->tdt_latency_timer_init; + ti9->resume[RES_WIN_TIMER] = ti9->pdata->tdt_window_timer_init; + ti9->res_interval = ti9->pdata->poll_interval; + + err = kxti9_device_power_on(ti9); + if (err < 0) + goto err3; + atomic_set(&ti9->enabled, 1); + + err = kxti9_verify(ti9); + if (err < 0) { + dev_err(&client->dev, "unresolved i2c client\n"); + goto err4; + } + + err = kxti9_update_g_range(ti9, ti9->pdata->g_range); + if (err < 0) + goto err4; + + err = kxti9_update_odr(ti9, ti9->res_interval); + if (err < 0) + goto err4; + + err = kxti9_input_init(ti9); + if (err < 0) + goto err4; + + kxti9_device_power_off(ti9); + atomic_set(&ti9->enabled, 0); + +#ifdef KXTI9_INT_MODE + err = request_irq(ti9->irq, kxti9_isr, + IRQF_TRIGGER_RISING | IRQF_DISABLED, "kxti9-irq", ti9); + if (err < 0) { + pr_err("%s: request irq failed: %d\n", __func__, err); + goto err5; + } + disable_irq_nosync(ti9->irq); +#endif + + mutex_unlock(&ti9->lock); + + return 0; + +#ifdef KXTI9_INT_MODE +err5: +#endif + kxti9_input_cleanup(ti9); +err4: + kxti9_device_power_off(ti9); +err3: + if (ti9->pdata->exit) + ti9->pdata->exit(); +err2: + kfree(ti9->pdata); + sysfs_remove_group(&client->dev.kobj, &kxti9_attribute_group); +err1: + mutex_unlock(&ti9->lock); + kfree(ti9); +err0: + return err; +} + +static int __devexit kxti9_remove(struct i2c_client *client) +{ + struct kxti9_data *ti9 = i2c_get_clientdata(client); + +#ifdef KXTI9_INT_MODE + free_irq(ti9->irq, ti9); + gpio_free(ti9->pdata->gpio); +#endif + kxti9_input_cleanup(ti9); + kxti9_device_power_off(ti9); + if (ti9->pdata->exit) + ti9->pdata->exit(); + kfree(ti9->pdata); + sysfs_remove_group(&client->dev.kobj, &kxti9_attribute_group); + kfree(ti9); + + return 0; +} + +#ifdef CONFIG_PM +static int kxti9_resume(struct i2c_client *client) +{ + //struct kxti9_data *ti9 = i2c_get_clientdata(client); + //return kxti9_enable(ti9); + return 0; +} + +static int kxti9_suspend(struct i2c_client *client, pm_message_t mesg) +{ + //struct kxti9_data *ti9 = i2c_get_clientdata(client); + //return kxti9_disable(ti9); + return 0; +} + +static void kxti9_shutdown(struct i2c_client *client) +{ + struct kxti9_data *ti9 = i2c_get_clientdata(client); + if (atomic_read(&ti9->enabled)) { + flush_delayed_work_sync(&ti9->input_work); + cancel_delayed_work_sync(&ti9->input_work); + } +} +#endif + +static const struct i2c_device_id kxti9_id[] = { + {NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, kxti9_id); + +static struct i2c_driver kxti9_driver = { + .driver = { + .name = NAME, + }, + .probe = kxti9_probe, + .remove = __devexit_p(kxti9_remove), + .resume = kxti9_resume, + .suspend = kxti9_suspend, + .shutdown = kxti9_shutdown, + .id_table = kxti9_id, +}; + +int kxti9_enable_accel(int en) +{ + printk(KERN_DEBUG "%s: enable = %d\n", __func__, en); + if (en) + kxti9_enable(gs_ti9); + else + kxti9_disable(gs_ti9); + return 0; +} + +int kxti9_setDelay(int mdelay) +{ + printk(KERN_DEBUG "%s: delay = %d\n", __func__, mdelay); + gs_ti9->res_interval = mdelay; + return kxti9_update_odr(gs_ti9, gs_ti9->res_interval); +} + +int kxti9_getLSG(int *lsg) +{ + int max_count; + if (gs_ti9->resume[RES_CTRL_REG1] & RES_12BIT) + max_count = 2048; + else + max_count = 128; + + if ((gs_ti9->resume[RES_CTRL_REG1] & 0x18) == KXTI9_G_2G) + *lsg = max_count >> 1; + else if ((gs_ti9->resume[RES_CTRL_REG1] & 0x18) == KXTI9_G_4G) + *lsg = max_count >> 2; + else if ((gs_ti9->resume[RES_CTRL_REG1] & 0x18) == KXTI9_G_8G) + *lsg = max_count >> 3; + + printk(KERN_DEBUG "%s: LSG = %d\n", __func__, *lsg); + return 0; +} + +struct gsensor_data kxti9_gs_data = { + .i2c_addr = KXTI9_I2C_ADDR, + .enable = kxti9_enable_accel, + .setDelay = kxti9_setDelay, + .getLSG = kxti9_getLSG, +}; + +static int __init kxti9_init(void) +{ + if (get_gsensor_conf(&gs_conf)) + return -1; + + if (gs_conf.op != 2) + return -1; + + printk("G-Sensor kxti9 init\n"); + + if (gsensor_register(&kxti9_gs_data)) + return -1; + + if (gsensor_i2c_register_device() < 0) + return -1; + + return i2c_add_driver(&kxti9_driver); +} + +static void __exit kxti9_exit(void) +{ + i2c_del_driver(&kxti9_driver); +} + +module_init(kxti9_init); +module_exit(kxti9_exit); + +MODULE_DESCRIPTION("KXTI9 accelerometer driver"); +MODULE_AUTHOR("Chris Hudson <chudson@kionix.com>"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h new file mode 100755 index 00000000..c66c740a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/TP_DRIVER_NOT_USE/kxti9_gsensor/kxti9.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2009, Kionix, Inc. All Rights Reserved. + * Written by Chris Hudson <chudson@kionix.com> + * + * 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 3 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 __KXTI9_H__ +#define __KXTI9_H__ + +#define KXTI9_I2C_ADDR 0x0F +/* CONTROL REGISTER 1 BITS */ +#define RES_12BIT 0x40 +#define KXTI9_G_2G 0x00 +#define KXTI9_G_4G 0x08 +#define KXTI9_G_8G 0x10 +#define SHIFT_ADJ_2G 4 +#define SHIFT_ADJ_4G 3 +#define SHIFT_ADJ_8G 2 +#define TPE 0x01 /* tilt position function enable bit */ +#define WUFE 0x02 /* wake-up function enable bit */ +#define TDTE 0x04 /* tap/double-tap function enable bit */ +/* CONTROL REGISTER 3 BITS */ +#define OTP1_6 0x00 /* tilt ODR masks */ +#define OTP6_3 0x20 +#define OTP12_5 0x40 +#define OTP50 0x60 +#define OWUF25 0x00 /* wuf ODR masks */ +#define OWUF50 0x01 +#define OWUF100 0x02 +#define OWUF200 0x03 +#define OTDT50 0x00 /* tdt ODR masks */ +#define OTDT100 0x04 +#define OTDT200 0x08 +#define OTDT400 0x0C +/* INTERRUPT CONTROL REGISTER 1 BITS */ +#define KXTI9_IEN 0x20 /* interrupt enable */ +#define KXTI9_IEA 0x10 /* interrupt polarity */ +#define KXTI9_IEL 0x08 /* interrupt response */ +#define IEU 0x04 /* alternate unlatched response */ +/* DATA CONTROL REGISTER BITS */ +#define ODR800F 0x06 /* lpf output ODR masks */ +#define ODR400F 0x05 +#define ODR200F 0x04 +#define ODR100F 0x03 +#define ODR50F 0x02 +#define ODR25F 0x01 +#define ODR12_5F 0x00 + +#ifdef __KERNEL__ +struct kxti9_platform_data { + int poll_interval; + int min_interval; + + u8 g_range; + u8 shift_adj; + + u8 axis_map_x; + u8 axis_map_y; + u8 axis_map_z; + + u8 negate_x; + u8 negate_y; + u8 negate_z; + + u8 data_odr_init; + u8 ctrl_reg1_init; + u8 int_ctrl_init; + u8 tilt_timer_init; + u8 engine_odr_init; + u8 wuf_timer_init; + u8 wuf_thresh_init; + u8 tdt_timer_init; + u8 tdt_h_thresh_init; + u8 tdt_l_thresh_init; + u8 tdt_tap_timer_init; + u8 tdt_total_timer_init; + u8 tdt_latency_timer_init; + u8 tdt_window_timer_init; + + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); + + int gpio; +}; +#endif /* __KERNEL__ */ + +#endif /* __KXTI9_H__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile b/ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile new file mode 100755 index 00000000..06c28edd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/cm3232/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_cm3232 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := cm3232.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c b/ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c new file mode 100755 index 00000000..207ddd3a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/cm3232/cm3232.c @@ -0,0 +1,855 @@ +/* + * cm3232.c - Intersil cm3232 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia <mdigioia@intersil.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/hwmon.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/pm_runtime.h> +#include <linux/input-polldev.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> + +#include <linux/device.h> +#include <linux/platform_device.h> +//#include <linux/earlysuspend.h> + +#include "../sensor.h" + +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(cm3232); +#define SENSOR_I2C_NAME "cm3232" +#define SENSOR_I2C_ADDR 0x10 +#define MODULE_NAME "cm3232" + +#define REG_CMD_1 0x00 +#define REG_CMD_2 0x01 +#define REG_DATA_LSB 0x02 +#define REG_DATA_MSB 0x03 +#define ISL_MOD_MASK 0xE0 +#define ISL_MOD_POWERDOWN 0 +#define ISL_MOD_ALS_ONCE 1 +#define ISL_MOD_IR_ONCE 2 +#define ISL_MOD_RESERVED 4 +#define ISL_MOD_ALS_CONT 5 +#define ISL_MOD_IR_CONT 6 +#define IR_CURRENT_MASK 0xC0 +#define IR_FREQ_MASK 0x30 +#define SENSOR_RANGE_MASK 0x03 +#define ISL_RES_MASK 0x0C + + +#undef dbg +#define dbg(fmt, args...) //printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int no_adc_map = 1; +static int last_mod; + +static struct i2c_client *this_client = NULL; + +struct isl_device { + struct input_polled_dev* input_poll_dev; + struct i2c_client* client; + int resolution; + int range; + int isdbg; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +static struct isl_device* l_sensorconfig = NULL; +static struct kobject *android_lsensor_kobj = NULL; +static int l_enable = 0; // 0:don't report data, 1 + +static DEFINE_MUTEX(mutex); + +#if 0 +static int isl_set_mod(struct i2c_client *client, int mod) +{ + int ret, val, freq; + + switch (mod) { + case ISL_MOD_POWERDOWN: + case ISL_MOD_RESERVED: + goto setmod; + case ISL_MOD_ALS_ONCE: + case ISL_MOD_ALS_CONT: + freq = 0; + break; + case ISL_MOD_IR_ONCE: + case ISL_MOD_IR_CONT: + freq = 1; + break; + default: + return -EINVAL; + } + /* set IR frequency */ + val = i2c_smbus_read_byte_data(client, REG_CMD_2); + if (val < 0) + return -EINVAL; + val &= ~IR_FREQ_MASK; + if (freq) + val |= IR_FREQ_MASK; + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, val); + if (ret < 0) + return -EINVAL; + +setmod: + /* set operation mod */ + val = i2c_smbus_read_byte_data(client, REG_CMD_1); + if (val < 0) + return -EINVAL; + val &= ~ISL_MOD_MASK; + val |= (mod << 5); + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, val); + if (ret < 0) + return -EINVAL; + + if (mod != ISL_MOD_POWERDOWN) + last_mod = mod; + + return mod; +} + +static int isl_get_res(struct i2c_client *client) +{ + int val; + + printk(KERN_INFO MODULE_NAME ": %s cm3232 get_res call, \n", __func__); + val = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; + + if (val < 0) + return -EINVAL; + + val &= ISL_RES_MASK; + val >>= 2; + + switch (val) { + case 0: + return 65536; + case 1: + return 4096; + case 2: + return 256; + case 3: + return 16; + default: + return -EINVAL; + } +} + +static int isl_get_range(struct i2c_client* client) +{ + switch (i2c_smbus_read_word_data(client, 0)>>8 & 0xff & 0x3) { + case 0: return 1000; + case 1: return 4000; + case 2: return 16000; + case 3: return 64000; + default: return -EINVAL; + } +} +#endif +//Fixme plan to transfer the adc value to the config.xml lux 2013-5-10 +static __u16 uadc[8] = {2, 8, 100, 400, 900, 1000, 1500, 1900};//customize +static __u16 ulux[9] = {128, 200, 1300, 2000, 3000, 4000, 5000, 6000, 7000}; +static __u16 adc_to_lux(__u16 adc) +{ + static long long var = 0; + int i = 0; //length of array is 8,9 + for (i=0; i<8; i++) { + if ( adc < uadc[i]){ + break; + } + } + if ( i<9) + { + var++; + if (var%2) + return ulux[i]+0; + else + return ulux[i]+1; + } + return ulux[4]; +} + + + +static int isl_get_lux_data(struct i2c_client* client) +{ + //struct isl_device* idev = i2c_get_clientdata(client); + + //__u16 resH = 0, resL = 0; + __s16 resH = 0, resL = 0; + //int range; + resL = i2c_smbus_read_word_data(client, 0x50); + //resH = i2c_smbus_read_word_data(client, 0x51)&0xff00; + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + + return 3000;//??? + //return -1; + } + //Fixme plan to transfer the adc value to the config.xml lux 2013-5-10 + if (!no_adc_map) + resL = adc_to_lux(resL); + //printk("<<<< lux %d\n", resL); + return resL ;//* idev->range / idev->resolution; + return (resH | resL) ;//* idev->range / idev->resolution; +} + + +static int isl_set_default_config(struct i2c_client *client) +{ + //struct isl_device* idev = i2c_get_clientdata(client); + + int ret=0; + //ret = _cm3232_I2C_Write_Byte(CM3232_SLAVE_addr, CM3232_ALS_RESET); + ret = i2c_smbus_write_byte_data(client, 0, (1 << 6)); + if (ret < 0) + return -EINVAL; + //if(ret<0) + //return ret; + msleep(10); + + //ret = _cm3232_I2C_Write_Byte(CM3232_SLAVE_addr, CM3232_ALS_IT_200ms | CM3232_ALS_HS_HIGH ); + ret = i2c_smbus_write_byte_data(client, 0, (1 << 2)|(1 << 1)); + if (ret < 0) + return -EINVAL; + msleep(10); + return 0; +/* We don't know what it does ... */ +// ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xE0); +// ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0xC3); +/* Set default to ALS continuous */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xA0); + if (ret < 0) + return -EINVAL; +/* Range: 0~16000, number of clock cycles: 65536 */ + ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0x02); // vivienne + if (ret < 0) + return -EINVAL; + //idev->resolution = isl_get_res(client); + //idev->range = isl_get_range(client);; + dbg("cm3232 set_default_config call, \n"); + + return 0; +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int cm3232_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + + + return 0; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +static void isl_input_lux_poll(struct input_polled_dev *dev) +{ + struct isl_device* idev = dev->private; + struct input_dev* input = idev->input_poll_dev->input; + struct i2c_client* client = idev->client; + static unsigned int val=0; + + //printk("%s\n", __FUNCTION__); + if (l_enable != 0) + { + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + #if 0 + if(val>0x2000) + val=0; + val+=100; + #endif + //printk(KERN_ALERT "by flashchen val is %x",val); + input_report_abs(input, ABS_MISC, isl_get_lux_data(client)); + //input_report_abs(input, ABS_MISC, val);//isl_get_lux_data(client)); + input_sync(input); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + } +} + +static struct i2c_device_id cm3232_id[] = { + {"cm3232", 0}, + {} +}; + +#if 0 +static int cm3232_runtime_suspend(struct device *dev) +{ + + dev_dbg(dev, "suspend\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s cm3232 suspend call, \n", __func__); + return 0; +} + +static int cm3232_runtime_resume(struct device *dev) +{ + + dev_dbg(dev, "resume\n"); + + mutex_lock(&mutex); + pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + + printk(KERN_INFO MODULE_NAME ": %s cm3232 resume call, \n", __func__); + return 0; +} +#endif +MODULE_DEVICE_TABLE(i2c, cm3232_id); + +/*static const struct dev_pm_ops cm3232_pm_ops = { + .runtime_suspend = cm3232_runtime_suspend, + .runtime_resume = cm3232_runtime_resume, +}; + +static struct i2c_board_info isl_info = { + I2C_BOARD_INFO("cm3232", 0x44), +}; + +static struct i2c_driver cm3232_driver = { + .driver = { + .name = "cm3232", + .pm = &cm3232_pm_ops, + }, + .probe = cm3232_probe, + .remove = cm3232_remove, + .id_table = cm3232_id, + .detect = cm3232_detect, + //.address_data = &addr_data, +};*/ + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmad_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_data(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + //return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define CM3232_DRVID 0 + uval = CM3232_DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("cm3232_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmad_read, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmad_fops, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void cm3232_early_suspend(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void cm3232_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} +#endif +static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + + int i; + int size = sizeof(uadc)/sizeof(uadc[0]); + printk("<<<%s\n", __FUNCTION__); + for (i=0; i<size; i++) + { + printk(" %5d ", uadc[i]); + //sprintf(buf, "%d " &uadc[i]); + } + printk("\n"); + + return sizeof(uadc); + //printk(" %s \n", buf); +} + +static ssize_t adc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + __u32 tmp; + int index; + int n; + int size = sizeof(uadc)/sizeof(uadc[0]); + + printk("<<<%s\n", __FUNCTION__); + printk("<< %s >>>\n", buf); + n = sscanf(buf, "%d:%d", &index, &tmp); + printk("<<<<int n %d %d:%d \n", n, index, tmp); + if ( n==2 && index>=0 && index<size){ + + uadc[index] = tmp; + no_adc_map = 0; + } + else { + printk("<<<param error!\n"); + no_adc_map = 1; + } + return count; +} +static struct device_attribute cm3232_attr[] = +{ + __ATTR(adc, 0644, adc_show, adc_store), + __ATTR_NULL, +}; + +static struct device *sdevice; +static struct class *sclass; +static dev_t sdev_no; +static int device_create_attribute(struct device *dev, struct device_attribute *attr) +{ + int err, i; + for (i=0; NULL != attr[i].attr.name; i++) + { + err = device_create_file(dev, &attr[i]); //&attr[i].attr + if (err) + break; + } + if (err) + { + for (; i>=0; i--) + device_remove_file(dev, &attr[i]);//&attr[i].attr + } + return err; +} + +static void device_remove_attribute(struct device *dev, struct device_attribute *attr) +{ + int i; + for (i=0; attr[i].attr.name != NULL; i++) + device_remove_file(dev, &attr[i]); //&attr[i].attr +} + + +static int get_adc_val(void) +{ + int i, varlen, n; + __u32 buf[8]; + char varbuf[50]; + char *name = "wmt.io.lsensor"; + + varlen = sizeof(varbuf); + if (wmt_getsyspara(name, varbuf, &varlen)) + { + printk("<<<<fail to wmt_syspara %s\n", "wmt.io.lsensor"); + no_adc_map = 1; + return -1; + } + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d", &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], \ + &buf[6], &buf[7]); + //printk("<<< n %d \n", n); + if (n != 8) + { + printk("<<<<<%s uboot env wmt.io.lsensor param error!\n", __FUNCTION__); + return -1; + } + for (i=0; i<8; i++) + { + //printk("<<<< %5d ", buf[i]); + uadc[i] = buf[i]; + } + no_adc_map = 0; + //printk("\n"); + return 0; +} + +static int +cm3232_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int res=0; + int sret = 0; + struct isl_device* idev = kzalloc(sizeof(struct isl_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + //android_lsensor_kobj = kobject_create_and_add("android_lsensor", NULL); + /* + if (android_lsensor_kobj == NULL) { + errlog( + "lsensor_sysfs_init:"\ + "subsystem_register failed\n"); + res = -ENOMEM; + goto err_kobjetc_create; + } + //res = sysfs_create_group(android_lsensor_kobj, &m_isl_gr); + if (res) { + //pr_warn("cm3232: device create file failed!!\n"); + printk(KERN_INFO MODULE_NAME ": %s cm3232 device create file failed\n", __func__); + res = -EINVAL; + goto err_sysfs_create; + } + */ + +/* last mod is ALS continuous */ + last_mod = 5; + //pm_runtime_enable(&client->dev); + idev->input_poll_dev = input_allocate_polled_device(); + if(!idev->input_poll_dev) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + idev->input_poll_dev->private = idev; + idev->input_poll_dev->poll = isl_input_lux_poll; + idev->input_poll_dev->poll_interval = 100;//50; + idev->input_poll_dev->input->open = isl_input_open; + idev->input_poll_dev->input->close = isl_input_close; + idev->input_poll_dev->input->name = "lsensor_lux"; + idev->input_poll_dev->input->id.bustype = BUS_I2C; + idev->input_poll_dev->input->dev.parent = &client->dev; + input_set_drvdata(idev->input_poll_dev->input, idev); + input_set_capability(idev->input_poll_dev->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_dev->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + res = isl_set_default_config(client); + res = misc_register(&mmad_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_register; + } + res = input_register_polled_device(idev->input_poll_dev); + if(res < 0) + goto err_input_register_device; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = cm3232_early_suspend; + idev->earlysuspend.resume = cm3232_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("cm3232 probe succeed!\n"); + //create class device sysdevice 2013-5-10 + //get_adc_val(); + sclass = class_create(THIS_MODULE, "cm3232"); + if (IS_ERR(sclass)) + { + printk("<<<%s fail to create class!\n", __FUNCTION__); + return 0; + } + + + sret = alloc_chrdev_region(&sdev_no, 0, 1, "cm3232_devno"); + if (sret) + { + printk("<<<<%s alloc_chrdev_region fail!\n", __FUNCTION__); + class_destroy(sclass); + return 0; + } + sdevice = device_create(sclass, NULL, sdev_no, NULL, "cm3232_dev"); + if (IS_ERR(sdevice)) + { + printk("<<<%s device_create fail!\n", __FUNCTION__); + class_destroy(sclass); + return 0; + } + device_create_attribute(sdevice, cm3232_attr); + + return 0; +err_input_register_device: + misc_deregister(&mmad_device); + input_free_polled_device(idev->input_poll_dev); +err_misc_register: +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); + + kobject_del(android_lsensor_kobj); + + kfree(idev); + return res; +} + +static int cm3232_remove(struct i2c_client *client) +{ + struct isl_device* idev = i2c_get_clientdata(client); + if (!IS_ERR(sdevice)) + { + device_remove_attribute(sdevice, cm3232_attr); + device_destroy(sclass, sdev_no); + class_destroy(sclass); + + } + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmad_device); + input_unregister_polled_device(idev->input_poll_dev); + input_free_polled_device(idev->input_poll_dev); + //sysfs_remove_group(android_lsensor_kobj, &m_isl_gr); + kobject_del(android_lsensor_kobj); + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s cm3232 remove call, \n", __func__); + return 0; +} +//****************add platform_device & platform_driver for suspend &resume 2013-7-2 +static int ls_probe(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_remove(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_suspend(struct platform_device *pdev, pm_message_t state){ + printk("<<<%s\n", __FUNCTION__); + + return 0; +} + +static int ls_resume(struct platform_device *pdev){ + //return 0; + int ret = 0; + int count = 0; + printk("<<<%s\n", __FUNCTION__); +RETRY: + ret = isl_set_default_config(this_client); + if (ret < 0){ + printk("%s isl_set_default_config fail!\n", __FUNCTION__); + count++; + if (count < 5){ + mdelay(2); + goto RETRY; + } + else + return ret; + } + return 0; + +} +static void lsdev_release(struct device *dev) +{ + return; +} +static struct platform_device lsdev = { + .name = "lsdevice", + .id = -1, + .dev = { + .release = lsdev_release, + }, +}; +static struct platform_driver lsdrv = { + .probe = ls_probe, + .remove = ls_remove, + .suspend = ls_suspend, + .resume = ls_resume, + .driver = { + .name = "lsdevice", + }, +}; +//******************************************************************** + +static int __init sensor_cm3232_init(void) +{ + int ret = 0; + printk(KERN_INFO MODULE_NAME ": %s cm3232 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even cm3232_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&cm3232_driver); + if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (cm3232_detect(this_client)) + { + errlog("Can't find light sensor cm3232!\n"); + goto detect_fail; + } + get_adc_val(); + if(cm3232_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } + + ret = platform_device_register(&lsdev); + if (ret){ + printk("<<<platform_device_register fail!\n"); + return ret; + } + ret = platform_driver_register(&lsdrv); + if (ret){ + printk("<<<platform_driver_register fail!\n"); + platform_device_unregister(&lsdev); + return ret; + } + return 0; + +detect_fail: + sensor_i2c_unregister_device(this_client); + return -1; +} + +static void __exit sensor_cm3232_exit(void) +{ + printk(KERN_INFO MODULE_NAME ": %s cm3232 exit call \n", __func__); + cm3232_remove(this_client); + sensor_i2c_unregister_device(this_client); + platform_driver_unregister(&lsdrv); + platform_device_unregister(&lsdev); + //i2c_del_driver(&cm3232_driver); +} + +module_init(sensor_cm3232_init); +module_exit(sensor_cm3232_exit); + +MODULE_AUTHOR("flash"); +MODULE_ALIAS("cm3232 ALS"); +MODULE_DESCRIPTION("Intersil cm3232 ALS Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/Makefile new file mode 100755 index 00000000..a5dfa3cb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_dmard06
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := dmard06.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/dmard06.c b/ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/dmard06.c new file mode 100755 index 00000000..bcb6e5ad --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard06_gsensor/dmard06.c @@ -0,0 +1,980 @@ +/* + * @file drivers/i2c/chips/dmard06.c + * @brief DMARD06 g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.0 + * @date 2011/8/5 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ + +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/cdev.h> +//#include <linux/earlysuspend.h> +#include <linux/wakelock.h> +#include <asm/uaccess.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <mach/hardware.h> +#include <linux/miscdevice.h> + +////////////////////////////////////////////////////////// +#define AKMIO 0xA1 + +/* IOCTLs for AKM library */ +#define ECS_IOCTL_INIT _IO(AKMIO, 0x01) +#define ECS_IOCTL_WRITE _IOW(AKMIO, 0x02, char[5]) +#define ECS_IOCTL_READ _IOWR(AKMIO, 0x03, char[5]) +#define ECS_IOCTL_RESET _IO(AKMIO, 0x04) +#define ECS_IOCTL_INT_STATUS _IO(AKMIO, 0x05) +#define ECS_IOCTL_FFD_STATUS _IO(AKMIO, 0x06) +#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x07, short) +#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1]) +#define ECS_IOCTL_GET_NUMFRQ _IOR(AKMIO, 0x09, char[2]) +#define ECS_IOCTL_SET_PERST _IO(AKMIO, 0x0A) +#define ECS_IOCTL_SET_G0RST _IO(AKMIO, 0x0B) +#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12]) +#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int) +#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int) +#define ECS_IOCTL_GET_CALI_DATA _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE]) +#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short) + +/* IOCTLs for APPs */ +#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short) +#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short) +#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short) +//#define ECS_IOCTL_APP_SET_AFLAG _IOW(AKMIO, 0x13, short) +#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short) +#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short) +#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short) +#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17) +//#define ECS_IOCTL_APP_SET_DELAY _IOW(AKMIO, 0x18, short) +#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY +#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) /* Set raw magnetic vector flag */ +#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) /* Get raw magnetic vector flag */ + +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define WMT_IOCTL_SENSOR_CAL_OFFSET _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x01, int) //offset calibration +#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short) +#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int) + + +/* IOCTLs for pedometer */ +#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short) +////////////////////////////////////////////////////////////////// +#define SENSOR_DELAY_FASTEST 0 +#define SENSOR_DELAY_GAME 20 +#define SENSOR_DELAY_UI 60 +#define SENSOR_DELAY_NORMAL 200 + +#define DMARD06_DRVID 3 + +///////////////////////////////////////////////////////////////// + +#undef dbg +#define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +#define DMARD06_I2C_NAME "dmard06" +#define DMARD06_I2C_ADDR 0x1c + +#define GSENSOR_PROC_NAME "gsensor_config" +#define GSENSOR_MAJOR 161 +#define GSENSOR_NAME "dmard06" +#define GSENSOR_DRIVER_NAME "dmard06_drv" + +#define GSENDMARD06_UBOOT_NAME "wmt.io.d06sensor" + +#define MAX_WR_DMARD06_LEN (1+1) + +#define LSG 32 + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const DMARD06_DEVICE_NAME = "dmard06"; +//////////////////////////////////////////////////////////// +#define ID_REG_ADDR 0x0F +#define SWRESET_REG_ADDR 0x53 +#define T_REG_ADDR 0x40 +#define XYZ_REG_ADDR 0x41 +#define CTR1_REG_ADDR 0x44 +#define CTR2_REG_ADDR 0x45 +#define CTR3_REG_ADDR 0x46 +#define CTR4_REG_ADDR 0x47 +#define CTR5_REG_ADDR 0x48 +#define STAT_REG_ADDR 0x49 + + + +static int dmard06_init(void); +static void dmard06_exit(void); + +static int dmard06_file_open(struct inode*, struct file*); +static ssize_t dmard06_file_write(struct file*, const char*, size_t, loff_t*); +static ssize_t dmard06_file_read(struct file*, char*, size_t, loff_t*); +static int dmard06_file_close(struct inode*, struct file*); + +static int dmard06_i2c_suspend(struct platform_device *pdev, pm_message_t state); +static int dmard06_i2c_resume(struct platform_device *pdev); +static int dmard06_i2c_probe(void); +static int dmard06_i2c_remove(void); +static void dmard06_i2c_read_xyz(s8 *x, s8 *y, s8 *z); +static void dmard06_i2c_accel_value(s8 *val); +static int dmard06_probe( + struct platform_device *pdev); +static int dmard06_remove(struct platform_device *pdev); +static int dmard06_i2c_xyz_read_reg(u8* index ,u8 *buffer, int length); + + + +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id); +extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); + +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +///////////////////////////////////////////////////////////////// +struct work_struct poll_work; +static struct mutex sense_data_mutex; + + +struct dmard06_config +{ + int op; + int int_gpio; //0-3 + int samp; + int xyz_axis[3][3]; // (axis,direction) + int irq; + struct proc_dir_entry* sensor_proc; + //int sensorlevel; + //int shake_enable; // 1--enable shake, 0--disable shake + //int manual_rotation; // 0--landance, 90--vertical + struct input_dev *input_dev; + //struct work_struct work; + struct delayed_work work; // for polling + struct workqueue_struct *queue; + int isdbg; // 0-- no debug log, 1--show debug log + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + spinlock_t spinlock; + int pollcnt; // the counts of polling + int offset[3]; // for calibration +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif +}; + +static struct dmard06_config l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .irq = 6, + .int_gpio = 3, + .sensor_proc = NULL, + //.sensorlevel = SENSOR_GRAVITYGAME_MODE, + //.shake_enable = 0, // default enable shake + .isdbg = 0, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds + .offset = {0, 0, 0}, +}; + +static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; + + +struct raw_data +{ + short x; + short y; + short z; +}; + +struct dev_data +{ + dev_t devno; + struct cdev cdev; + struct class *class; + struct i2c_client *client; +}; + +static struct dev_data dev; + +struct file_operations dmard06_fops = +{ + .owner = THIS_MODULE, + .read = dmard06_file_read, + .write = dmard06_file_write, + .open = dmard06_file_open, + .release = dmard06_file_close, +}; + +static int dmard06_file_open(struct inode *inode, struct file *filp) +{ + dbg("open...\n"); + + return 0; +} + +static ssize_t dmard06_file_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) +{ + dbg("write...\n"); + + return 0; +} + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + +static int dmard06_packet_rptValue(int x, int y, int z) +{ + return ((0xFF&z) | ((0xFF&y)<<8) | ((0xFF&x)<<16)); +} + + +static void dmard06_work_func(struct work_struct *work) +{ + u8 buffer[3]; + //buffer[0] = 0x41; + u8 index = 0x41; + s8 x,y,z; + int xyz,tx,ty,tz; + + mutex_lock(&sense_data_mutex); + //read data + dmard06_i2c_xyz_read_reg(&index, buffer, 3); + mutex_unlock(&sense_data_mutex); + // check whether it's valid + // report the data + x = (s8)buffer[0]; + y = (s8)buffer[1]; + z = (s8)buffer[2]; + dmard06_i2c_accel_value(&x); + dmard06_i2c_accel_value(&y); + dmard06_i2c_accel_value(&z); + tx = x*l_sensorconfig.xyz_axis[0][1]+l_sensorconfig.offset[0]; + ty = y*l_sensorconfig.xyz_axis[1][1]+l_sensorconfig.offset[1]; + tz = z*l_sensorconfig.xyz_axis[2][1]+l_sensorconfig.offset[2]; + xyz = dmard06_packet_rptValue(tx, ty, tz); + input_report_abs(l_sensorconfig.input_dev, ABS_X, xyz); + + //input_report_abs(l_sensorconfig.input_dev, l_sensorconfig.xyz_axis[0][0], + // x*l_sensorconfig.xyz_axis[0][1]+l_sensorconfig.offset[0]); + //input_report_abs(l_sensorconfig.input_dev, l_sensorconfig.xyz_axis[1][0], + // y*l_sensorconfig.xyz_axis[1][1]+l_sensorconfig.offset[1]); + //input_report_abs(l_sensorconfig.input_dev, l_sensorconfig.xyz_axis[2][0], + //z*l_sensorconfig.xyz_axis[2][1]+l_sensorconfig.offset[2]); + input_sync(l_sensorconfig.input_dev); + dbg("x=%2x(tx=%2x),y=%2x(ty=%2x),z=%2x(tz=%2x),xyz=%x", + (char)x, (char)tx, (char)y, (char)ty, (char)z, (char)tz, xyz); + + // for next polling + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + //klog("%d=%d,%d=%d,%d=%d\n", l_sensorconfig.xyz_axis[0][0], x*l_sensorconfig.xyz_axis[0][1], + // l_sensorconfig.xyz_axis[1][0], y*l_sensorconfig.xyz_axis[1][1], + // l_sensorconfig.xyz_axis[2][0], z*l_sensorconfig.xyz_axis[2][1]); + //klog("the polling period:%d\n", msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + +} + + +static ssize_t dmard06_file_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + int ret; + s8 x, y, z; + struct raw_data rdata; + + dbg("read...\n"); + mutex_lock(&sense_data_mutex); + dmard06_i2c_read_xyz(&x, &y, &z); + rdata.x = x; + rdata.y = y; + rdata.z = z; + + ret = copy_to_user(buf, &rdata, count); + mutex_unlock(&sense_data_mutex); + + return count; +} + +static int dmard06_file_close(struct inode *inode, struct file *filp) +{ + dbg("close...\n"); + + return 0; +} + +static void dmard06_platform_release(struct device *device) +{ + return; +} + + +static struct platform_device dmard06_device = { + .name = GSENSOR_NAME, + .id = 0, + .dev = { + .release = dmard06_platform_release, + }, +}; + +static struct platform_driver dmard06_driver = { + .probe = dmard06_probe, + .remove = dmard06_remove, + .suspend = dmard06_i2c_suspend, + .resume = dmard06_i2c_resume, + .driver = { + .name = GSENSOR_NAME, + }, +}; + +static int dmard06_i2c_xyz_write_reg(u8* index ,u8 *buffer, int length) +{ + /*int ret = 0; + u8 buf[MAX_WR_DMARD06_LEN]; + struct i2c_msg msg[1]; + + buf[0] = *index; + memcpy(buf+1, buffer, length); + msg[0].addr = DMARD06_I2C_ADDR; + msg[0].flags = 0 ; + msg[0].flags &= ~(I2C_M_RD); + msg[0].len = length+1; + msg[0].buf = buf; + if ((ret = wmt_i2c_xfer_continue_if_4(msg,1,0)) <= 0) + { + errlog("write error!\n"); + } + return ret;*/ + return i2c_api_do_send(0, DMARD06_I2C_ADDR, index, buffer, length); +} + +static int dmard06_i2c_xyz_read_reg(u8* index ,u8 *buffer, int length) +{ + /*int ret = 0; + + struct i2c_msg msg[] = + { + {.addr = DMARD06_I2C_ADDR, .flags = 0, .len = 1, .buf = index,}, + {.addr = DMARD06_I2C_ADDR, .flags = I2C_M_RD, .len = length, .buf = buffer,}, + }; + ret = wmt_i2c_xfer_continue_if_4(msg, 2,0); + if (ret <= 0) + { + errlog("read error!\n"); + } + return ret;*/ + return i2c_api_do_recv(0, DMARD06_I2C_ADDR, index, buffer, length); +} + +static void dmard06_i2c_read_xyz(s8 *x, s8 *y, s8 *z) +{ + + u8 buffer[3]; + //buffer[0] = 0x41; + u8 index = 0x41; + + dmard06_i2c_xyz_read_reg(&index, buffer, 3); + *x = (s8)buffer[0]; + *y = (s8)buffer[1]; + *z = (s8)buffer[2]; + dmard06_i2c_accel_value(x); + dmard06_i2c_accel_value(y); + dmard06_i2c_accel_value(z); + if (ABS_X == l_sensorconfig.xyz_axis[0][0]) + { + *x = l_sensorconfig.xyz_axis[0][1]*(*x); + *y = l_sensorconfig.xyz_axis[1][1]*(*y); + } else { + *x = l_sensorconfig.xyz_axis[0][1]*(*y); + *y = l_sensorconfig.xyz_axis[1][1]*(*x); + } + *z = l_sensorconfig.xyz_axis[2][1]*(*z); + + dbg("dmrd06:x=%x,y=%x,z=%x\n", *x, *y, *z); +} + +static void dmard06_i2c_accel_value(s8 *val) +{ + *val >>= 1; +} + +static int dmard06_CalOffset(int side) +{ + u8 buffer[3]; + //buffer[0] = 0x41; + u8 index = 0x41; + s8 x,y,z; + + //mutex_lock(&sense_data_mutex); + //read data + dmard06_i2c_xyz_read_reg(&index, buffer, 3); + //mutex_unlock(&sense_data_mutex); + // check whether it's valid + // report the data + x = (s8)buffer[0]; + y = (s8)buffer[1]; + z = (s8)buffer[2]; + dmard06_i2c_accel_value(&x); + dmard06_i2c_accel_value(&y); + dmard06_i2c_accel_value(&z); + l_sensorconfig.offset[0] = 0 - x*l_sensorconfig.xyz_axis[0][1]; + l_sensorconfig.offset[1] = 0 - y*l_sensorconfig.xyz_axis[1][1]; + l_sensorconfig.offset[2] = LSG - z*l_sensorconfig.xyz_axis[2][1]; + return 0; + +} + +static int dmard06_i2c_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("...\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + + return 0; +} + +static int is_dmard06(void) +{ + int err = 0; + u8 cAddress = 0, cData = 0; + char buf[4]; + + cAddress = 0x53; + //i2c_master_send( client, (char*)&cAddress, 1); + //i2c_master_recv( client, (char*)&cData, 1); + if (dmard06_i2c_xyz_read_reg(&cAddress, &cData,1) <= 0) + { + errlog("Error to read SW_RESET register!\n"); + } + dbg("i2c Read 0x53 = %x \n", cData); + + cAddress = 0x0f; + //i2c_master_send( client, (char*)&cAddress, 1); + //i2c_master_recv( client, (char*)&cData, 1); + if (dmard06_i2c_xyz_read_reg(&cAddress, &cData,1) <= 0) + { + errlog("Can't find dmard06!\n"); + return -1; + } + dbg("i2c Read 0x0f = %d \n", cData); + + if(( cData&0x00FF) == 0x0006) + { + klog("Find DMARD06!\n"); + } + else + { + errlog("ID isn't 0x06.(0x%x) !\n",cData); + return -1; + } + + return 0; +} + +static int dmard06_i2c_remove(void) +{ + + return 0; +} + +static int dmard06_i2c_resume(struct platform_device *pdev) +{ + dbg("...\n"); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + + return 0; +} + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + unsigned int amsr = 0; + int test = 0; + + mutex_lock(&sense_data_mutex); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + printk(KERN_ALERT "Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + printk(KERN_ERR "The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.d06sensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(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]), + &l_sensorconfig.offset[0], + &l_sensorconfig.offset[1], + &l_sensorconfig.offset[2]); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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; +} + +// To contol the g-sensor for UI +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the g-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the g-sensor node...\n"); + return 0; +} + + +static int +mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + char rwbuf[5]; + short delay, enable, amsr = -1; + unsigned int sample; + int ret = 0; + int side; + char varbuff[80]; + unsigned int uval = 0; + + dbg("g-sensor ioctr...\n"); + memset(rwbuf, 0, sizeof(rwbuf)); + mutex_lock(&sense_data_mutex); + switch (cmd) { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + ret = -EFAULT; + goto errioctl; + } + klog("set delay=%d \n", delay); + //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp); + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + ret = -EFAULT; + goto errioctl; + } + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + ret = -EFAULT; + goto errioctl; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + /*if (enable != 0) + { + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + } else { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + }*/ + l_sensorconfig.sensor_enable = enable; + + } + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + ret = -EFAULT; + goto errioctl; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD06_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + ret = -EFAULT; + goto errioctl; + } + dbg("dmard06_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENSOR_CAL_OFFSET: + klog("-->WMT_IOCTL_SENSOR_CAL_OFFSET\n"); + if(copy_from_user(&side, (int*)argp, sizeof(int))) + { + ret = -EFAULT; + goto errioctl; + } + dbg("side=%d\n",side); + if (dmard06_CalOffset(side) != 0) + { + ret = -EFAULT; + goto errioctl; + } + // save the param + sprintf(varbuff, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + 10,//l_sensorconfig.samp, + (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]), + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + wmt_setsyspara(GSENDMARD06_UBOOT_NAME, varbuff); + ret = 0; + break; + default: + break; + } + + + /*switch (cmd) { + case ECS_IOCTL_READ: + if (copy_to_user(argp, &rwbuf, sizeof(rwbuf))) + return -EFAULT; + break; + default: + break; + }*/ +errioctl: + mutex_unlock(&sense_data_mutex); + return ret; +} + + +static struct file_operations mmad_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .unlocked_ioctl = mmad_ioctl, +}; + + +static struct miscdevice mmad_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &mmad_fops, +}; + +static int dmard06_probe( + struct platform_device *pdev) +{ + int err = 0; + + //register ctrl dev + err = misc_register(&mmad_device); + if (err != 0) + { + errlog("Can't register mma_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + // init work queue + l_sensorconfig.queue = create_singlethread_workqueue("sensor-data-report"); + //INIT_WORK(&l_sensorconfig.work, mma_work_func); + INIT_DELAYED_WORK(&l_sensorconfig.work, dmard06_work_func); + mutex_init(&sense_data_mutex); + l_sensorconfig.input_dev = input_allocate_device(); + if (!l_sensorconfig.input_dev) { + err = -ENOMEM; + errlog("Failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + //set_bit(EV_KEY, l_sensorconfig.input_dev->evbit); + //set_bit(EV_ABS, l_sensorconfig.input_dev->evbit); + l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); + //set_bit(KEY_NEXTSONG, l_sensorconfig.input_dev->keybit); + + /* yaw */ + //input_set_abs_params(l_sensorconfig.input_dev, ABS_RX, 0, 360*100, 0, 0); + /* pitch */ + //input_set_abs_params(l_sensorconfig.input_dev, ABS_RY, -180*100, 180*100, 0, 0); + /* roll */ + //input_set_abs_params(l_sensorconfig.input_dev, ABS_RZ, -90*100, 90*100, 0, 0); + /* x-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -128, 128, 0, 0); + /* y-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -128, 128, 0, 0); + /* z-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -128, 128, 0, 0); + + l_sensorconfig.input_dev->name = "g-sensor"; + + err = input_register_device(l_sensorconfig.input_dev); + + if (err) { + errlog("Unable to register input device: %s\n", + l_sensorconfig.input_dev->name); + goto exit_input_register_device_failed; + } + + return 0; +exit_input_register_device_failed: + input_free_device(l_sensorconfig.input_dev); +exit_input_dev_alloc_failed: + // release proc + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + // unregister the ctrl dev + misc_deregister(&mmad_device); + return err; +} + +static int dmard06_remove(struct platform_device *pdev) +{ + if (NULL != l_sensorconfig.queue) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&mmad_device); + return 0; +} +#if 0 +static void dmard06_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + dbg("exit\n"); +} + +static void dmard06_late_resume(struct early_suspend *h) +{ + dbg("start\n"); + // init + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + dbg("exit\n"); +} +#endif + +static int __init dmard06_init(void) +{ + int ret = 0; + + // detech the device + if (is_dmard06() != 0) + { + return -1; + } + // parse g-sensor u-boot arg + ret = get_axisset(NULL); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + /*if ((ret != 0) || !l_sensorconfig.op) + return -EINVAL; + */ + + // Create device node + if (register_chrdev (GSENSOR_MAJOR, GSENSOR_NAME, &dmard06_fops)) { + printk (KERN_ERR "unable to get major %d\n", GSENSOR_MAJOR); + return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, GSENSOR_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",GSENSOR_NAME); + return ret; + } + INIT_WORK(&poll_work, dmard06_work_func); + + + if((ret = platform_device_register(&dmard06_device))) + { + printk(KERN_ERR "%s Can't register mma7660 platform devcie!!!\n", __FUNCTION__); + return ret; + } + if ((ret = platform_driver_register(&dmard06_driver)) != 0) + { + printk(KERN_ERR "%s Can't register mma7660 platform driver!!!\n", __FUNCTION__); + return ret; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + l_sensorconfig.earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + l_sensorconfig.earlysuspend.suspend = dmard06_early_suspend; + l_sensorconfig.earlysuspend.resume = dmard06_late_resume; + register_early_suspend(&l_sensorconfig.earlysuspend); +#endif + + klog("dmard06 g-sensor driver load!\n"); + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + return 0; +} + +static void __exit dmard06_exit(void) +{ + //unregister_early_suspend(&l_sensorconfig.earlysuspend); + platform_driver_unregister(&dmard06_driver); + platform_device_unregister(&dmard06_device); + device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0)); + unregister_chrdev(GSENSOR_MAJOR, GSENSOR_NAME); + class_destroy(l_dev_class); + +} + +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMARD06 g-sensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(dmard06_init); +module_exit(dmard06_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile new file mode 100755 index 00000000..82f27563 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_dmard08
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := dmard08.o cyclequeue.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c new file mode 100755 index 00000000..4d6b97cd --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.c @@ -0,0 +1,68 @@ +#include <linux/mutex.h> + + +#include "cyclequeue.h" + +static struct que_data que[QUEUE_LEN]; +static unsigned int head = -1; // point to the first valaid queue data +static unsigned int tail = 0; // point to the next to the last valaid queue data +static DEFINE_MUTEX(que_mutex); + +// Whether queue is full +// return 1--full,0 -- no full +int clque_is_full(void) +{ + int ret = 0; + + mutex_lock(&que_mutex); + ret = ((tail+1)%QUEUE_LEN) == head ? 1 : 0; + mutex_unlock(&que_mutex); + return ret; +} + +// Whether queue is empty +// return 1--empty,0--no empty +int clque_is_empty(void) +{ + int ret = 0; + + mutex_lock(&que_mutex); + ret = (tail == head) ? 1: 0; + mutex_unlock(&que_mutex); + return ret; +} + +// add to queue +// return:0--successful,-1--queue is full +int clque_in(struct que_data* data) +{ + /*if (clque_is_full()) + { + return -1; + }*/ + mutex_lock(&que_mutex); + que[tail].data[0] = data->data[0]; + que[tail].data[1] = data->data[1]; + que[tail].data[2] = data->data[2]; + tail = (tail+1)%QUEUE_LEN; + mutex_unlock(&que_mutex); + return 0; +} + +// out to queue +// return:0--successful,-1--queue is empty +int clque_out(struct que_data* data) +{ + /*if (clque_is_empty()) + { + return -1; + }*/ + mutex_lock(&que_mutex); + data->data[0]= que[head].data[0]; + data->data[1]= que[head].data[1]; + data->data[2]= que[head].data[2]; + head = (head+1)%QUEUE_LEN; + mutex_unlock(&que_mutex); + return 0; +} + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h new file mode 100755 index 00000000..52b9996f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/cyclequeue.h @@ -0,0 +1,18 @@ +#ifndef __CYCLEQUEUE_163704111637_H
+#define __CYCLEQUEUE_163704111637_H
+
+#define DATA_TYPE short
+#define QUEUE_LEN 16
+
+struct que_data {
+ DATA_TYPE data[3];
+};
+
+extern int clque_in(struct que_data* data);
+extern int clque_out(struct que_data* data);
+extern int clque_is_full(void);
+extern int clque_is_empty(void);
+#endif
+
+
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c new file mode 100755 index 00000000..3cbe2ac7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.c @@ -0,0 +1,1019 @@ +/* + * @file drivers/i2c/dmard08.c + * @brief DMARD08 g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.22 + * @date 2011/12/01 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/cdev.h> +//#include <linux/earlysuspend.h> +#include <linux/wakelock.h> +#include <asm/uaccess.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/serio.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <mach/hardware.h> +#include <asm/io.h> +#include <linux/miscdevice.h> +#include <mach/gpio.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +// ****Add by Steve Huang*********2011-11-18******** +#include <linux/syscalls.h> +#include "../sensor.h" +//#include "cyclequeue.h" +// ************************************************ + +#define GSENSOR_I2C_NAME "dmard08" +#define GSENSOR_I2C_ADDR 0x1c + +#define SENSOR_DATA_SIZE 3 + +static struct i2c_client *this_client = NULL; +static struct mutex sense_data_mutex; +static struct class* l_dev_class = NULL; + +static struct wmt_gsensor_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}, +}; + + +// ****Add by Steve Huang*********2011-11-18******** +/*void gsensor_write_offset_to_file(void); +void gsensor_read_offset_from_file(void); +char OffsetFileName[] = "/data/misc/dmt/offset.txt";*/ +//************************************************** + + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); + +/*static int dmard08_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int dmard08_i2c_resume(struct i2c_client *client);*/ +//static int __devinit dmard08_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +//static int __devexit dmard08_i2c_remove(struct i2c_client *client); +void dmard08_i2c_read_xyz(struct i2c_client *client, s16 *xyz); +static inline void dmard08_i2c_correct_accel_sign(s16 *val); //check output is correct +void dmard08_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb); //merge the register values + +struct raw_data { + short x; + short y; + short z; +}; + +struct raw_data rdata; +//static struct raw_data offset; + +struct dev_data +{ + dev_t devno; + struct cdev cdev; + struct class *class; + struct i2c_client *client; +}; +//static struct dev_data dev; + + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + + +/*void gsensor_read_accel_avg(int num_avg, raw_data *avg_p) // marked by eason check again!! +{ + long xyz_acc[SENSOR_DATA_SIZE]; + s16 xyz[SENSOR_DATA_SIZE]; + int i, j; + + //initialize the accumulation buffer + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < num_avg; i++) + { + device_i2c_read_xyz(l_sensorconfig.client, (s16 *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_acc[j] += xyz[j]; + } + + // calculate averages + for(i = 0; i < SENSOR_DATA_SIZE; i++) + avg_p->v[i] = (s16) (xyz_acc[i] / num_avg); +}*/ + +/*void gsensor_calibrate(int side) //marked by eason check again +{ + raw_data avg; + int avg_num = 16; + + //IN_FUNC_MSG; + // get acceleration average reading + gsensor_read_accel_avg(avg_num, &avg); + // calculate and set the offset + gsensor_calculate_offset(side, avg); +}*/ + +/*void ce_on(void) //marked by eason check again +{ + int gppdat; + gppdat = __raw_readl(S3C64XX_GPPDAT); + gppdat |= (1 << 0); + + __raw_writel(gppdat,S3C64XX_GPPDAT); +} + +void ce_off(void) +{ + int gppdat; + gppdat = __raw_readl(S3C64XX_GPPDAT); + gppdat &= ~(1 << 0); + + __raw_writel(gppdat,S3C64XX_GPPDAT); +} + +void config_ce_pin(void) +{ + unsigned int value; + //D08's CE (pin#12) is connected to S3C64XX AP processor's port P0 + //Below codes set port P0 as digital output + value = readl(S3C64XX_GPPCON); + value &= ~ (0x3); + value |= 1 ; //Output =01 , Input = 00 , Ext. Interrupt = 10 + writel(value, S3C64XX_GPPCON); //save S3C64XX_GPPCON change +} + +void gsensor_reset(void) +{ + ce_off(); + msleep(300); + ce_on(); +}*/ + +/*void gsensor_set_offset(int val[3]) //marked by eason check again +{ + int i; + IN_FUNC_MSG; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + offset.v[i] = (s16) val[i]; +}*/ + +/* +static const struct i2c_device_id dmard08_i2c_ids[] = +{ + {GSENSOR_I2C_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, dmard08_i2c_ids); + + +static struct i2c_driver dmard08_i2c_driver = +{ + .driver = { + .owner = THIS_MODULE, + .name = GSENSOR_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .probe = dmard08_i2c_probe, + .remove = __devexit_p(dmard08_i2c_remove), + //.suspend = dmard08_i2c_suspend, + //.resume = dmard08_i2c_resume, + .id_table = dmard08_i2c_ids, +}; +*/ + +static int dmard08_i2c_xyz_read_reg(struct i2c_client *client,u8 *buffer, int length) //OK +{ + + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = 1, .buf = buffer,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = buffer,}, + }; + return i2c_transfer(client->adapter, msg, 2); +} + +static int dmard08_i2c_xyz_write_reg(struct i2c_client *client,u8 *buffer, int length) //write reg OK +{ + struct i2c_msg msg[] = + { + {.addr = client->addr, .flags = 0, .len = length, .buf = buffer,}, + }; + return i2c_transfer(client->adapter, msg, 1); +} + +//static void dmard08_i2c_read_xyz(struct i2c_client, s16 *x, s16 *y, s16 *z) //add by eason +void dmard08_i2c_read_xyz(struct i2c_client *client, s16 *xyz_p) +{ +// s16 xTmp,yTmp,zTmp; //added by eason + s16 xyzTmp[SENSOR_DATA_SIZE]; + int i; +/*get xyz high/low bytes, 0x02~0x07*/ + u8 buffer[6]; + buffer[0] = 0x2; + mutex_lock(&sense_data_mutex); + dmard08_i2c_xyz_read_reg(client, buffer, 6); + mutex_unlock(&sense_data_mutex); + + //merge to 11-bits value + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmard08_i2c_merge_register_values(client, (xyzTmp + i), buffer[2*i], buffer[2*i + 1]); + } + //transfer to the default layout + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + { + xyz_p[i] = xyzTmp[i]; // add by eason +/* xyz_p[i] = 0; + for(j = 0; j < 3; j++) + xyz_p[i] += sensorlayout[i][j] * xyzTmp[j]; */ + } + dbg("%x,%x,%x,",xyz_p[0], xyz_p[1], xyz_p[2]); + //printk("@DMT@ dmard08_i2c_read_xyz: X-axis: %d ,Y-axis: %d ,Z-axis: %d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +} + +void dmard08_i2c_merge_register_values(struct i2c_client *client, s16 *val, u8 msb, u8 lsb) +{ + + *val = (((u16)msb) << 3) | (u16)lsb; + dmard08_i2c_correct_accel_sign(val); +} + +static inline void dmard08_i2c_correct_accel_sign(s16 *val) +{ + + *val<<= (sizeof(s16) * BITS_PER_BYTE - 11); + *val>>= (sizeof(s16) * BITS_PER_BYTE - 11); +} + +/* +static int dmard08_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + dbg("...\n"); + return 0; +} +*/ + +//static int __devinit dmard08_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id) +static int __devinit dmard08_hw_init(struct i2c_client *client/*,const struct i2c_device_id *id*/) +{ + char cAddress = 0 , cData = 0; + u8 buffer[2]; + + //for(i = 0; i < SENSOR_DATA_SIZE; ++i) //marked by eason check again + // offset.v[i] = 0; + + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + { + dbg("I2C_FUNC_I2C not support\n"); + return -1; + } + //config_ce_pin(); //how used? + //gsensor_reset(); //how used? + /* check SW RESET */ + cAddress = 0x08; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x08 = %d \n", cData); + if( cData == 0x00) + { + cAddress = 0x09; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x09 = %d \n", cData); + if( cData == 0x00) + { + cAddress = 0x0a; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x0a = %d \n", cData); + if( cData == 0x88) + { + cAddress = 0x0b; + i2c_master_send( client, (char*)&cAddress, 1); + i2c_master_recv( client, (char*)&cData, 1); + dbg( "i2c Read 0x0b = %d \n", cData); + if( cData == 0x08) + { + dbg( "DMT_DEVICE_NAME registered I2C driver!\n"); + l_sensorconfig.client = client; + } + else + { + dbg( "err : i2c Read 0x0B = %d!\n",cData); + l_sensorconfig.client = NULL; + return -1; + } + } + else + { + dbg( "err : i2c Read 0x0A = %d!\n",cData); + l_sensorconfig.client = NULL; + return -1; + } + } + else + { + dbg( "err : i2c Read 0x09 = %d!\n",cData); + l_sensorconfig.client = NULL; + return -1; + } + } + else + { + dbg( "err : i2c Read 0x08 = %d!\n",cData); + l_sensorconfig.client = NULL; + + return -1; + } + + /* set sampling period if samp = 1, set the sampling frequency = 684 + otherwise set the sample frequency = 342 (default) added by eason 2012/3/7*/ + if (l_sensorconfig.samp == 1) { + buffer[0] = 0x08; + buffer[1] = 0x04; + dmard08_i2c_xyz_write_reg(client, buffer, 2); + } + + /*check sensorlayout[i][j] //eason + for(i = 0; i < 3; ++i) + { + for(j = 0; j < 3; j++) + printk("%d",sensorlayout[i][j]); + printk("\n"); + } */ + + return 0; +} + +static int __devexit dmard08_i2c_remove(struct i2c_client *client) //OK +{ + dbg("...\n"); + + return 0; +} + +/* +static int dmard08_i2c_resume(struct i2c_client *client) //OK +{ + dbg("...\n"); + + return 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.dm08sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(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]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + errlog("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void dmard08_platform_release(struct device *device) +{ + dbg("...\n"); + return; +} + + +static struct platform_device dmard08_device = { + .name = GSENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = dmard08_platform_release, + }, +}; + +static int dmard08_suspend(struct platform_device *pdev, pm_message_t state) +{ + dbg("...\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + + return 0; +} + + +static int dmard08_open(struct inode *node, struct file *fle) +{ + dbg("open...\n"); + return 0; +} + +/* release command for dmard08 device file */ +static int dmard08_close(struct inode *node, struct file *fle) +{ + dbg("close...\n"); + return 0; +} + +/* ioctl command for dmard08 device file */ +static long dmard08_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + //unsigned char data[6]; + short delay = 0; + short enable = 0; + unsigned int uval = 0; + + if (WMT_IOCTL_SENSOR_CAL_OFFSET == cmd) + { + return 0;// now do nothing + } + + /* cmd mapping */ + mutex_lock(&sense_data_mutex); + switch(cmd) + { + + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + dbg("ECS_IOCTL_APP_SET_DELAY\n"); + if (copy_from_user(&delay,(short*)arg, sizeof(short))) + { + errlog("Can't get set delay!!!\n"); + err = -EFAULT; + goto errioctl; + } + klog("set delay=%d \n", delay); + //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp); + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + err = -EFAULT; + goto errioctl; + } + break; + case ECS_IOCTL_APP_SET_AFLAG: + dbg("ECS_IOCTL_APP_SET_AFLAG\n"); + // enable/disable sensor + if (copy_from_user(&enable, (short*)arg, sizeof(short))) + { + errlog("Can't get enable flag!!!\n"); + err = -EFAULT; + goto errioctl; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + if (enable != l_sensorconfig.sensor_enable) + { + // do sth ??? + //mma_enable_disable(enable); + /*if (enable != 0) + { + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + } else { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + }*/ + l_sensorconfig.sensor_enable = enable; + + } + } else { + errlog("Wrong enable argument!!!\n"); + err = -EFAULT; + goto errioctl; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD08_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("dmard08_driver_id:%d\n",uval); + break; + default: + break; + } +errioctl: + mutex_unlock(&sense_data_mutex); + return err; +} + +/* +static ssize_t dmard08_read(struct file *file, char __user *buf, size_t count, loff_t *offset) +{ + struct que_data data; + short xyz_temp[3]; + + // read data from cycle queue + while (clque_is_empty()) msleep(10); + clque_out(&data); + xyz_temp[0] = data.data[0]; + xyz_temp[1] = data.data[1]; + xyz_temp[2] = data.data[2]; + + + if(copy_to_user(buf, &xyz_temp, sizeof(xyz_temp))) + return -EFAULT; + dbg("x=%x,y=%x,z=%x\n",xyz_temp[0], xyz_temp[1], xyz_temp[2]); + return sizeof(xyz_temp); +} +*/ +/* +static ssize_t dmard08_write(struct file *file, const char __user *buf, size_t count, loff_t *offset) +{ + dbg("write...\n"); + return 0; +} +*/ + +static const struct file_operations d08_fops = { + .owner = THIS_MODULE, + .open = dmard08_open, + .release = dmard08_close, + //.read = dmard08_read, + //.wirte = dmard08_write, + .unlocked_ioctl = dmard08_ioctl, +}; + +static struct miscdevice d08_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GSENSOR_DEV_NODE, + .fops = &d08_fops, +}; + + +static int dmard08_resume(struct platform_device *pdev) +{ + char buffer[2]; + dbg("...\n"); + + if (l_sensorconfig.samp == 1) { + buffer[0] = 0x08; + buffer[1] = 0x04; + dmard08_i2c_xyz_write_reg(l_sensorconfig.client, buffer, 2); + } + + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return 0; +} + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + mutex_lock(&sense_data_mutex); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + klog("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + +static void read_work_func(struct work_struct *work) +{ + s16 xyz[SENSOR_DATA_SIZE]; + s16 txyz[SENSOR_DATA_SIZE]; + + if (! l_sensorconfig.sensor_enable) + { + // no report data + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + return; + } + // read data to one cycle que + //dbg("read...\n"); + dmard08_i2c_read_xyz(l_sensorconfig.client, (s16 *)xyz); + + // x + txyz[0] = xyz[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]+l_sensorconfig.offset[0]; + // y + txyz[1] = xyz[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]+l_sensorconfig.offset[1]; + // z + txyz[2] = xyz[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]+l_sensorconfig.offset[2]; + + input_report_abs(l_sensorconfig.input_dev, ABS_X, txyz[0]); + input_report_abs(l_sensorconfig.input_dev, ABS_Y, txyz[1]); + input_report_abs(l_sensorconfig.input_dev, ABS_Z, txyz[2]); + input_sync(l_sensorconfig.input_dev); + l_sensorconfig.test_pass = 1; // for testing + // read next + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); +} + + +static int dmard08_probe(struct platform_device *pdev) +{ + int err = 0; + + //register ctrl dev + err = misc_register(&d08_device); + if (err !=0) { + errlog("Can't register d08_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + // init work queue + l_sensorconfig.queue = create_singlethread_workqueue("sensor-report"); + INIT_DELAYED_WORK(&l_sensorconfig.work, read_work_func); + mutex_init(&sense_data_mutex); + // init input device + l_sensorconfig.input_dev = input_allocate_device(); + if (!l_sensorconfig.input_dev) { + err = -ENOMEM; + errlog("Failed to allocate input device\n"); + goto exit_input_dev_alloc_failed; + } + l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY); + /* x-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -1024, 1024, 0, 0); + /* y-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -1024, 1024, 0, 0); + /* z-axis acceleration */ + input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -1024, 1024, 0, 0); + + l_sensorconfig.input_dev->name = GSENSOR_INPUT_NAME; + + err = input_register_device(l_sensorconfig.input_dev); + + if (err) { + errlog("Unable to register input device: %s\n", + l_sensorconfig.input_dev->name); + goto exit_input_register_device_failed; + } + + return 0; +exit_input_register_device_failed: + // free inut + input_free_device(l_sensorconfig.input_dev); +exit_input_dev_alloc_failed: + // free queue + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + // free proc + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + // free work + // unregister ctrl dev + misc_deregister(&d08_device); + return err; +} + +static int dmard08_remove(struct platform_device *pdev) +{ + if (NULL != l_sensorconfig.queue) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.queue); + destroy_workqueue(l_sensorconfig.queue); + l_sensorconfig.queue = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&d08_device); + input_unregister_device(l_sensorconfig.input_dev); + return 0; +} + + +static struct platform_driver dmard08_driver = { + .probe = dmard08_probe, + .remove = dmard08_remove, + .suspend = dmard08_suspend, + .resume = dmard08_resume, + .driver = { + .name = GSENSOR_I2C_NAME, + }, +}; + +#if 0 +static void dmard08_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + cancel_delayed_work_sync(&l_sensorconfig.work); + dbg("exit\n"); +} + +static void dmard08_late_resume(struct early_suspend *h) +{ + dbg("start\n"); + // init + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + dbg("exit\n"); +} +#endif + +static int __init dmard08_init(void) //OK +{ + int ret = 0; + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + /*if ((ret != 0) || !l_sensorconfig.op) + { + dbg("Can't load gsensor dmar08 driver for error u-boot arg!\n"); + return -EINVAL; + }*/ + if (!(this_client = sensor_i2c_register_device(0, GSENSOR_I2C_ADDR, GSENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + // find the device + /*if(i2c_add_driver(&dmard08_i2c_driver) != 0) + { + ret = -1; + dbg("Can't find gsensor dmard08!\n"); + goto err_i2c_add_driver; + }*/ + if(dmard08_hw_init(this_client)) + { + ret = -1; + dbg("Can't find gsensor dmard08!\n"); + goto err_i2c_add_driver; + } + + + // create the platform device + l_dev_class = class_create(THIS_MODULE, GSENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&dmard08_device))) + { + klog("Can't register mc3230 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&dmard08_driver)) != 0) + { + errlog("Can't register mc3230 platform driver!!!\n"); + return ret; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + l_sensorconfig.earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + l_sensorconfig.earlysuspend.suspend = dmard08_early_suspend; + l_sensorconfig.earlysuspend.resume = dmard08_late_resume; + register_early_suspend(&l_sensorconfig.earlysuspend); +#endif + + queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp))); + + return 0; + +err_i2c_add_driver: + sensor_i2c_unregister_device(this_client); + return ret; +} + +static void __exit dmard08_exit(void) //OK +{ + platform_driver_unregister(&dmard08_driver); + platform_device_unregister(&dmard08_device); + class_destroy(l_dev_class); + sensor_i2c_unregister_device(this_client); +} + +//********************************************************************************************************* +// 2011-11-30 +// Add by Steve Huang +// function definition +/* +void gsensor_write_offset_to_file(void) +{ + char data[18]; + unsigned int orgfs; + long lfile=-1; + + //sprintf(data,"%5d %5d %5d",offset.u.x,offset.u.y,offset.u.z); //marked by eason check again + + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile=sys_open(OffsetFileName,O_WRONLY|O_CREAT, 0777); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + } + else + { + sys_write(lfile, data,18); + sys_close(lfile); + } + set_fs(orgfs); + + return; +} + +void gsensor_read_offset_from_file(void) +{ + unsigned int orgfs; + char data[18]; + long lfile=-1; + orgfs = get_fs(); +// Set segment descriptor associated to kernel space + set_fs(KERNEL_DS); + + lfile=sys_open(OffsetFileName, O_RDONLY, 0); + if (lfile < 0) + { + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + if(lfile==-2) + { + lfile=sys_open(OffsetFileName,O_WRONLY|O_CREAT, 0777); + if(lfile >=0) + { + strcpy(data,"00000 00000 00000"); + printk("sys_open %s OK!!. %ld\n",OffsetFileName,lfile); + sys_write(lfile,data,18); + sys_read(lfile, data, 18); + sys_close(lfile); + } + else + printk("sys_open %s error!!. %ld\n",OffsetFileName,lfile); + } + + } + else + { + sys_read(lfile, data, 18); + sys_close(lfile); + } + //sscanf(data,"%hd %hd %hd",&offset.u.x,&offset.u.y,&offset.u.z); //marked by eason check again + set_fs(orgfs); + +} +*/ +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMARD08 g-sensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(dmard08_init); +module_exit(dmard08_exit); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h new file mode 100755 index 00000000..e6a6c935 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard08_gsensor/dmard08.h @@ -0,0 +1,75 @@ +/* + * @file include/linux/dmard08.h + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.2 + * @date 2011/11/14 + * + * @section LICENSE + * + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + */ +#ifndef DMARD08_H +#define DMARD08_H + +#define GSENSOR_I2C_NAME "dmard08" +#define GSENSOR_I2C_ADDR 0x1c +/* +#define DEVICE_I2C_NAME "dmard08" + +//#define DMT_DEBUG_DATA 1 +#define DMT_DEBUG_DATA 0 + +#if DMT_DEBUG_DATA +#define IN_FUNC_MSG printk(KERN_INFO "@DMT@ In %s\n", __func__) +#define PRINT_X_Y_Z(x, y, z) printk(KERN_INFO "@DMT@ X/Y/Z axis: %04d , %04d , %04d\n", (x), (y), (z)) +#define PRINT_OFFSET(x, y, z) printk(KERN_INFO "@offset@ X/Y/Z axis: %04d , %04d , %04d\n",offset.x,offset.y,offset.z); +#else +#define IN_FUNC_MSG +#define PRINT_X_Y_Z(x, y, z) +#define PRINT_OFFSET(x, y, z) +#endif +*/ + +//g-senor layout configuration, choose one of the following configuration +#define CONFIG_GSEN_LAYOUT_PAT_1 +//#define CONFIG_GSEN_LAYOUT_PAT_2 +//#define CONFIG_GSEN_LAYOUT_PAT_3 +//#define CONFIG_GSEN_LAYOUT_PAT_4 +//#define CONFIG_GSEN_LAYOUT_PAT_5 +//#define CONFIG_GSEN_LAYOUT_PAT_6 +//#define CONFIG_GSEN_LAYOUT_PAT_7 +//#define CONFIG_GSEN_LAYOUT_PAT_8 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define DEFAULT_SENSITIVITY 256 +#define IOCTL_MAGIC 0x09 +#define SENSOR_DATA_SIZE 3 + +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) + +#define SENSOR_MAXNR 4 + +#endif + diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile new file mode 100755 index 00000000..d9242020 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/Makefile @@ -0,0 +1,35 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_dmard09
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := dmt09.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c new file mode 100755 index 00000000..90b03aa3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.c @@ -0,0 +1,1685 @@ +/* + * @file drivers/misc/dmt09.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.06 + * @date 2013/08/14 + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include "dmt09.h" +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/wakelock.h> +#include <asm/uaccess.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/clk.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/string.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> + +#include "../sensor.h" + +////////////////////////////////////////////////////////// +static struct wmt_gsensor_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 struct class* l_dev_class = NULL; +static void update_var(void); + +//////////////////////////////////////////////////////////// + + +static unsigned int interval; +static int D09_write_offset_to_file(struct i2c_client *client); +void D09_read_offset_from_file(struct i2c_client *client); +#define DMT_BROADCAST_APK_ENABLE +char D09_OffsetFileName[] = "/data/misc/gsensor_offset.txt";//"/system/vendor/dmt/gsensor_offset.txt";// /* FILE offset.txt */ +char DmtXXFileName[] = "/data/misc/dmt_sensor.txt";//"/system/vendor/dmt/dmt_sensor.txt";// +static int create_devidfile(void); +static struct dmt_data *s_dmt; +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +static int dmard09_suspend(struct platform_device *pdev, pm_message_t state); +static int dmard09_resume(struct platform_device *pdev); + +/*static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client);*/ +static int D09_i2c_read_xyz(struct i2c_client *client, int *xyz); +static int device_i2c_rxdata(struct i2c_client *client, unsigned char *rxDat, int length); +static int device_i2c_txdata(struct i2c_client *client, unsigned char *txData, int length); + +static int dmt_get_filter(struct i2c_client *client); +static int dmt_set_filter(struct i2c_client *client,int); +static int dmt_get_position(struct i2c_client *client); +static int dmt_set_position(struct i2c_client *client,int); +static int DMT_GetOpenStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(struct dmt_data *dmt , int en){ + unsigned long dmt_delay; + if(en){ + dmt_delay=msecs_to_jiffies(atomic_read(&dmt->delay)); + if(dmt_delay<1) + dmt_delay=1; + + GSE_LOG("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&dmt->delaywork,dmt_delay); + } + else + cancel_delayed_work_sync(&dmt->delaywork); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value){ + long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + return true; +} +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + return true; +} +/* sysfs enable show & store */ +static ssize_t dmt_sysfs_enable_show( + struct dmt_data *dmt, char *buf, int pos) +{ + char str[2][16]={"ACC enable OFF","ACC enable ON"}; + int flag; + flag=atomic_read(&dmt->enable); + return sprintf(buf, "%s\n", str[flag]); +} + +static ssize_t dmt_sysfs_enable_store( + struct dmt_data *dmt, char const *buf, size_t count, int pos) +{ + int en = 0; + if (NULL == buf) + return -EINVAL; + //GSE_LOG("buf=%x %x\n", buf[0], buf[1]); + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return count; +} + +static ssize_t dmt_enable_show(struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_enable_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_enable_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count){ + return dmt_sysfs_enable_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/* sysfs delay show & store*/ +static ssize_t dmt_sysfs_delay_show( struct dmt_data *dmt, char *buf, int pos){ + return sprintf(buf, "%d\n", atomic_read(&dmt->delay)); +} + +static ssize_t dmt_sysfs_delay_store( struct dmt_data *dmt, char const *buf, size_t count, int pos){ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + atomic_set(&dmt->delay, (unsigned int) val); + GSE_LOG("Driver attribute set delay =%lld\n", val); + + return count; +} + +static ssize_t dmt_delay_show( struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return dmt_sysfs_delay_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_delay_store( struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + return dmt_sysfs_delay_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} +/* sysfs position show & store */ +static ssize_t dmt_position_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_position(dmt->client)); +} + +static ssize_t dmt_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long position; + int ret; + + ret = strict_strtoul(buf, 10, &position); + if (ret < 0) + return count; + + dmt_set_position(dmt->client, position); + return count; +} +/* sysfs offset show & store */ +static ssize_t dmt_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + return sprintf(buf, "( %d %d %d )\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); +} + +static ssize_t dmt_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + sscanf(buf, "%d %d %d", (int *)&dmt->offset.v[0], (int *)&dmt->offset.v[1], (int *)&dmt->offset.v[2]); + D09_write_offset_to_file(dmt->client); + update_var(); + return count; +} +/* sysfs filter show & store */ +static ssize_t dmt_filter_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_filter(dmt->client)); +} + +static ssize_t dmt_filter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long filter; + int ret; + + ret = strict_strtoul(buf, 10, &filter); + if (ret < 0) + return count; + + dmt_set_filter(dmt->client, filter); + return count; +} + +/* sysfs data show */ +static ssize_t dmt_acc_private_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + raw_data accel; + + mutex_lock(&dmt->data_mutex); + accel = dmt->last; + mutex_unlock(&dmt->data_mutex); + + return sprintf(buf, "( %d %d %d )\n", dmt->last.v[0], dmt->last.v[1], dmt->last.v[2]); +} +/* sysfs id show */ +static ssize_t dmt_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char str[8]={GSENSOR_ID}; + return sprintf(buf, "%s\n", str); +} +/* sysfs debug_suspend show & store */ +#ifdef DMT_DEBUG_DATA +static ssize_t dmt_debug_suspend_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + int suspend = dmt->suspend; + + mutex_lock(&dmt->suspend_mutex); + suspend = sprintf(buf, "%d\n", dmt->suspend); + mutex_unlock(&dmt->suspend_mutex); + return suspend; +} + +static ssize_t dmt_debug_suspend_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long suspend; + pm_message_t msg; + int ret; + + ret = strict_strtoul(buf, 10, &suspend); + if (ret < 0) + return count; + + memset(&msg, 0, sizeof(pm_message_t)); + + mutex_lock(&dmt->suspend_mutex); + + if (suspend) { + dmard09_suspend(dmt->pdevice, msg); + dmt->suspend = 1; + } else { + dmard09_resume(dmt->pdevice); + dmt->suspend = 0; + } + + mutex_unlock(&dmt->suspend_mutex); + + return count; +} +/* sysfs reg_read show & store */ +static ssize_t dmt_reg_read_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int err; + unsigned char i2c[1]; + + i2c[0] = (unsigned char)atomic_read(&dmt->addr); + err = device_i2c_rxdata(dmt->client, i2c, 1); + if (err < 0) + return err; + + return sprintf(buf, "0x%02X\n", i2c[0]); +} + +static ssize_t dmt_reg_read_store(struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int addr = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &addr)) + return -EINVAL; + + if (addr < 0 || 128 < addr) + return -EINVAL; + + atomic_set(&dmt->addr, addr); + + return 1; +} +#endif /* DEBUG */ +/********************************************************************* + * + * SysFS attribute functions + * + * directory : /sys/class/accelemeter/dmardXX/ + * files : + * - enable_acc [rw] [t] : enable flag for accelerometer + * - delay_acc [rw] [t] : delay in nanosecond for accelerometer + * - position [rw] [t] : chip mounting position + * - offset [rw] [t] : offset + * - data [r] [t] : raw data + * - id [r] [t] : chip id + * + * debug : + * - debug_suspend [w] [t] : suspend test + * - reg_read [rw] [t] : Read register + * - reg_write [rw] [t] : Weite register + * + * [rw]= read/write + * [r] = read only + * [w] = write only + * [b] = binary format + * [t] = text format + */ + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0660, dmt_enable_show, dmt_enable_store), + __ATTR(delay_acc, 0660, dmt_delay_show, dmt_delay_store), + __ATTR(position, 0660, dmt_position_show, dmt_position_store), + __ATTR(offset, 0660, dmt_offset_show, dmt_offset_store), + __ATTR(filter, 0660, dmt_filter_show, dmt_filter_store), + __ATTR(data, 0660, dmt_acc_private_data_show, NULL), + __ATTR(id, 0660, dmt_id_show, NULL), +#ifdef DMT_DEBUG_DATA + __ATTR(debug_suspend, 0660, dmt_debug_suspend_show,dmt_debug_suspend_store), + __ATTR(reg_read, 0660, dmt_reg_read_show, dmt_reg_read_store), + __ATTR(reg_write, 0660, NULL, NULL), +#endif // DEBUG + __ATTR_NULL, +}; + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const GSENSOR_DEVICE_NAME = SENSOR_I2C_NAME; +static char const *const device_link_name = "i2c"; +static dev_t const dmt_device_dev_t = MKDEV(MISC_MAJOR, MISC_DYNAMIC_MINOR); + +// dmt sysfs functions +static int create_device_attributes(struct device *dev, struct device_attribute *attrs){ + int i; + int err = 0; + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_sysfs_interfaces(struct dmt_data *dmt) +{ + int err; + + if (NULL == dmt) + return -EINVAL; + + err = 0; + dmt->class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if (IS_ERR(dmt->class)) { + err = PTR_ERR(dmt->class); + goto exit_class_create_failed; + } + + dmt->class_dev = device_create( + dmt->class, + NULL, + dmt_device_dev_t, + dmt, + GSENSOR_DEVICE_NAME); + if (IS_ERR(dmt->class_dev)) { + err = PTR_ERR(dmt->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &dmt->class_dev->kobj, + &dmt->client->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + dmt->class_dev, + DMT_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; +#if 0 + err = create_device_binary_attributes( + &dmt->class_dev->kobj, + dmt_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; +#endif + + return err; + +#if 0 +exit_device_binary_attributes_create_failed: + remove_device_attributes(dmt->class_dev, dmt_attributes); +#endif +exit_device_attributes_create_failed: + sysfs_remove_link(&dmt->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(dmt->class, dmt_device_dev_t); +exit_class_device_create_failed: + dmt->class_dev = NULL; + class_destroy(dmt->class); +exit_class_create_failed: + dmt->class = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct dmt_data *dmt){ + if (NULL == dmt) + return; + + if (NULL != dmt->class_dev) { + + remove_device_attributes( + dmt->class_dev, + DMT_attributes); + sysfs_remove_link( + &dmt->class_dev->kobj, + device_link_name); + dmt->class_dev = NULL; + } + if (NULL != dmt->class) { + device_destroy( + dmt->class, + dmt_device_dev_t); + class_destroy(dmt->class); + dmt->class = NULL; + } +} + +int D09_input_init(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int err = 0; + dmt->input = input_allocate_device(); + if (!dmt->input){ + GSE_ERR("input device allocate ERROR !!\n"); + return -ENOMEM; + } + else + GSE_LOG("input device allocate Success !!\n"); + /* Setup input device */ + //dmt->input->name = SENSOR_I2C_NAME; + set_bit(EV_ABS, dmt->input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(dmt->input, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Z, ABSMIN, ABSMAX, 0, 0); + /* Set InputDevice Name */ + dmt->input->name = INPUT_NAME_ACC; + /* Register */ + err = input_register_device(dmt->input); + if (err) { + GSE_ERR("input_register_device ERROR !!\n"); + input_free_device(dmt->input); + return err; + } + GSE_LOG("input_register_device SUCCESS %d !! \n",err); + + return err; +} + +int D09_calibrate(struct i2c_client *client) +{ + struct dmt_data *dmt = i2c_get_clientdata(client); + raw_data avg; + int i, j; + long xyz_acc[SENSOR_DATA_SIZE]; + int xyz[SENSOR_DATA_SIZE]; + /* initialize the offset value */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = 0; + /* initialize the accumulation buffer */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < AVG_NUM; i++) { + D09_i2c_read_xyz(client, (int *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; ++j) + xyz_acc[j] += xyz[j]; + } + /* calculate averages */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + avg.v[i] = xyz_acc[i] / AVG_NUM; + + if(avg.v[2] < 0){ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] + DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE; + } + else{ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] - DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE; + } + return 0; +} + +int dmard09_init(struct i2c_client *client){ + + //struct dmt_data *dmt = i2c_get_clientdata(client); + unsigned char buffer[7]; + /* 1. Active Mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_ACTIVE; + device_i2c_txdata(client, buffer, 2); + /* 2. check D09 who am I */ + buffer[0] = REG_DC; + device_i2c_rxdata(client, buffer, 1); + if (buffer[0] == VALUE_WHO_AM_I) + { + printk(KERN_INFO GSE_TAG"D09 WHO_AM_I_VALUE = %d \n", buffer[0]); + GSE_LOG("D09 registered I2C driver!\n"); + } + else + { + GSE_ERR("gsensor I2C err = %d!\n", buffer[0]); + return -1; + } + /* 3. Set Data conversion rate*/ + buffer[0] = REG_CNT_L1; + buffer[1] = VALUE_ODR_100; + buffer[2] = VALUE_CNT_L2; + device_i2c_txdata(client, buffer, 3); + /* 4. open hardware filter */ + buffer[0] = REG_ODF; + buffer[1] = ODF_Ave_4; + buffer[2] = 0x00; + device_i2c_txdata(client, buffer, 3); + /* 5. check hardware filter again */ + buffer[0] = REG_ODF; //0x07 smooth filter 1/8 Bandwidth */ + device_i2c_rxdata(client, buffer, 2); + printk(KERN_INFO GSE_TAG" REG_ODF = %x , %x\n", buffer[0] , buffer[1]); + + return 0; +} + +void D09_set_offset(struct i2c_client *client, int val[3]){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int i; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = val[i]; +} + +struct file_operations sensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static struct miscdevice dmt_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_I2C_NAME, + .fops = &sensor_fops, +}; + +static int sensor_close_dev(struct i2c_client *client){ + char buffer[3]; + buffer[0] = REG_ACTR; + device_i2c_rxdata(client, buffer, 2); + buffer[1] = buffer[0] & 0xFE; //Mask off last bit (POWER DOWN MODE) + //buffer[1] = MODE_POWERDOWN; + device_i2c_txdata(client,buffer, 2); + return 0; +} + +static void dmard09_shutdown(struct platform_device *pdev) +{ + flush_delayed_work_sync(&s_dmt->delaywork); + DMT_sysfs_update_active_status(s_dmt , 0); +} + + +//static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg){ +static int dmard09_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + flush_delayed_work_sync(&dmt->delaywork); + DMT_sysfs_update_active_status(dmt , 0); + return sensor_close_dev(dmt->client); +} + +//static int device_i2c_resume(struct i2c_client *client){ +static int dmard09_resume(struct platform_device *pdev) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + int en = 1; + GSE_FUN(); + printk("dmt->enable=%d",dmt->enable); + dmard09_init(dmt->client); + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return 0; +} +/* +static int __devexit device_i2c_remove(struct i2c_client *client){ + return 0; +} + +static const struct i2c_device_id device_i2c_ids[] = { + { SENSOR_I2C_NAME, 0}, + { } +}; + +static struct i2c_driver device_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = device_i2c_ids, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), +#ifdef CONFIG_HAS_EARLYSUSPEND + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, +#endif +}; +*/ +static int device_open(struct inode *inode, struct file *filp){ + return 0; +} + +static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ + //struct i2c_client *client = (struct i2c_client *)file->private_data; + //struct dmt_data *dmt = (struct dmt_data*)i2c_get_clientdata(client); + + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE], xyz[SENSOR_DATA_SIZE]; + /* check type */ + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + + /* check user space pointer is valid */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) { + case SENSOR_RESET: + ret = dmard09_init(s_dmt->client); + return ret; + + case SENSOR_CALIBRATION: + /* get orientation info */ + //if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) return -EFAULT; + D09_calibrate(s_dmt->client); + GSE_LOG("Sensor_calibration:%d %d %d\n", s_dmt->offset.u.x, s_dmt->offset.u.y, s_dmt->offset.u.z); + /* save file */ + D09_write_offset_to_file(s_dmt->client); + update_var(); + + /* return the offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + /* get data from file */ + D09_read_offset_from_file(s_dmt->client); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + D09_set_offset(s_dmt->client , intBuf); + /* write into file */ + D09_write_offset_to_file(s_dmt->client); + update_var(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + D09_i2c_read_xyz(s_dmt->client, (int *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - s_dmt->offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) { + GSE_LOG("%s: -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(s_dmt->input, ABS_X, intBuf[0]); + input_report_abs(s_dmt->input, ABS_Y, intBuf[1]); + input_report_abs(s_dmt->input, ABS_Z, intBuf[2]); + input_sync(s_dmt->input); + GSE_LOG("SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",intBuf[0],intBuf[1],intBuf[2]); + return ret; + + case SENSOR_GET_OPEN_STATUS: + GSE_LOG("Going into DMT_GetOpenStatus()\n"); + ret = DMT_GetOpenStatus(s_dmt->client); + return ret; + + case SENSOR_GET_CLOSE_STATUS: + GSE_LOG("Going into DMT_GetCloseStatus()\n"); + ret = DMT_GetCloseStatus(s_dmt->client); + return ret; + + case SENSOR_GET_DELAY: + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return ret; + + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp){ + return 0; +} + +/***** I2C I/O function ***********************************************/ +static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length){ + struct i2c_msg msgs[] = { + {.addr = client->addr, .flags = 0, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = rxData,}, + }; + //unsigned char addr = rxData[0]; + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "RxData: len=%02x, addr=%02x, data=%02x\n", + //length, addr, rxData[0]); + + return 0; +} + +static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length){ + struct i2c_msg msg[] = { + {.addr = client->addr, .flags = 0, .len = length, .buf = txData,}, + }; + + if (i2c_transfer(client->adapter, msg, 1) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "TxData: len=%02x, addr=%02x data=%02x\n", + //length, txData[0], txData[1]); + return 0; +} + +static int D09_i2c_read_xyz(struct i2c_client *client, int *xyz_p){ + + struct dmt_data *dmt = i2c_get_clientdata(client); + u8 buffer[11]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int pos = dmt->position; + int i, j , k; + /* get xyz high/low bytes, 0x0A */ + buffer[0] = REG_STAT; + /* Read acceleration data */ + if (device_i2c_rxdata(client, buffer, 8)!= 0) + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + { + xyz_p[i] = 0; + xyzTmp[i] = 0; + } + else + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + xyzTmp[i] = 0; + /* merge xyz high/low bytes & 1g = 128 becomes 1g = 1024 */ + mutex_lock(&dmt->data_mutex); + xyzTmp[i] =(((int16_t)((buffer[2*(i+1)+1] << 8)) | buffer[2*(i+1)] ) >> 3) << 5; + mutex_unlock(&dmt->data_mutex); + } +#ifdef SW_FILTER + if( dmt->aveflag >= dmt->filter){ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = dmt->sum[i] - dmt->bufferave[i][dmt->pointer] + xyzTmp[i]; + } + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_p[i] += (int)(dmt->sum[j]/dmt->filter * dmt_position_map[pos][i][j]); + } + } + else{ + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->sum[i] = xyzTmp[i]; +#endif + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++){ + xyz_p[i] += (int)(xyzTmp[j] * dmt_position_map[pos][i][j]); + //GSE_LOG("%04d, %04d,%d \n", xyz_p[i], xyzTmp[j], dmt_position_map[pos][i][j]); + } + } + //GSE_LOG("xyz_p: %04d , %04d , %04d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +#ifdef SW_FILTER + dmt->aveflag++; + } + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = 0; + } + dmt->pointer++; + dmt->pointer %= dmt->filter; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->bufferave[i][dmt->pointer] = xyzTmp[i]; + } + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(k = 0; k < dmt->filter; ++k){ + dmt->sum[i] += dmt->bufferave[i][k]; + } + } +#endif + return 0; +} + +static void DMT_work_func(struct work_struct *delaywork){ + struct dmt_data *dmt = container_of(delaywork, struct dmt_data, delaywork.work); + int i; + //static bool firsttime=true; + raw_data xyz; + unsigned long dmt_delay = msecs_to_jiffies(atomic_read(&dmt->delay)); + + + D09_i2c_read_xyz(dmt->client, (int *)&xyz.v); + /* dmt->last = RawData - Offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->last.v[i] = xyz.v[i] - dmt->offset.v[i]; + //GSE_LOG("@DMTRaw @ X/Y/Z axis: %04d , %04d , %04d\n", xyz.v[0], xyz.v[1], xyz.v[2]); + //GSE_LOG("@Offset @ X/Y/Z axis: %04d , %04d , %04d\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + //GSE_LOG("@Raw-Offset@ X/Y/Z axis: %04d , %04d , %04d ,dmt_delay=%d\n", dmt->last.u.x, dmt->last.u.y, dmt->last.u.z, atomic_read(&dmt->delay)); + +#ifdef STABLE_VALUE_FUNCTION + if(abs(dmt->last.v[0])< RANGE_XYZ){ dmt->last.v[0] = 0;} + if(abs(dmt->last.v[1])< RANGE_XYZ){ dmt->last.v[1] = 0;} + if(abs(dmt->last.v[2])< RANGE_XYZ){ dmt->last.v[2] = 0;} +#endif + + + input_report_abs(dmt->input, ABS_X, -dmt->last.v[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]);//dmt->last.v[0]); + input_report_abs(dmt->input, ABS_Y, -dmt->last.v[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]);//dmt->last.v[1]); + input_report_abs(dmt->input, ABS_Z, -dmt->last.v[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]);//dmt->last.v[2]); + input_sync(dmt->input); + + if(dmt_delay < 1) + dmt_delay = 1; + schedule_delayed_work(&dmt->delaywork, dmt_delay); +} + +static int mma09_open(struct inode *node, struct file *fle) +{ + GSE_LOG("open...\n"); + return 0; +} + +static int mma09_close(struct inode *node, struct file *fle) +{ + GSE_LOG("close...\n"); + return 0; +} + +static long mma09_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + //unsigned char data[6]; + void __user *argp = (void __user *)arg; + short delay, enable; + unsigned int uval = 0; + + + /* cmd mapping */ + switch(cmd) + { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + l_sensorconfig.sensor_samp = 1000/delay; + atomic_set(&s_dmt->delay, 1000/delay); + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable); + + l_sensorconfig.sensor_enable = enable; + atomic_set(&s_dmt->enable,enable); + DMT_sysfs_update_active_status(s_dmt , enable); + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD09_DRVID;//; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + GSE_LOG("dmard09_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + uval = (10<<8) | 1; + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<<resolution:0x%x\n",uval); + default: + err = -1; + break; + } + + return err; +} + +static const struct file_operations d09_fops = { + .owner = THIS_MODULE, + .open = mma09_open, + .release = mma09_close, + .unlocked_ioctl = mma09_ioctl, +}; + + +static struct miscdevice d09_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GSENSOR_DEV_NODE, + .fops = &d09_fops, +}; + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + //mutex_lock(&sense_data_mutex); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + klog("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + atomic_set(&s_dmt->enable,1); + DMT_sysfs_update_active_status(s_dmt , 1); + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + atomic_set(&s_dmt->enable,0); + DMT_sysfs_update_active_status(s_dmt , 0); + } + //mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +//static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id){ +static int __devinit dmard09_probe(struct platform_device *pdev) +{ + int i, k, ret = 0; + //struct dmt_data *s_dmt = i2c_get_clientdata(client); + //struct dmt_data *s_dmt; + GSE_FUN(); +/* + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){ + GSE_ERR("check_functionality failed.\n"); + ret = -ENODEV; + goto exit0; + } + + // Allocate memory for driver data + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + ret = -ENOMEM; + goto exit1; + } +*/ + /*for(i = 0; i < SENSOR_DATA_SIZE; ++i) + s_dmt->offset.v[i] = 0;*/ +#ifdef SW_FILTER + s_dmt->pointer = 0; + s_dmt->aveflag = 0; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + s_dmt->sum[i] = 0; + for(k = 0; k < SENSOR_DATA_AVG; ++k){ + s_dmt->bufferave[i][k] = 0; + } + } + s_dmt->filter = SENSOR_DATA_AVG; + GSE_LOG("D09_DEFAULT_FILTER: %d\n", s_dmt->filter); +#endif + /* I2C initialization */ + //s_dmt->client = client; + + /* set client data */ + i2c_set_clientdata(s_dmt->client, s_dmt); + /*ret = dmard09_init(client); + if (ret < 0) + goto exit2; + */ + /* input */ + ret = D09_input_init(s_dmt->client); + if (ret){ + GSE_ERR("D09_input_init fail, error code= %d\n",ret); + goto exit3; + } + + /* initialize variables in dmt_data */ + mutex_init(&s_dmt->data_mutex); + mutex_init(&s_dmt->enable_mutex); +#ifdef DMT_DEBUG_DATA + mutex_init(&s_dmt->suspend_mutex); +#endif + init_waitqueue_head(&s_dmt->open_wq); + atomic_set(&s_dmt->active, 0); + atomic_set(&s_dmt->enable, 0); + atomic_set(&s_dmt->delay, 0); + atomic_set(&s_dmt->addr, 0); + /* DMT Acceleration Sensor Mounting Position on Board */ + s_dmt->position = D09_DEFAULT_POSITION; + GSE_LOG("D09_DEFAULT_POSITION: %d\n", s_dmt->position); + //s_dmt->position = (CONFIG_INPUT_DMT_ACCELEROMETER_POSITION); + //GSE_LOG("CONFIG_INPUT_DMT_ACCELEROMETER_POSITION: %d\n", s_dmt->position); + /* Misc device */ + if (misc_register(&dmt_device) < 0){ + GSE_ERR("dmt_dev register failed"); + goto exit4; + } + + /* Setup sysfs */ + if (create_sysfs_interfaces(s_dmt) < 0){ + GSE_ERR("create sysfs failed."); + goto exit5; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + s_dmt->early_suspend.suspend = device_i2c_suspend; + s_dmt->early_suspend.resume = device_i2c_resume; + register_early_suspend(&s_dmt->early_suspend); +#endif + /* Setup driver interface */ + INIT_DELAYED_WORK(&s_dmt->delaywork, DMT_work_func); + GSE_LOG("DMT: INIT_DELAYED_WORK\n"); + + //register ctrl dev + ret = misc_register(&d09_device); + if (ret !=0) { + errlog("Can't register d09_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + + //create offset file after factory reset + D09_read_offset_from_file(s_dmt->client); + + return 0; + +exit5: + misc_deregister(&dmt_device); +exit4: + input_unregister_device(s_dmt->input); +exit3: + kfree(s_dmt); +/*exit2: +exit1: +exit0:*/ + return ret; +} +/* +static struct i2c_board_info dmard09_board_info={ + .type = SENSOR_I2C_NAME, + .addr = SENSOR_I2C_ADDR, +}; +*/ +//static struct i2c_client *client; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +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.dm09sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(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]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + errlog("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void dmard09_platform_release(struct device *device) +{ + GSE_LOG("...\n"); + return; +} + +static int __devexit dmard09_remove(struct platform_device *pdev) +{ + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + //misc_deregister(&d09_device); + return 0; +} + + +static struct platform_device dmard09_device = { + .name = SENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = dmard09_platform_release, + }, +}; + +static struct platform_driver dmard09_driver = { + .probe = dmard09_probe, + .remove = dmard09_remove, + .shutdown = dmard09_shutdown, + .suspend = dmard09_suspend, + .resume = dmard09_resume, + .driver = { + .name = SENSOR_I2C_NAME, + }, +}; + + +static int __init device_init(void){ + //struct device *device; + struct i2c_client *this_client; + int ret = 0; + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + GSE_LOG("D09 gsensor driver: initialize.\n"); + + if (!(this_client = sensor_i2c_register_device(0, DEVICE_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (dmard09_init(this_client)) + { + GSE_ERR("Failed to init dmard09!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + /* Allocate memory for driver data */ + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + //memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + return -ENOMEM; + } + + s_dmt->client = this_client; + s_dmt->pdevice = &dmard09_device; + s_dmt->offset.u.x = l_sensorconfig.offset[0]; + s_dmt->offset.u.y = l_sensorconfig.offset[1]; + s_dmt->offset.u.z = l_sensorconfig.offset[2]; + + + // create the platform device + l_dev_class = class_create(THIS_MODULE, SENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&dmard09_device))) + { + GSE_ERR("Can't register dmard09 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&dmard09_driver)) != 0) + { + GSE_ERR("Can't register dmard09 platform driver!!!\n"); + return ret; + } + + return 0; +} + +static void __exit device_exit(void){ + //i2c_unregister_device(client); + //i2c_del_driver(&device_i2c_driver); + GSE_LOG("D09 gsensor driver: release.\n"); + + flush_delayed_work_sync(&s_dmt->delaywork); + cancel_delayed_work_sync(&s_dmt->delaywork); + + input_unregister_device(s_dmt->input); + input_free_device(s_dmt->input); + misc_deregister(&dmt_device); + misc_deregister(&d09_device); + platform_driver_unregister(&dmard09_driver); + platform_device_unregister(&dmard09_device); + sensor_i2c_unregister_device(s_dmt->client); + class_destroy(l_dev_class); + + remove_sysfs_interfaces(s_dmt); + kfree(s_dmt); +} + +static int dmt_get_filter(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->filter; +} + +static int dmt_set_filter(struct i2c_client *client, int filter){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((filter >= 1) && (filter <= 32))) + return -1; + dmt->filter = filter; + return 0; +} + +static int dmt_get_position(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->position; +} + +static int dmt_set_position(struct i2c_client *client, int position){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((position >= 0) && (position <= 7))) + return -1; + dmt->position = position; + return 0; +} + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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], + s_dmt->offset.u.x, + s_dmt->offset.u.y, + s_dmt->offset.u.z + ); + + wmt_setsyspara("wmt.io.dm09sensor",varbuf); +} + +static int D09_write_offset_to_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + char r_buf[18] = {0}; + char w_buf[18] = {0}; + //unsigned int orgfs; + struct file *fp; + mm_segment_t fs; + ssize_t ret; + //int8_t i; + + sprintf(w_buf,"%5d %5d %5d", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + /* Set segment descriptor associated to kernel space */ + fp = filp_open(D09_OffsetFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("filp_open %s error!!.:%d\n",D09_OffsetFileName,fp); + return -1; + } + else{ + fs = get_fs(); + //set_fs(KERNEL_DS); + set_fs(get_ds()); + GSE_LOG("filp_open %s SUCCESS!!.\n",D09_OffsetFileName); + //fp->f_op->write(fp,data,18, &fp->f_pos); + //filp_close(fp,NULL); + ret = fp->f_op->write(fp,w_buf,18,&fp->f_pos); + if(ret != 18) + { + printk(KERN_ERR "%s: write error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + //fp->f_pos=0x00; + ret = fp->f_op->read(fp,r_buf, 18,&fp->f_pos); + if(ret < 0) + { + printk(KERN_ERR "%s: read error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + set_fs(fs); + + // + //printk(KERN_INFO "%s: read ret=%d!", __func__, ret); + /* for(i=0; i<18 ;i++) + { + if(r_buf[i] != w_buf[i]) + { + printk(KERN_ERR "%s: read back error, r_buf[%x](0x%x) != w_buf[%x](0x%x)\n", + __func__, i, r_buf[i], i, w_buf[i]); + filp_close(fp,NULL); + return -EIO; + } + } + */ + + } + filp_close(fp,NULL); + return 0; +} + +void D09_read_offset_from_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + unsigned int orgfs; + char data[18]; + struct file *fp; + int ux,uy,uz; + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + + fp = filp_open(D09_OffsetFileName, O_RDWR , 0); + GSE_FUN(); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + if(l_sensorconfig.op){ //first time + l_sensorconfig.op=0; +#if AUTO_CALIBRATION + /* get acceleration average reading */ + D09_calibrate(client); + update_var(); + D09_write_offset_to_file(client); +#endif +#ifdef DMT_BROADCAST_APK_ENABLE + create_devidfile(); + return; +#endif + } + D09_write_offset_to_file(client); + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",D09_OffsetFileName); + fp->f_op->read(fp,data,18, &fp->f_pos); + GSE_LOG("filp_read result %s\n",data); + sscanf(data,"%d %d %d",&ux,&uy,&uz); + dmt->offset.u.x=ux; + dmt->offset.u.y=uy; + dmt->offset.u.z=uz; + } + set_fs(orgfs); +} +static int create_devidfile(void) +{ + char data[18]; + unsigned int orgfs; + struct file *fp; + + sprintf(data,"%5d %5d %5d",0,0,0); + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + GSE_FUN(); + fp = filp_open(DmtXXFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + return -1; + } + fp->f_op->write(fp,data,18, &fp->f_pos); + set_fs(orgfs); + filp_close(fp,NULL); + return 0; +} +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h new file mode 100755 index 00000000..d30e606a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard09_gsensor/dmt09.h @@ -0,0 +1,183 @@ +/* @version 1.03 + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef DMT09_H +#define DMT09_H +#include <linux/types.h> +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/syscalls.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +//#include <linux/earlysuspend.h> +#define AUTO_CALIBRATION 0 +#define SW_FILTER /* Enable or Disable Software filter */ +#define SENSOR_DATA_AVG 4//8 /* AVG sensor data */ + +#define STABLE_VALUE_FUNCTION +#define RANGE_XYZ 40 + +//#define DMT_DEBUG_DATA +#define GSE_TAG "[DMT_Gsensor]" +#ifdef DMT_DEBUG_DATA +#define GSE_ERR(fmt, args...) printk(KERN_ERR GSE_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define GSE_LOG(fmt, args...) printk(KERN_INFO GSE_TAG fmt, ##args) +#define GSE_FUN(f) printk(KERN_INFO GSE_TAG" %s: %s: %i\n", __FILE__, __func__, __LINE__) +#define DMT_DATA(dev, ...) dev_dbg((dev), ##__VA_ARGS__) +#else +#define GSE_ERR(fmt, args...) +#define GSE_LOG(fmt, args...) +#define GSE_FUN(f) +#define DMT_DATA(dev, format, ...) +#endif + +#define GSENSOR_ID "DMARD09" +#define INPUT_NAME_ACC "g-sensor"//"DMT_accel"//"g-sensor"// /* Input Device Name */ +#define SENSOR_I2C_NAME "dmard09"//"dmt"// /* Device name for DMARD09 misc. device */ +#define DEVICE_I2C_ADDR 0x1d +#define REG_ACTR 0x00 +#define REG_STAT 0x0A +#define REG_DX 0x0C +#define REG_DY 0x0E +#define REG_DZ 0x10 +#define REG_DT 0x12 +#define REG_INL 0x16 +#define REG_DC 0x18 +#define REG_CNT_L1 0x1B +#define REG_CNT_L2 0x1C +#define REG_CNT_L3 0x1D +#define REG_INC 0x1E +#define REG_ODF 0x20 +#define REG_THR1 0x62 +#define REG_THR2 0x64 + +#define MODE_ACTIVE 0x61 /* active */ +#define MODE_POWERDOWN 0x60 /* powerdown */ + +#define VALUE_WHO_AM_I 0x95 /* D09 WMI */ +#define VALUE_ODR_200 0x9C /* conversion rate 200Hz */ +#define VALUE_ODR_100 0x98 /* conversion rate 100Hz */ +#define VALUE_ODR_50 0x94 /* conversion rate 50Hz */ +#define VALUE_ODR_20 0x90 /* conversion rate 20Hz */ +#define VALUE_ODR_10 0x8C /* conversion rate 10Hz */ +#define VALUE_ODR_5 0x88 /* conversion rate 5Hz */ +#define VALUE_ODR_1 0x84 /* conversion rate 1Hz */ +#define VALUE_ODR_0_5 0x80 /* conversion rate 0.5Hz */ +#define VALUE_CNT_L2 0xE4 /* Disable IEN */ +/* Optional Digital Filter [Low Byte and High Byte Order] */ +#define ODF_NoFilter 0x00 /* No filter */ +#define ODF_Ave_4 0x03 /* smooth filter 1/4 Bandwidth */ +#define ODF_Ave_8 0x07 /* smooth filter 1/8 Bandwidth */ +#define ODF_Ave_16 0x0f /* smooth filter 1/16 Bandwidth */ + + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 +#define SENSOR_DATA_SIZE 3 +#define DEFAULT_SENSITIVITY 1024 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) +#define SENSOR_MAXNR 8 +/* Default sensorlayout parameters */ +#define D09_DEFAULT_POSITION 6 + +/* Transformation matrix for chip mounting position */ +static const int dmt_position_map[][3][3] = { + { { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, }, /* top/upper-left */ + { { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, }, /* top/lower-left */ + { {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, }, /* top/lower-right */ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, }, /* top/upper-right */ + { {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, }, /* bottom/upper-right*/ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0, 1}, }, /* bottom/upper-left */ + { { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, }, /* bottom/lower-right*/ + { { 0, 1,0}, { 1, 0, 0}, { 0, 0, 1}, }, /* bottom/lower-left */ +}; + +typedef union { + struct { + int x; + int y; + int z; + } u; + int v[SENSOR_DATA_SIZE]; +} raw_data; + +struct dmt_data { + struct platform_device *pdevice; + struct device *class_dev; + struct class *class; + struct input_dev *input; + struct i2c_client *client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct delayed_work delaywork; + struct work_struct work; + struct mutex data_mutex; + struct mutex enable_mutex; /* for suspend */ + raw_data last; /* RawData */ + raw_data offset; /* Offset */ +#ifdef SW_FILTER + int sum[SENSOR_DATA_SIZE]; /* SW_FILTER sum */ + int bufferave[3][32]; + s8 aveflag; /* FULL bufferave[][] */ + s8 pointer; /* last update data */ +#endif + wait_queue_head_t open_wq; + atomic_t active; + atomic_t delay; + atomic_t enable; + int filter; + int position; /* must int type ,for Kconfig setup */ + atomic_t addr; +#ifdef DMT_DEBUG_DATA + struct mutex suspend_mutex; + int suspend; +#endif +}; + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define DMT_NUM_SENSORS 3 + +/* ABS axes parameter range [um/s^2] (for input event) */ +#define GRAVITY_EARTH 9806550 +#define ABSMAX (GRAVITY_EARTH * 2) +#define ABSMIN (-GRAVITY_EARTH * 2) + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile new file mode 100755 index 00000000..3241f881 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_dmard10
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := dmt10.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c new file mode 100755 index 00000000..9810ea3a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.c @@ -0,0 +1,1702 @@ +/* + * @file drivers/misc/dmt10.c + * @brief DMT g-sensor Linux device driver + * @author Domintech Technology Co., Ltd (http://www.domintech.com.tw) + * @version 1.06 + * @date 2013/08/14 + * @section LICENSE + * + * Copyright 2012 Domintech Technology Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ +#include "dmt10.h" +#include <linux/module.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/kthread.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/wakelock.h> +#include <asm/uaccess.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/clk.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/string.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> + +#include "../sensor.h" + +////////////////////////////////////////////////////////// +static struct wmt_gsensor_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 struct class* l_dev_class = NULL; +static void update_var(void); + +//////////////////////////////////////////////////////////// + + +static unsigned int interval; +static int D10_write_offset_to_file(struct i2c_client *client); +void D10_read_offset_from_file(struct i2c_client *client); +#define DMT_BROADCAST_APK_ENABLE +char D10_OffsetFileName[] = "/data/misc/gsensor_offset.txt"; /* FILE offset.txt */ +char DmtXXFileName[] = "/data/misc/dmt_sensor.txt"; +static int create_devidfile(void); +static struct dmt_data *s_dmt; +static int device_init(void); +static void device_exit(void); + +static int device_open(struct inode*, struct file*); +static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +static int device_close(struct inode*, struct file*); + +static int dmard10_suspend(struct platform_device *pdev, pm_message_t state); +static int dmard10_resume(struct platform_device *pdev); + +/*static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg); +static int device_i2c_resume(struct i2c_client *client); +static int __devinit device_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); +static int __devexit device_i2c_remove(struct i2c_client *client);*/ +static int D10_i2c_read_xyz(struct i2c_client *client, int *xyz); +static int device_i2c_rxdata(struct i2c_client *client, unsigned char *rxDat, int length); +static int device_i2c_txdata(struct i2c_client *client, unsigned char *txData, int length); + +static int dmt_get_filter(struct i2c_client *client); +static int dmt_set_filter(struct i2c_client *client,int); +static int dmt_get_position(struct i2c_client *client); +static int dmt_set_position(struct i2c_client *client,int); +static int DMT_GetOpenStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) != 0)); + return 0; +} + +static int DMT_GetCloseStatus(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + GSE_LOG("start active=%d\n",dmt->active.counter); + wait_event_interruptible(dmt->open_wq, (atomic_read(&dmt->active) <= 0)); + return 0; +} + +static void DMT_sysfs_update_active_status(struct dmt_data *dmt , int en){ + unsigned long dmt_delay; + if(en){ + dmt_delay=msecs_to_jiffies(atomic_read(&dmt->delay)); + if(dmt_delay<1) + dmt_delay=1; + + GSE_LOG("schedule_delayed_work start with delay time=%lu\n",dmt_delay); + schedule_delayed_work(&dmt->delaywork,dmt_delay); + } + else + cancel_delayed_work_sync(&dmt->delaywork); +} + +static bool get_value_as_int(char const *buf, size_t size, int *value){ + long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtol(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtol(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtol(buf, 10, &tmp)) + return false; + } + + if (tmp > INT_MAX) + return false; + + *value = tmp; + return true; +} +static bool get_value_as_int64(char const *buf, size_t size, long long *value) +{ + long long tmp; + if (size == 0) + return false; + /* maybe text format value */ + if ((buf[0] == '0') && (size > 1)) { + if ((buf[1] == 'x') || (buf[1] == 'X')) { + /* hexadecimal format */ + if (0 != strict_strtoll(buf, 16, &tmp)) + return false; + } else { + /* octal format */ + if (0 != strict_strtoll(buf, 8, &tmp)) + return false; + } + } else { + /* decimal format */ + if (0 != strict_strtoll(buf, 10, &tmp)) + return false; + } + + if (tmp > LLONG_MAX) + return false; + + *value = tmp; + return true; +} +/* sysfs enable show & store */ +static ssize_t dmt_sysfs_enable_show( + struct dmt_data *dmt, char *buf, int pos) +{ + char str[2][16]={"ACC enable OFF","ACC enable ON"}; + int flag; + flag=atomic_read(&dmt->enable); + return sprintf(buf, "%s\n", str[flag]); +} + +static ssize_t dmt_sysfs_enable_store( + struct dmt_data *dmt, char const *buf, size_t count, int pos) +{ + int en = 0; + if (NULL == buf) + return -EINVAL; + //GSE_LOG("buf=%x %x\n", buf[0], buf[1]); + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &en)) + return -EINVAL; + + en = en ? 1 : 0; + + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return count; +} + +static ssize_t dmt_enable_show(struct device *dev, struct device_attribute *attr, char *buf){ + return dmt_sysfs_enable_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_enable_store( struct device *dev, struct device_attribute *attr, char const *buf, size_t count){ + return dmt_sysfs_enable_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} + +/* sysfs delay show & store*/ +static ssize_t dmt_sysfs_delay_show( struct dmt_data *dmt, char *buf, int pos){ + return sprintf(buf, "%d\n", atomic_read(&dmt->delay)); +} + +static ssize_t dmt_sysfs_delay_store( struct dmt_data *dmt, char const *buf, size_t count, int pos){ + long long val = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int64(buf, count, &val)) + return -EINVAL; + + atomic_set(&dmt->delay, (unsigned int) val); + GSE_LOG("Driver attribute set delay =%lld\n", val); + + return count; +} + +static ssize_t dmt_delay_show( struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return dmt_sysfs_delay_show( dev_get_drvdata(dev), buf, ACC_DATA_FLAG); +} + +static ssize_t dmt_delay_store( struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + return dmt_sysfs_delay_store( dev_get_drvdata(dev), buf, count, ACC_DATA_FLAG); +} +/* sysfs position show & store */ +static ssize_t dmt_position_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_position(dmt->client)); +} + +static ssize_t dmt_position_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long position; + int ret; + + ret = strict_strtoul(buf, 10, &position); + if (ret < 0) + return count; + + dmt_set_position(dmt->client, position); + return count; +} +/* sysfs offset show & store */ +static ssize_t dmt_offset_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + return sprintf(buf, "( %d %d %d )\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); +} + +static ssize_t dmt_offset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + sscanf(buf, "%d %d %d", (int *)&dmt->offset.v[0], (int *)&dmt->offset.v[1], (int *)&dmt->offset.v[2]); + D10_write_offset_to_file(dmt->client); + update_var(); + return count; +} +/* sysfs filter show & store */ +static ssize_t dmt_filter_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + + return sprintf(buf, "%d\n", dmt_get_filter(dmt->client)); +} + +static ssize_t dmt_filter_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long filter; + int ret; + + ret = strict_strtoul(buf, 10, &filter); + if (ret < 0) + return count; + + dmt_set_filter(dmt->client, filter); + return count; +} + +/* sysfs data show */ +static ssize_t dmt_acc_private_data_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + raw_data accel; + + mutex_lock(&dmt->data_mutex); + accel = dmt->last; + mutex_unlock(&dmt->data_mutex); + + return sprintf(buf, "( %d %d %d )\n", dmt->last.v[0], dmt->last.v[1], dmt->last.v[2]); +} +/* sysfs id show */ +static ssize_t dmt_id_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + char str[8]={GSENSOR_ID}; + return sprintf(buf, "%s\n", str); +} +/* sysfs debug_suspend show & store */ +#ifdef DMT_DEBUG_DATA +static ssize_t dmt_debug_suspend_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + int suspend = dmt->suspend; + + mutex_lock(&dmt->suspend_mutex); + suspend = sprintf(buf, "%d\n", dmt->suspend); + mutex_unlock(&dmt->suspend_mutex); + return suspend; +} + +static ssize_t dmt_debug_suspend_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct input_dev *input = to_input_dev(dev); + struct dmt_data *dmt = input_get_drvdata(input); + unsigned long suspend; + pm_message_t msg; + int ret; + + ret = strict_strtoul(buf, 10, &suspend); + if (ret < 0) + return count; + + memset(&msg, 0, sizeof(pm_message_t)); + + mutex_lock(&dmt->suspend_mutex); + + if (suspend) { + dmard10_suspend(dmt->pdevice, msg); + dmt->suspend = 1; + } else { + dmard10_resume(dmt->pdevice); + dmt->suspend = 0; + } + + mutex_unlock(&dmt->suspend_mutex); + + return count; +} +/* sysfs reg_read show & store */ +static ssize_t dmt_reg_read_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int err; + unsigned char i2c[1]; + + i2c[0] = (unsigned char)atomic_read(&dmt->addr); + err = device_i2c_rxdata(dmt->client, i2c, 1); + if (err < 0) + return err; + + return sprintf(buf, "0x%02X\n", i2c[0]); +} + +static ssize_t dmt_reg_read_store(struct device *dev, + struct device_attribute *attr, + char const *buf, + size_t count) +{ + struct dmt_data *dmt = dev_get_drvdata(dev); + int addr = 0; + + if (NULL == buf) + return -EINVAL; + + if (0 == count) + return 0; + + if (false == get_value_as_int(buf, count, &addr)) + return -EINVAL; + + if (addr < 0 || 128 < addr) + return -EINVAL; + + atomic_set(&dmt->addr, addr); + + return 1; +} +#endif /* DEBUG */ +/********************************************************************* + * + * SysFS attribute functions + * + * directory : /sys/class/accelemeter/dmardXX/ + * files : + * - enable_acc [rw] [t] : enable flag for accelerometer + * - delay_acc [rw] [t] : delay in nanosecond for accelerometer + * - position [rw] [t] : chip mounting position + * - offset [rw] [t] : offset + * - data [r] [t] : raw data + * - id [r] [t] : chip id + * + * debug : + * - debug_suspend [w] [t] : suspend test + * - reg_read [rw] [t] : Read register + * - reg_write [rw] [t] : Weite register + * + * [rw]= read/write + * [r] = read only + * [w] = write only + * [b] = binary format + * [t] = text format + */ + +static struct device_attribute DMT_attributes[] = { + __ATTR(enable_acc, 0660, dmt_enable_show, dmt_enable_store), + __ATTR(delay_acc, 0660, dmt_delay_show, dmt_delay_store), + __ATTR(position, 0660, dmt_position_show, dmt_position_store), + __ATTR(offset, 0660, dmt_offset_show, dmt_offset_store), + __ATTR(filter, 0660, dmt_filter_show, dmt_filter_store), + __ATTR(data, 0660, dmt_acc_private_data_show, NULL), + __ATTR(id, 0660, dmt_id_show, NULL), +#ifdef DMT_DEBUG_DATA + __ATTR(debug_suspend, 0660, dmt_debug_suspend_show,dmt_debug_suspend_store), + __ATTR(reg_read, 0660, dmt_reg_read_show, dmt_reg_read_store), + __ATTR(reg_write, 0660, NULL, NULL), +#endif // DEBUG + __ATTR_NULL, +}; + +static char const *const ACCELEMETER_CLASS_NAME = "accelemeter"; +static char const *const GSENSOR_DEVICE_NAME = SENSOR_I2C_NAME; +static char const *const device_link_name = "i2c"; +static dev_t const dmt_device_dev_t = MKDEV(MISC_MAJOR, MISC_DYNAMIC_MINOR); + +// dmt sysfs functions +static int create_device_attributes(struct device *dev, struct device_attribute *attrs){ + int i; + int err = 0; + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) { + err = device_create_file(dev, &attrs[i]); + if (0 != err) + break; + } + + if (0 != err) { + for (; i >= 0 ; --i) + device_remove_file(dev, &attrs[i]); + } + return err; +} + +static void remove_device_attributes( + struct device *dev, + struct device_attribute *attrs) +{ + int i; + + for (i = 0 ; NULL != attrs[i].attr.name ; ++i) + device_remove_file(dev, &attrs[i]); +} + +static int create_sysfs_interfaces(struct dmt_data *dmt) +{ + int err; + + if (NULL == dmt) + return -EINVAL; + + err = 0; + dmt->class = class_create(THIS_MODULE, ACCELEMETER_CLASS_NAME); + if (IS_ERR(dmt->class)) { + err = PTR_ERR(dmt->class); + goto exit_class_create_failed; + } + + dmt->class_dev = device_create( + dmt->class, + NULL, + dmt_device_dev_t, + dmt, + GSENSOR_DEVICE_NAME); + if (IS_ERR(dmt->class_dev)) { + err = PTR_ERR(dmt->class_dev); + goto exit_class_device_create_failed; + } + + err = sysfs_create_link( + &dmt->class_dev->kobj, + &dmt->client->dev.kobj, + device_link_name); + if (0 > err) + goto exit_sysfs_create_link_failed; + + err = create_device_attributes( + dmt->class_dev, + DMT_attributes); + if (0 > err) + goto exit_device_attributes_create_failed; +#if 0 + err = create_device_binary_attributes( + &dmt->class_dev->kobj, + dmt_bin_attributes); + if (0 > err) + goto exit_device_binary_attributes_create_failed; +#endif + + return err; + +#if 0 +exit_device_binary_attributes_create_failed: + remove_device_attributes(dmt->class_dev, dmt_attributes); +#endif +exit_device_attributes_create_failed: + sysfs_remove_link(&dmt->class_dev->kobj, device_link_name); +exit_sysfs_create_link_failed: + device_destroy(dmt->class, dmt_device_dev_t); +exit_class_device_create_failed: + dmt->class_dev = NULL; + class_destroy(dmt->class); +exit_class_create_failed: + dmt->class = NULL; + return err; +} + +static void remove_sysfs_interfaces(struct dmt_data *dmt){ + if (NULL == dmt) + return; + + if (NULL != dmt->class_dev) { + + remove_device_attributes( + dmt->class_dev, + DMT_attributes); + sysfs_remove_link( + &dmt->class_dev->kobj, + device_link_name); + dmt->class_dev = NULL; + } + if (NULL != dmt->class) { + device_destroy( + dmt->class, + dmt_device_dev_t); + class_destroy(dmt->class); + dmt->class = NULL; + } +} + +int D10_input_init(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int err = 0; + dmt->input = input_allocate_device(); + if (!dmt->input){ + GSE_ERR("input device allocate ERROR !!\n"); + return -ENOMEM; + } + else + GSE_LOG("input device allocate Success !!\n"); + /* Setup input device */ + //dmt->input->name = SENSOR_I2C_NAME; + set_bit(EV_ABS, dmt->input->evbit); + /* Accelerometer [-78.5, 78.5]m/s2 in Q16 */ + input_set_abs_params(dmt->input, ABS_X, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Y, ABSMIN, ABSMAX, 0, 0); + input_set_abs_params(dmt->input, ABS_Z, ABSMIN, ABSMAX, 0, 0); + /* Set InputDevice Name */ + dmt->input->name = INPUT_NAME_ACC; + /* Register */ + err = input_register_device(dmt->input); + if (err) { + GSE_ERR("input_register_device ERROR !!\n"); + input_free_device(dmt->input); + return err; + } + GSE_LOG("input_register_device SUCCESS %d !! \n",err); + + return err; +} + +int D10_calibrate(struct i2c_client *client) +{ + struct dmt_data *dmt = i2c_get_clientdata(client); + raw_data avg; + int i, j; + long xyz_acc[SENSOR_DATA_SIZE]; + int xyz[SENSOR_DATA_SIZE]; + /* initialize the offset value */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = 0; + /* initialize the accumulation buffer */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_acc[i] = 0; + + for(i = 0; i < AVG_NUM; i++) { + D10_i2c_read_xyz(client, (int *)&xyz); + for(j = 0; j < SENSOR_DATA_SIZE; ++j) + xyz_acc[j] += xyz[j]; + } + /* calculate averages */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + avg.v[i] = xyz_acc[i] / AVG_NUM; + + if(avg.v[2] < 0){ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] + DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE; + } + else{ + dmt->offset.u.x = avg.v[0] ; + dmt->offset.u.y = avg.v[1] ; + dmt->offset.u.z = avg.v[2] - DEFAULT_SENSITIVITY; + return CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE; + } + return 0; +} + +int dmard10_init(struct i2c_client *client){ + unsigned char buffer[7], buffer2[2]; + /* 1. check D10 , VALUE_STADR = 0x55 , VALUE_STAINT = 0xAA */ + buffer[0] = REG_STADR; + buffer2[0] = REG_STAINT; + + device_i2c_rxdata(client, buffer, 2); + device_i2c_rxdata(client, buffer2, 2); + + if( buffer[0] == VALUE_STADR || buffer2[0] == VALUE_STAINT){ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d\n", buffer[0], buffer2[0]); + } + else{ + GSE_LOG(" REG_STADR_VALUE = %d , REG_STAINT_VALUE = %d \n", buffer[0], buffer2[0]); + return -1; + } + /* 2. Powerdown reset */ + buffer[0] = REG_PD; + buffer[1] = VALUE_PD_RST; + device_i2c_txdata(client, buffer, 2); + /* 3. ACTR => Standby mode => Download OTP to parameter reg => Standby mode => Reset data path => Standby mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_ReadOTP; + buffer[3] = MODE_Standby; + buffer[4] = MODE_ResetDataPath; + buffer[5] = MODE_Standby; + device_i2c_txdata(client, buffer, 6); + /* 4. OSCA_EN = 1 ,TSTO = b'000(INT1 = normal, TEST0 = normal) */ + buffer[0] = REG_MISC2; + buffer[1] = VALUE_MISC2_OSCA_EN; + device_i2c_txdata(client, buffer, 2); + /* 5. AFEN = 1(AFE will powerdown after ADC) */ + buffer[0] = REG_AFEM; + buffer[1] = VALUE_AFEM_AFEN_Normal; + buffer[2] = VALUE_CKSEL_ODR_100_204; + buffer[3] = VALUE_INTC; + buffer[4] = VALUE_TAPNS_Ave_4; + buffer[5] = 0x00; // DLYC, no delay timing + buffer[6] = 0x07; // INTD=1 (push-pull), INTA=1 (active high), AUTOT=1 (enable T) + device_i2c_txdata(client, buffer, 7); + /* 6. write TCGYZ & TCGX */ + buffer[0] = REG_WDAL; // REG:0x01 + buffer[1] = 0x00; // set TC of Y,Z gain value + buffer[2] = 0x00; // set TC of X gain value + buffer[3] = 0x03; // Temperature coefficient of X,Y,Z gain + device_i2c_txdata(client, buffer, 4); + + buffer[0] = REG_ACTR; // REG:0x00 + buffer[1] = MODE_Standby; // Standby + buffer[2] = MODE_WriteOTPBuf; // WriteOTPBuf + buffer[3] = MODE_Standby; // Standby + device_i2c_txdata(client, buffer, 4); + //buffer[0] = REG_TCGYZ; + //device_i2c_rxdata(client, buffer, 2); + //GSE_LOG(" TCGYZ = %d, TCGX = %d \n", buffer[0], buffer[1]); + + /* 7. Activation mode */ + buffer[0] = REG_ACTR; + buffer[1] = MODE_Active; + device_i2c_txdata(client, buffer, 2); + return 0; +} + +void D10_set_offset(struct i2c_client *client, int val[3]){ + struct dmt_data *dmt = i2c_get_clientdata(client); + int i; + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->offset.v[i] = val[i]; +} + +struct file_operations sensor_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = device_ioctl, + .open = device_open, + .release = device_close, +}; + +static struct miscdevice dmt_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_I2C_NAME, + .fops = &sensor_fops, +}; + +static int sensor_close_dev(struct i2c_client *client){ + char buffer[3]; + GSE_FUN(); + buffer[0] = REG_AFEM; + buffer[1] = 0x0f; + device_i2c_txdata(client,buffer, 2); + buffer[0] = REG_ACTR; + buffer[1] = MODE_Standby; + buffer[2] = MODE_Off; + device_i2c_txdata(client,buffer, 3); + return 0; +} + +static void dmard10_shutdown(struct platform_device *pdev) +{ + flush_delayed_work_sync(&s_dmt->delaywork); + DMT_sysfs_update_active_status(s_dmt , 0); +} + + +//static int device_i2c_suspend(struct i2c_client *client, pm_message_t mesg){ +static int dmard10_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + flush_delayed_work_sync(&dmt->delaywork); + DMT_sysfs_update_active_status(dmt , 0); + return sensor_close_dev(dmt->client); +} + +//static int device_i2c_resume(struct i2c_client *client){ +static int dmard10_resume(struct platform_device *pdev) +{ + struct dmt_data *dmt = i2c_get_clientdata(s_dmt->client); + int en = 1; + GSE_FUN(); + printk("dmt->enable=%d",dmt->enable); + dmard10_init(dmt->client); + atomic_set(&dmt->enable,en); + DMT_sysfs_update_active_status(dmt , en); + return 0; +} +/* +static int __devexit device_i2c_remove(struct i2c_client *client){ + return 0; +} + +static const struct i2c_device_id device_i2c_ids[] = { + { SENSOR_I2C_NAME, 0}, + { } +}; + +static struct i2c_driver device_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_I2C_NAME, + }, + .class = I2C_CLASS_HWMON, + .id_table = device_i2c_ids, + .probe = device_i2c_probe, + .remove = __devexit_p(device_i2c_remove), +#ifdef CONFIG_HAS_EARLYSUSPEND + .suspend = device_i2c_suspend, + .resume = device_i2c_resume, +#endif +}; +*/ +static int device_open(struct inode *inode, struct file *filp){ + return 0; +} + +static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ + //struct i2c_client *client = (struct i2c_client *)file->private_data; + //struct dmt_data *dmt = (struct dmt_data*)i2c_get_clientdata(client); + + int err = 0, ret = 0, i; + int intBuf[SENSOR_DATA_SIZE], xyz[SENSOR_DATA_SIZE]; + /* check type */ + if (_IOC_TYPE(cmd) != IOCTL_MAGIC) return -ENOTTY; + + /* check user space pointer is valid */ + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + if (err) return -EFAULT; + + switch(cmd) { + case SENSOR_RESET: + ret = dmard10_init(s_dmt->client); + return ret; + + case SENSOR_CALIBRATION: + /* get orientation info */ + //if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) return -EFAULT; + D10_calibrate(s_dmt->client); + GSE_LOG("Sensor_calibration:%d %d %d\n", s_dmt->offset.u.x, s_dmt->offset.u.y, s_dmt->offset.u.z); + /* save file */ + D10_write_offset_to_file(s_dmt->client); + update_var(); + + /* return the offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_GET_OFFSET: + /* get data from file */ + D10_read_offset_from_file(s_dmt->client); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = s_dmt->offset.v[i]; + + ret = copy_to_user((int *)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SET_OFFSET: + ret = copy_from_user(&intBuf, (int *)arg, sizeof(intBuf)); + D10_set_offset(s_dmt->client , intBuf); + /* write into file */ + D10_write_offset_to_file(s_dmt->client); + update_var(); + return ret; + + case SENSOR_READ_ACCEL_XYZ: + D10_i2c_read_xyz(s_dmt->client, (int *)&xyz); + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + intBuf[i] = xyz[i] - s_dmt->offset.v[i]; + + ret = copy_to_user((int*)arg, &intBuf, sizeof(intBuf)); + return ret; + + case SENSOR_SETYPR: + if(copy_from_user(&intBuf, (int*)arg, sizeof(intBuf))) { + GSE_LOG("%s: -EFAULT\n",__func__); + return -EFAULT; + } + input_report_abs(s_dmt->input, ABS_X, intBuf[0]); + input_report_abs(s_dmt->input, ABS_Y, intBuf[1]); + input_report_abs(s_dmt->input, ABS_Z, intBuf[2]); + input_sync(s_dmt->input); + GSE_LOG("SENSOR_SETYPR OK! x=%d,y=%d,z=%d\n",intBuf[0],intBuf[1],intBuf[2]); + return ret; + + case SENSOR_GET_OPEN_STATUS: + GSE_LOG("Going into DMT_GetOpenStatus()\n"); + ret = DMT_GetOpenStatus(s_dmt->client); + return ret; + + case SENSOR_GET_CLOSE_STATUS: + GSE_LOG("Going into DMT_GetCloseStatus()\n"); + ret = DMT_GetCloseStatus(s_dmt->client); + return ret; + + case SENSOR_GET_DELAY: + ret = copy_to_user((int*)arg, &interval, sizeof(interval)); + return ret; + + default: /* redundant, as cmd was checked against MAXNR */ + return -ENOTTY; + } + + return 0; +} + +static int device_close(struct inode *inode, struct file *filp){ + return 0; +} + +/***** I2C I/O function ***********************************************/ +static int device_i2c_rxdata( struct i2c_client *client, unsigned char *rxData, int length){ + struct i2c_msg msgs[] = { + {.addr = client->addr, .flags = 0, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = length, .buf = rxData,}, + }; + //unsigned char addr = rxData[0]; + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "RxData: len=%02x, addr=%02x, data=%02x\n", + //length, addr, rxData[0]); + + return 0; +} + +static int device_i2c_txdata( struct i2c_client *client, unsigned char *txData, int length){ + struct i2c_msg msg[] = { + {.addr = client->addr, .flags = 0, .len = length, .buf = txData,}, + }; + + if (i2c_transfer(client->adapter, msg, 1) < 0) { + dev_err(&client->dev, "%s: transfer failed.", __func__); + return -EIO; + } + //DMT_DATA(&client->dev, "TxData: len=%02x, addr=%02x data=%02x\n", + //length, txData[0], txData[1]); + return 0; +} + +static int D10_i2c_read_xyz(struct i2c_client *client, int *xyz_p){ + struct dmt_data *dmt = i2c_get_clientdata(client); + u8 buffer[11]; + s16 xyzTmp[SENSOR_DATA_SIZE]; + int pos = dmt->position; + int i, j , k; + /* get xyz high/low bytes, 0x12 */ + buffer[0] = REG_STADR; + /* Read acceleration data */ + if (device_i2c_rxdata(client, buffer, 10)!= 0) + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + xyz_p[i] = 0; + else + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + xyz_p[i] = 0; + /* merge xyz high/low bytes & 1g = 128 becomes 1g = 1024 */ + mutex_lock(&dmt->data_mutex); + xyzTmp[i] = ((int16_t)((buffer[2*(i+1)+1] << 8)) | buffer[2*(i+1)] ) << 3; + mutex_unlock(&dmt->data_mutex); + } +#ifdef SW_FILTER + if( dmt->aveflag >= dmt->filter){ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = dmt->sum[i] - dmt->bufferave[i][dmt->pointer] + xyzTmp[i]; + } + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++) + xyz_p[i] += (int)(dmt->sum[j]/dmt->filter * dmt_position_map[pos][i][j]); + } + } + else{ + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->sum[i] = xyzTmp[i]; +#endif + /* transfer to the default layout */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(j = 0; j < SENSOR_DATA_SIZE; j++){ + xyz_p[i] += (int)(xyzTmp[j] * dmt_position_map[pos][i][j]); + //GSE_LOG("%04d, %04d,%d \n", xyz_p[i], xyzTmp[j], dmt_position_map[pos][i][j]); + } + } + //GSE_LOG("xyz_p: %04d , %04d , %04d\n", xyz_p[0], xyz_p[1], xyz_p[2]); +#ifdef SW_FILTER + dmt->aveflag++; + } + /* init dmt->sum */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->sum[i] = 0; + } + dmt->pointer++; + dmt->pointer %= dmt->filter; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + dmt->bufferave[i][dmt->pointer] = xyzTmp[i]; + } + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + for(k = 0; k < dmt->filter; ++k){ + dmt->sum[i] += dmt->bufferave[i][k]; + } + } +#endif + return 0; +} + +static void DMT_work_func(struct work_struct *delaywork){ + struct dmt_data *dmt = container_of(delaywork, struct dmt_data, delaywork.work); + int i; + //static bool firsttime=true; + raw_data xyz; + unsigned long dmt_delay = msecs_to_jiffies(atomic_read(&dmt->delay)); + + + D10_i2c_read_xyz(dmt->client, (int *)&xyz.v); + /* dmt->last = RawData - Offset */ + for(i = 0; i < SENSOR_DATA_SIZE; ++i) + dmt->last.v[i] = xyz.v[i] - dmt->offset.v[i]; + //GSE_LOG("@DMTRaw @ X/Y/Z axis: %04d , %04d , %04d\n", xyz.v[0], xyz.v[1], xyz.v[2]); + //GSE_LOG("@Offset @ X/Y/Z axis: %04d , %04d , %04d\n", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + //GSE_LOG("@Raw-Offset@ X/Y/Z axis: %04d , %04d , %04d ,dmt_delay=%d\n", dmt->last.u.x, dmt->last.u.y, dmt->last.u.z, atomic_read(&dmt->delay)); + + + input_report_abs(dmt->input, ABS_X, dmt->last.v[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]);//dmt->last.v[0]); + input_report_abs(dmt->input, ABS_Y, dmt->last.v[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]);//dmt->last.v[1]); + input_report_abs(dmt->input, ABS_Z, dmt->last.v[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]);//dmt->last.v[2]); + input_sync(dmt->input); + + if(dmt_delay < 1) + dmt_delay = 1; + schedule_delayed_work(&dmt->delaywork, dmt_delay); +} + +static int mma10_open(struct inode *node, struct file *fle) +{ + GSE_LOG("open...\n"); + return 0; +} + +static int mma10_close(struct inode *node, struct file *fle) +{ + GSE_LOG("close...\n"); + return 0; +} + +static long mma10_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int err = 0; + //unsigned char data[6]; + void __user *argp = (void __user *)arg; + short delay, enable; + unsigned int uval = 0; + + + /* cmd mapping */ + switch(cmd) + { + case ECS_IOCTL_APP_SET_DELAY: + // set the rate of g-sensor + if (copy_from_user(&delay, argp, sizeof(short))) + { + printk(KERN_ALERT "Can't get set delay!!!\n"); + return -EFAULT; + } + klog("Get delay=%d\n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + l_sensorconfig.sensor_samp = 1000/delay; + atomic_set(&s_dmt->delay, 1000/delay); + break; + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + klog("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable); + + l_sensorconfig.sensor_enable = enable; + atomic_set(&s_dmt->enable,enable); + DMT_sysfs_update_active_status(s_dmt , enable); + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = DMARD10_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + GSE_LOG("dmard10_driver_id:%d\n",uval); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + uval = (10<<8) | 1; + if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<<resolution:0x%x\n",uval); + default: + err = -1; + break; + } + + return err; +} + +static const struct file_operations d10_fops = { + .owner = THIS_MODULE, + .open = mma10_open, + .release = mma10_close, + .unlocked_ioctl = mma10_ioctl, +}; + + +static struct miscdevice d10_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GSENSOR_DEV_NODE, + .fops = &d10_fops, +}; + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + //mutex_lock(&sense_data_mutex); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + klog("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + atomic_set(&s_dmt->enable,1); + DMT_sysfs_update_active_status(s_dmt , 1); + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + atomic_set(&s_dmt->enable,0); + DMT_sysfs_update_active_status(s_dmt , 0); + } + //mutex_unlock(&sense_data_mutex); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +//static int __devinit device_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id){ +static int __devinit dmard10_probe(struct platform_device *pdev) +{ + int i, k, ret = 0; + //struct dmt_data *s_dmt = i2c_get_clientdata(client); + //struct dmt_data *s_dmt; + GSE_FUN(); +/* + if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){ + GSE_ERR("check_functionality failed.\n"); + ret = -ENODEV; + goto exit0; + } + + // Allocate memory for driver data + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + ret = -ENOMEM; + goto exit1; + } +*/ + /*for(i = 0; i < SENSOR_DATA_SIZE; ++i) + s_dmt->offset.v[i] = 0;*/ +#ifdef SW_FILTER + s_dmt->pointer = 0; + s_dmt->aveflag = 0; + for(i = 0; i < SENSOR_DATA_SIZE; ++i){ + s_dmt->sum[i] = 0; + for(k = 0; k < SENSOR_DATA_AVG; ++k){ + s_dmt->bufferave[i][k] = 0; + } + } + s_dmt->filter = SENSOR_DATA_AVG; + GSE_LOG("D10_DEFAULT_FILTER: %d\n", s_dmt->filter); +#endif + /* I2C initialization */ + //s_dmt->client = client; + + /* set client data */ + i2c_set_clientdata(s_dmt->client, s_dmt); + /*ret = dmard10_init(client); + if (ret < 0) + goto exit2; + */ + /* input */ + ret = D10_input_init(s_dmt->client); + if (ret){ + GSE_ERR("D10_input_init fail, error code= %d\n",ret); + goto exit3; + } + + /* initialize variables in dmt_data */ + mutex_init(&s_dmt->data_mutex); + mutex_init(&s_dmt->enable_mutex); +#ifdef DMT_DEBUG_DATA + mutex_init(&s_dmt->suspend_mutex); +#endif + init_waitqueue_head(&s_dmt->open_wq); + atomic_set(&s_dmt->active, 0); + atomic_set(&s_dmt->enable, 0); + atomic_set(&s_dmt->delay, 0); + atomic_set(&s_dmt->addr, 0); + /* DMT Acceleration Sensor Mounting Position on Board */ + s_dmt->position = D10_DEFAULT_POSITION; + GSE_LOG("D10_DEFAULT_POSITION: %d\n", s_dmt->position); + //s_dmt->position = (CONFIG_INPUT_DMT_ACCELEROMETER_POSITION); + //GSE_LOG("CONFIG_INPUT_DMT_ACCELEROMETER_POSITION: %d\n", s_dmt->position); + /* Misc device */ + if (misc_register(&dmt_device) < 0){ + GSE_ERR("dmt_dev register failed"); + goto exit4; + } + + /* Setup sysfs */ + if (create_sysfs_interfaces(s_dmt) < 0){ + GSE_ERR("create sysfs failed."); + goto exit5; + } +#ifdef CONFIG_HAS_EARLYSUSPEND + s_dmt->early_suspend.suspend = device_i2c_suspend; + s_dmt->early_suspend.resume = device_i2c_resume; + register_early_suspend(&s_dmt->early_suspend); +#endif + /* Setup driver interface */ + INIT_DELAYED_WORK(&s_dmt->delaywork, DMT_work_func); + GSE_LOG("DMT: INIT_DELAYED_WORK\n"); + + //register ctrl dev + ret = misc_register(&d10_device); + if (ret !=0) { + errlog("Can't register d10_device!\n"); + return -1; + } + // register rd/wr proc + l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (l_sensorconfig.sensor_proc != NULL) + { + l_sensorconfig.sensor_proc->write_proc = sensor_writeproc; + l_sensorconfig.sensor_proc->read_proc = sensor_readproc; + } + + //create offset file after factory reset + D10_read_offset_from_file(s_dmt->client); + + return 0; + +exit5: + misc_deregister(&dmt_device); +exit4: + input_unregister_device(s_dmt->input); +exit3: + kfree(s_dmt); +/*exit2: +exit1: +exit0:*/ + return ret; +} +/* +static struct i2c_board_info dmard10_board_info={ + .type = SENSOR_I2C_NAME, + .addr = SENSOR_I2C_ADDR, +}; +*/ +//static struct i2c_client *client; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +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.dm10sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; //open it for no env just,not insmod such module 2014-6-30 + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(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]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + errlog("gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void dmard10_platform_release(struct device *device) +{ + GSE_LOG("...\n"); + return; +} + +static int __devexit dmard10_remove(struct platform_device *pdev) +{ + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + //misc_deregister(&d10_device); + return 0; +} + + +static struct platform_device dmard10_device = { + .name = SENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = dmard10_platform_release, + }, +}; + +static struct platform_driver dmard10_driver = { + .probe = dmard10_probe, + .remove = dmard10_remove, + .shutdown = dmard10_shutdown, + .suspend = dmard10_suspend, + .resume = dmard10_resume, + .driver = { + .name = SENSOR_I2C_NAME, + }, +}; + + +static int __init device_init(void){ + //struct device *device; + struct i2c_client *this_client; + int ret = 0; + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + GSE_LOG("D10 gsensor driver: initialize.\n"); + + if (!(this_client = sensor_i2c_register_device(0, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (dmard10_init(this_client)) + { + GSE_ERR("Failed to init dmard10!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + /* Allocate memory for driver data */ + s_dmt = kzalloc(sizeof(struct dmt_data), GFP_KERNEL); + //memset(s_dmt, 0, sizeof(struct dmt_data)); + if (s_dmt == NULL) { + GSE_ERR("alloc data failed.\n"); + return -ENOMEM; + } + + s_dmt->client = this_client; + s_dmt->pdevice = &dmard10_device; + s_dmt->offset.u.x = l_sensorconfig.offset[0]; + s_dmt->offset.u.y = l_sensorconfig.offset[1]; + s_dmt->offset.u.z = l_sensorconfig.offset[2]; + + + // create the platform device + l_dev_class = class_create(THIS_MODULE, SENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&dmard10_device))) + { + GSE_ERR("Can't register dmard10 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&dmard10_driver)) != 0) + { + GSE_ERR("Can't register dmard10 platform driver!!!\n"); + return ret; + } + + return 0; +} + +static void __exit device_exit(void){ + //i2c_unregister_device(client); + //i2c_del_driver(&device_i2c_driver); + GSE_LOG("D10 gsensor driver: release.\n"); + + flush_delayed_work_sync(&s_dmt->delaywork); + cancel_delayed_work_sync(&s_dmt->delaywork); + + input_unregister_device(s_dmt->input); + input_free_device(s_dmt->input); + misc_deregister(&dmt_device); + misc_deregister(&d10_device); + platform_driver_unregister(&dmard10_driver); + platform_device_unregister(&dmard10_device); + sensor_i2c_unregister_device(s_dmt->client); + class_destroy(l_dev_class); + + remove_sysfs_interfaces(s_dmt); + kfree(s_dmt); +} + +static int dmt_get_filter(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->filter; +} + +static int dmt_set_filter(struct i2c_client *client, int filter){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((filter >= 1) && (filter <= 32))) + return -1; + dmt->filter = filter; + return 0; +} + +static int dmt_get_position(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + return dmt->position; +} + +static int dmt_set_position(struct i2c_client *client, int position){ + struct dmt_data *dmt = i2c_get_clientdata(client); + if (!((position >= 0) && (position <= 7))) + return -1; + dmt->position = position; + return 0; +} + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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], + s_dmt->offset.u.x, + s_dmt->offset.u.y, + s_dmt->offset.u.z + ); + + wmt_setsyspara("wmt.io.dm10sensor",varbuf); +} + +static int D10_write_offset_to_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + char r_buf[18] = {0}; + char w_buf[18] = {0}; + //unsigned int orgfs; + struct file *fp; + mm_segment_t fs; + ssize_t ret; + //int8_t i; + + sprintf(w_buf,"%5d %5d %5d", dmt->offset.u.x, dmt->offset.u.y, dmt->offset.u.z); + /* Set segment descriptor associated to kernel space */ + fp = filp_open(D10_OffsetFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("filp_open %s error!!.\n",D10_OffsetFileName); + return -1; + } + else{ + fs = get_fs(); + //set_fs(KERNEL_DS); + set_fs(get_ds()); + GSE_LOG("filp_open %s SUCCESS!!.\n",D10_OffsetFileName); + //fp->f_op->write(fp,data,18, &fp->f_pos); + //filp_close(fp,NULL); + ret = fp->f_op->write(fp,w_buf,18,&fp->f_pos); + if(ret != 18) + { + printk(KERN_ERR "%s: write error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + //fp->f_pos=0x00; + ret = fp->f_op->read(fp,r_buf, 18,&fp->f_pos); + if(ret < 0) + { + printk(KERN_ERR "%s: read error!\n", __func__); + filp_close(fp,NULL); + return -EIO; + } + set_fs(fs); + + // + //printk(KERN_INFO "%s: read ret=%d!", __func__, ret); + /* for(i=0; i<18 ;i++) + { + if(r_buf[i] != w_buf[i]) + { + printk(KERN_ERR "%s: read back error, r_buf[%x](0x%x) != w_buf[%x](0x%x)\n", + __func__, i, r_buf[i], i, w_buf[i]); + filp_close(fp,NULL); + return -EIO; + } + } + */ + + } + filp_close(fp,NULL); + return 0; +} + +void D10_read_offset_from_file(struct i2c_client *client){ + struct dmt_data *dmt = i2c_get_clientdata(client); + unsigned int orgfs; + char data[18]; + struct file *fp; + int ux,uy,uz; + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + + fp = filp_open(D10_OffsetFileName, O_RDWR , 0); + GSE_FUN(); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + if(l_sensorconfig.op){ //first time + l_sensorconfig.op=0; +#if AUTO_CALIBRATION + /* get acceleration average reading */ + D10_calibrate(client); + update_var(); + D10_write_offset_to_file(client); +#endif +#ifdef DMT_BROADCAST_APK_ENABLE + create_devidfile(); + return; +#endif + } + D10_write_offset_to_file(client); + } + else{ + GSE_LOG("filp_open %s SUCCESS!!.\n",D10_OffsetFileName); + fp->f_op->read(fp,data,18, &fp->f_pos); + GSE_LOG("filp_read result %s\n",data); + sscanf(data,"%d %d %d",&ux,&uy,&uz); + dmt->offset.u.x=ux; + dmt->offset.u.y=uy; + dmt->offset.u.z=uz; + } + set_fs(orgfs); +} +static int create_devidfile(void) +{ + char data[18]; + unsigned int orgfs; + struct file *fp; + + sprintf(data,"%5d %5d %5d",0,0,0); + orgfs = get_fs(); + /* Set segment descriptor associated to kernel space */ + set_fs(KERNEL_DS); + GSE_FUN(); + fp = filp_open(DmtXXFileName, O_RDWR | O_CREAT, 0777); + if(IS_ERR(fp)){ + GSE_ERR("Sorry,file open ERROR !\n"); + return -1; + } + fp->f_op->write(fp,data,18, &fp->f_pos); + set_fs(orgfs); + filp_close(fp,NULL); + return 0; +} +//********************************************************************************************************* +MODULE_AUTHOR("DMT_RD"); +MODULE_DESCRIPTION("DMT Gsensor Driver"); +MODULE_LICENSE("GPL"); + +module_init(device_init); +module_exit(device_exit); diff --git a/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h new file mode 100755 index 00000000..f77b07e3 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/dmard10_gsensor/dmt10.h @@ -0,0 +1,192 @@ +/* @version 1.03 + * Copyright 2011 Domintech Technology Co., Ltd + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef DMT10_H +#define DMT10_H +#include <linux/types.h> +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/mutex.h> +#include <linux/syscalls.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/delay.h> +//#include <linux/earlysuspend.h> +#define AUTO_CALIBRATION 0 +#define SW_FILTER /* Enable or Disable Software filter */ +#define SENSOR_DATA_AVG 8 /* AVG sensor data */ + +//#define DMT_DEBUG_DATA +#define GSE_TAG "[DMT_Gsensor]" +#ifdef DMT_DEBUG_DATA +#define GSE_ERR(fmt, args...) printk(KERN_ERR GSE_TAG"%s %d : "fmt, __FUNCTION__, __LINE__, ##args) +#define GSE_LOG(fmt, args...) printk(KERN_INFO GSE_TAG fmt, ##args) +#define GSE_FUN(f) printk(KERN_INFO GSE_TAG" %s: %s: %i\n", __FILE__, __func__, __LINE__) +#define DMT_DATA(dev, ...) dev_dbg((dev), ##__VA_ARGS__) +#else +#define GSE_ERR(fmt, args...) +#define GSE_LOG(fmt, args...) +#define GSE_FUN(f) +#define DMT_DATA(dev, format, ...) +#endif + +#define GSENSOR_ID "DMARD10" +#define INPUT_NAME_ACC "g-sensor"//"DMT_accel"//"g-sensor"// /* Input Device Name */ +#define SENSOR_I2C_NAME "dmard10"//"dmt"// /* Device name for DMARD10 misc. device */ +#define SENSOR_I2C_ADDR 0x18 +#define REG_ACTR 0x00 +#define REG_WDAL 0x01 +#define REG_TAPNS 0x0f +#define REG_MISC2 0x1f +#define REG_AFEM 0x0c +#define REG_CKSEL 0x0d +#define REG_INTC 0x0e +#define REG_STADR 0x12 +#define REG_STAINT 0x1C +#define REG_PD 0x21 +#define REG_TCGYZ 0x26 +#define REG_X_OUT 0x41 + +#define MODE_Off 0x00 +#define MODE_ResetAtOff 0x01 +#define MODE_Standby 0x02 +#define MODE_ResetAtStandby 0x03 +#define MODE_Active 0x06 +#define MODE_Trigger 0x0a +#define MODE_ReadOTP 0x12 +#define MODE_WriteOTP 0x22 +#define MODE_WriteOTPBuf 0x42 +#define MODE_ResetDataPath 0x82 + +#define VALUE_STADR 0x55 +#define VALUE_STAINT 0xAA +#define VALUE_AFEM_AFEN_Normal 0x8f// AFEN set 1 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_AFEM_Normal 0x0f// AFEN set 0 , ATM[2:0]=b'000(normal),EN_Z/Y/X/T=1 +#define VALUE_INTC 0x00// INTC[6:5]=b'00 +#define VALUE_INTC_Interrupt_En 0x20// INTC[6:5]=b'01 (Data ready interrupt enable, active high at INT0) +#define VALUE_CKSEL_ODR_0_204 0x04// ODR[3:0]=b'0000 (0.78125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_1_204 0x14// ODR[3:0]=b'0001 (1.5625Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_3_204 0x24// ODR[3:0]=b'0010 (3.125Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_6_204 0x34// ODR[3:0]=b'0011 (6.25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_12_204 0x44// ODR[3:0]=b'0100 (12.5Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_25_204 0x54// ODR[3:0]=b'0101 (25Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_50_204 0x64// ODR[3:0]=b'0110 (50Hz), CCK[3:0]=b'0100 (204.8kHZ) +#define VALUE_CKSEL_ODR_100_204 0x74// ODR[3:0]=b'0111 (100Hz), CCK[3:0]=b'0100 (204.8kHZ) + +#define VALUE_TAPNS_NoFilter 0x00 // TAP1/TAP2 NO FILTER +#define VALUE_TAPNS_Ave_2 0x11 // TAP1/TAP2 Average 2 +#define VALUE_TAPNS_Ave_4 0x22 // TAP1/TAP2 Average 4 +#define VALUE_TAPNS_Ave_8 0x33 // TAP1/TAP2 Average 8 +#define VALUE_TAPNS_Ave_16 0x44 // TAP1/TAP2 Average 16 +#define VALUE_TAPNS_Ave_32 0x55 // TAP1/TAP2 Average 32 +#define VALUE_MISC2_OSCA_EN 0x08 +#define VALUE_PD_RST 0x52 + +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_NEGATIVE 1 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Z_POSITIVE 2 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_NEGATIVE 3 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_Y_POSITIVE 4 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_NEGATIVE 5 +#define CONFIG_GSEN_CALIBRATION_GRAVITY_ON_X_POSITIVE 6 + +#define AVG_NUM 16 +#define SENSOR_DATA_SIZE 3 +#define DEFAULT_SENSITIVITY 1024 + +#define IOCTL_MAGIC 0x09 +#define SENSOR_RESET _IO(IOCTL_MAGIC, 0) +#define SENSOR_CALIBRATION _IOWR(IOCTL_MAGIC, 1, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OFFSET _IOR(IOCTL_MAGIC, 2, int[SENSOR_DATA_SIZE]) +#define SENSOR_SET_OFFSET _IOWR(IOCTL_MAGIC, 3, int[SENSOR_DATA_SIZE]) +#define SENSOR_READ_ACCEL_XYZ _IOR(IOCTL_MAGIC, 4, int[SENSOR_DATA_SIZE]) +#define SENSOR_SETYPR _IOW(IOCTL_MAGIC, 5, int[SENSOR_DATA_SIZE]) +#define SENSOR_GET_OPEN_STATUS _IO(IOCTL_MAGIC, 6) +#define SENSOR_GET_CLOSE_STATUS _IO(IOCTL_MAGIC, 7) +#define SENSOR_GET_DELAY _IOR(IOCTL_MAGIC, 8, unsigned int*) +#define SENSOR_MAXNR 8 +/* Default sensorlayout parameters */ +#define D10_DEFAULT_POSITION 6 + +/* Transformation matrix for chip mounting position */ +static const int dmt_position_map[][3][3] = { + { { 1, 0, 0}, { 0,-1, 0}, { 0, 0,-1}, }, /* top/upper-left */ + { { 0, 1, 0}, { 1, 0, 0}, { 0, 0,-1}, }, /* top/lower-left */ + { {-1, 0, 0}, { 0, 1, 0}, { 0, 0,-1}, }, /* top/lower-right */ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0,-1}, }, /* top/upper-right */ + { {-1, 0, 0}, { 0,-1, 0}, { 0, 0, 1}, }, /* bottom/upper-right*/ + { { 0,-1, 0}, {-1, 0, 0}, { 0, 0, 1}, }, /* bottom/upper-left */ + { { 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}, }, /* bottom/lower-right*/ + { { 0, 1,0}, { 1, 0, 0}, { 0, 0, 1}, }, /* bottom/lower-left */ +}; + +typedef union { + struct { + int x; + int y; + int z; + } u; + int v[SENSOR_DATA_SIZE]; +} raw_data; + +struct dmt_data { + struct platform_device *pdevice; + struct device *class_dev; + struct class *class; + struct input_dev *input; + struct i2c_client *client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + struct delayed_work delaywork; + struct work_struct work; + struct mutex data_mutex; + struct mutex enable_mutex; /* for suspend */ + raw_data last; /* RawData */ + raw_data offset; /* Offset */ +#ifdef SW_FILTER + int sum[SENSOR_DATA_SIZE]; /* SW_FILTER sum */ + int bufferave[3][32]; + s8 aveflag; /* FULL bufferave[][] */ + s8 pointer; /* last update data */ +#endif + wait_queue_head_t open_wq; + atomic_t active; + atomic_t delay; + atomic_t enable; + int filter; + int position; /* must int type ,for Kconfig setup */ + atomic_t addr; +#ifdef DMT_DEBUG_DATA + struct mutex suspend_mutex; + int suspend; +#endif +}; + +#define ACC_DATA_FLAG 0 +#define MAG_DATA_FLAG 1 +#define ORI_DATA_FLAG 2 +#define DMT_NUM_SENSORS 3 + +/* ABS axes parameter range [um/s^2] (for input event) */ +#define GRAVITY_EARTH 9806550 +#define ABSMAX (GRAVITY_EARTH * 2) +#define ABSMIN (-GRAVITY_EARTH * 2) + +#endif diff --git a/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile new file mode 100755 index 00000000..ac959091 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_lsensor_isl29023
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := isl29023.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c new file mode 100755 index 00000000..3366e92a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/isl29023_lsensor/isl29023.c @@ -0,0 +1,1164 @@ +/*
+ * isl29023.c - Intersil ISL29023 ALS & Proximity Driver
+ *
+ * By Intersil Corp
+ * Michael DiGioia
+ *
+ * Based on isl29011.c
+ * by Mike DiGioia <mdigioia@intersil.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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; version 2 of the License.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/hwmon.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/input-polldev.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+//#include <linux/earlysuspend.h>
+#include <linux/platform_device.h>
+#include "../sensor.h"
+
+/* Insmod parameters */
+//I2C_CLIENT_INSMOD_1(isl29023);
+
+#define MODULE_NAME "isl29023"
+
+#define SENSOR_I2C_NAME "isl29023"
+#define SENSOR_I2C_ADDR 0x44
+
+#undef dbg
+#define dbg(fmt, args...)
+
+#undef errlog
+#undef klog
+#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args)
+#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+
+/* ICS932S401 registers */
+#define ISL29023_REG_VENDOR_REV 0x06
+#define ISL29023_VENDOR 1
+#define ISL29023_VENDOR_MASK 0x0F
+#define ISL29023_REV 4
+#define ISL29023_REV_SHIFT 4
+#define ISL29023_REG_DEVICE 0x44
+#define ISL29023_DEVICE 44
+
+
+#define REG_CMD_1 0x00
+#define REG_CMD_2 0x01
+#define REG_DATA_LSB 0x02
+#define REG_DATA_MSB 0x03
+#define ISL_MOD_MASK 0xE0
+#define ISL_MOD_POWERDOWN 0
+#define ISL_MOD_ALS_ONCE 1
+#define ISL_MOD_IR_ONCE 2
+#define ISL_MOD_RESERVED 4
+#define ISL_MOD_ALS_CONT 5
+#define ISL_MOD_IR_CONT 6
+#define IR_CURRENT_MASK 0xC0
+#define IR_FREQ_MASK 0x30
+#define SENSOR_RANGE_MASK 0x03
+#define ISL_RES_MASK 0x0C
+
+static int last_mod;
+
+static struct i2c_client *this_client = NULL;
+struct isl_device {
+ struct input_polled_dev* input_poll_dev;
+ struct i2c_client* client;
+ int resolution;
+ int range;
+ int isdbg;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend earlysuspend; +#endif +
+};
+
+static struct isl_device* l_sensorconfig = NULL;
+static struct kobject *android_lsensor_kobj = NULL;
+static int l_enable = 1; // 0:don't report data
+
+static DEFINE_MUTEX(mutex);
+
+static int isl_set_range(struct i2c_client *client, int range)
+{
+ int ret_val;
+
+ ret_val = i2c_smbus_read_byte_data(client, REG_CMD_2);
+ if (ret_val < 0)
+ return -EINVAL;
+ ret_val &= ~SENSOR_RANGE_MASK; /*reset the bit */
+ ret_val |= range;
+ ret_val = i2c_smbus_write_byte_data(client, REG_CMD_2, ret_val);
+
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 set_range call, \n", __func__);
+ if (ret_val < 0)
+ return ret_val;
+ return range;
+}
+
+static int isl_set_mod(struct i2c_client *client, int mod)
+{
+ int ret, val, freq;
+
+ switch (mod) {
+ case ISL_MOD_POWERDOWN:
+ case ISL_MOD_RESERVED:
+ goto setmod;
+ case ISL_MOD_ALS_ONCE:
+ case ISL_MOD_ALS_CONT:
+ freq = 0;
+ break;
+ case ISL_MOD_IR_ONCE:
+ case ISL_MOD_IR_CONT:
+ freq = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* set IR frequency */
+ val = i2c_smbus_read_byte_data(client, REG_CMD_2);
+ if (val < 0)
+ return -EINVAL;
+ val &= ~IR_FREQ_MASK;
+ if (freq)
+ val |= IR_FREQ_MASK;
+ ret = i2c_smbus_write_byte_data(client, REG_CMD_2, val);
+ if (ret < 0)
+ return -EINVAL;
+
+setmod:
+ /* set operation mod */
+ val = i2c_smbus_read_byte_data(client, REG_CMD_1);
+ if (val < 0)
+ return -EINVAL;
+ val &= ~ISL_MOD_MASK;
+ val |= (mod << 5);
+ ret = i2c_smbus_write_byte_data(client, REG_CMD_1, val);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (mod != ISL_MOD_POWERDOWN)
+ last_mod = mod;
+
+ return mod;
+}
+
+static int isl_get_res(struct i2c_client *client)
+{
+ int val;
+
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 get_res call, \n", __func__);
+ val = i2c_smbus_read_word_data(client, 0)>>8 & 0xff;
+
+ if (val < 0)
+ return -EINVAL;
+
+ val &= ISL_RES_MASK;
+ val >>= 2;
+
+ switch (val) {
+ case 0:
+ return 65536;
+ case 1:
+ return 4096;
+ case 2:
+ return 256;
+ case 3:
+ return 16;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int isl_get_mod(struct i2c_client *client)
+{
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, REG_CMD_1);
+ if (val < 0)
+ return -EINVAL;
+ return val >> 5;
+}
+
+static int isl_get_range(struct i2c_client* client)
+{
+ switch (i2c_smbus_read_word_data(client, 0)>>8 & 0xff & 0x3) {
+ case 0: return 1000;
+ case 1: return 4000;
+ case 2: return 16000;
+ case 3: return 64000;
+ default: return -EINVAL;
+ }
+}
+
+static ssize_t
+isl_sensing_range_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val;
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ val = i2c_smbus_read_byte_data(client, REG_CMD_2);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ dev_dbg(dev, "%s: range: 0x%.2x\n", __func__, val);
+
+ if (val < 0)
+ return val;
+ return sprintf(buf, "%d000\n", 1 << (2 * (val & 3)));
+}
+
+static ssize_t
+ir_current_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val;
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ val = i2c_smbus_read_byte_data(client, REG_CMD_2);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ dev_dbg(dev, "%s: IR current: 0x%.2x\n", __func__, val);
+
+ if (val < 0)
+ return -EINVAL;
+ val >>= 6;
+
+ switch (val) {
+ case 0:
+ val = 100;
+ break;
+ case 1:
+ val = 50;
+ break;
+ case 2:
+ val = 25;
+ break;
+ case 3:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (val)
+ val = sprintf(buf, "%d\n", val);
+ else
+ val = sprintf(buf, "%s\n", "12.5");
+ return val;
+}
+
+static ssize_t
+isl_sensing_mod_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+// struct i2c_client *client = to_i2c_client(dev);
+
+ dev_dbg(dev, "%s: mod: 0x%.2x\n", __func__, last_mod);
+
+ switch (last_mod) {
+ case ISL_MOD_POWERDOWN:
+ return sprintf(buf, "%s\n", "0-Power-down");
+ case ISL_MOD_ALS_ONCE:
+ return sprintf(buf, "%s\n", "1-ALS once");
+ case ISL_MOD_IR_ONCE:
+ return sprintf(buf, "%s\n", "2-IR once");
+ case ISL_MOD_RESERVED:
+ return sprintf(buf, "%s\n", "4-Reserved");
+ case ISL_MOD_ALS_CONT:
+ return sprintf(buf, "%s\n", "5-ALS continuous");
+ case ISL_MOD_IR_CONT:
+ return sprintf(buf, "%s\n", "6-IR continuous");
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t
+isl_output_data_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret_val, mod;
+ unsigned long int output = 0;
+ int temp;
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+
+ temp = i2c_smbus_read_byte_data(client, REG_DATA_MSB);
+ if (temp < 0)
+ goto err_exit;
+ ret_val = i2c_smbus_read_byte_data(client, REG_DATA_LSB);
+ if (ret_val < 0)
+ goto err_exit;
+ ret_val |= temp << 8;
+
+ dev_dbg(dev, "%s: Data: %04x\n", __func__, ret_val);
+
+ mod = isl_get_mod(client);
+ switch (last_mod) {
+ case ISL_MOD_ALS_CONT:
+ case ISL_MOD_ALS_ONCE:
+ case ISL_MOD_IR_ONCE:
+ case ISL_MOD_IR_CONT:
+ output = ret_val;
+ break;
+ default:
+ goto err_exit;
+ }
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ return sprintf(buf, "%ld\n", output);
+
+err_exit:
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ return -EINVAL;
+}
+
+static int isl_get_lux_data(struct i2c_client* client)
+{
+ struct isl_device* idev = i2c_get_clientdata(client);
+
+ __u16 resH, resL;
+ //int range;
+ resL = i2c_smbus_read_word_data(client, 1)>>8;
+ resH = i2c_smbus_read_word_data(client, 2)&0xff00;
+ if ((resL < 0) || (resH < 0))
+ {
+ errlog("Error to read lux_data!\n");
+ return -1;
+ }
+ return (resH | resL) * idev->range / idev->resolution;
+}
+static ssize_t
+isl_lux_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ __u16 resH, resL;// L1, L2, H1, H2, thresL, thresH;
+ char cmd2;
+ int res, data, tmp, range, resolution;
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+
+// cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff; // 01h
+ resL = i2c_smbus_read_word_data(client, 1)>>8; // 02h
+ resH = i2c_smbus_read_word_data(client, 2)&0xff00; // 03h
+// L1 = i2c_smbus_read_word_data(client, 3)>>8; // 04h
+// L2 = i2c_smbus_read_word_data(client, 4)&0xff00; // 05h
+// H1 = i2c_smbus_read_word_data(client, 5)>>8; // 06h
+// H2 = i2c_smbus_read_word_data(client, 6)&0xff00; // 07h
+
+ res = resH | resL;
+// thresL = L2 | L1;
+// thresH = H2 | H1;
+
+ cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff;
+ resolution = isl_get_res(client); //resolution
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ tmp = cmd2 & 0x3; //range
+ switch (tmp) {
+ case 0:
+ range = 1000;
+ break;
+ case 1:
+ range = 4000;
+ break;
+ case 2:
+ range = 16000;
+ break;
+ case 3:
+ range = 64000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ data = res * range / resolution;
+
+// printk("Data = 0x%04x [%d]\n", data, data);
+// printk("CMD2 = 0x%x\n", cmd2);
+// printk("Threshold Low = 0x%04x\n", thresL);
+// printk("Threshold High = 0x%04x\n", thresH);
+
+ return sprintf(buf, "%u\n", data);
+}
+
+static ssize_t
+isl_cmd2_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned long cmd2;
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ cmd2 = i2c_smbus_read_word_data(client, 0)>>8 & 0xff;
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ dbg(" cmd2: 0x%02x\n", cmd2);
+ switch (cmd2) {
+ case 0:
+ return sprintf(buf, "%s\n", "[cmd2 = 0] n = 16, range = 1000");
+ case 1:
+ return sprintf(buf, "%s\n", "[cmd2 = 1] n = 16, range = 4000");
+ case 2:
+ return sprintf(buf, "%s\n", "[cmd2 = 2] n = 16, range = 16000");
+ case 3:
+ return sprintf(buf, "%s\n", "[cmd2 = 3] n = 16, range = 64000");
+
+ case 4:
+ return sprintf(buf, "%s\n", "[cmd2 = 4] n = 12, range = 1000");
+ case 5:
+ return sprintf(buf, "%s\n", "[cmd2 = 5] n = 12, range = 4000");
+ case 6:
+ return sprintf(buf, "%s\n", "[cmd2 = 6] n = 12, range = 16000");
+ case 7:
+ return sprintf(buf, "%s\n", "[cmd2 = 7] n = 12, range = 64000");
+
+ case 8:
+ return sprintf(buf, "%s\n", "[cmd2 = 8] n = 8, range = 1000");
+ case 9:
+ return sprintf(buf, "%s\n", "[cmd2 = 9] n = 8, range = 4000");
+ case 10:
+ return sprintf(buf, "%s\n", "[cmd2 = 10] n = 8, range = 16000");
+ case 11:
+ return sprintf(buf, "%s\n", "[cmd2 = 11] n = 8, range = 64000");
+
+ case 12:
+ return sprintf(buf, "%s\n", "[cmd2 = 12] n = 4, range = 1000");
+ case 13:
+ return sprintf(buf, "%s\n", "[cmd2 = 13] n = 4, range = 4000");
+ case 14:
+ return sprintf(buf, "%s\n", "[cmd2 = 14] n = 4, range = 16000");
+ case 15:
+ return sprintf(buf, "%s\n", "[cmd2 = 15] n = 4, range = 64000");
+
+ default:
+ return -EINVAL;
+ }
+}
+
+
+static ssize_t
+isl_sensing_range_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned int ret_val;
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ switch (val) {
+ case 1000:
+ val = 0;
+ break;
+ case 4000:
+ val = 1;
+ break;
+ case 16000:
+ val = 2;
+ break;
+ case 64000:
+ val = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ ret_val = isl_set_range(client, val);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ if (ret_val < 0)
+ return ret_val;
+ return count;
+}
+
+static ssize_t
+ir_current_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned int ret_val;
+ unsigned long val;
+
+ if (!strncmp(buf, "12.5", 4))
+ val = 3;
+ else {
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+ switch (val) {
+ case 100:
+ val = 0;
+ break;
+ case 50:
+ val = 1;
+ break;
+ case 25:
+ val = 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+
+ ret_val = i2c_smbus_read_byte_data(client, REG_CMD_2);
+ if (ret_val < 0)
+ goto err_exit;
+
+ ret_val &= ~IR_CURRENT_MASK; /*reset the bit before setting them */
+ ret_val |= (val << 6);
+
+ ret_val = i2c_smbus_write_byte_data(client, REG_CMD_2, ret_val);
+ if (ret_val < 0)
+ goto err_exit;
+
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ return count;
+
+err_exit:
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ return -EINVAL;
+}
+
+static ssize_t
+isl_sensing_mod_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int ret_val;
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+ if (val > 7)
+ return -EINVAL;
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ ret_val = isl_set_mod(client, val);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ if (ret_val < 0)
+ return ret_val;
+ return count;
+}
+
+static ssize_t
+isl_cmd2_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct isl_device* idev = i2c_get_clientdata(client);
+ int res;
+ unsigned long val;
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+ if (val > 15 || val < 0)
+ return -EINVAL;
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ res = i2c_smbus_write_byte_data(client, REG_CMD_2, val);
+ if (res < 0)
+ printk("Warning - write failed\n");
+
+ idev->resolution = isl_get_res(client);
+ idev->range = isl_get_range(client);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(range, S_IRUGO | S_IWUSR,
+ isl_sensing_range_show, isl_sensing_range_store);
+static DEVICE_ATTR(mod, S_IRUGO | S_IWUSR,
+ isl_sensing_mod_show, isl_sensing_mod_store);
+static DEVICE_ATTR(ir_current, S_IRUGO | S_IWUSR,
+ ir_current_show, ir_current_store);
+static DEVICE_ATTR(output, S_IRUGO, isl_output_data_show, NULL);
+static DEVICE_ATTR(cmd2, S_IRUGO | S_IWUSR,
+ isl_cmd2_show, isl_cmd2_store);
+static DEVICE_ATTR(lux, S_IRUGO,
+ isl_lux_show, NULL);
+
+static struct attribute *mid_att_isl[] = {
+ &dev_attr_range.attr,
+ &dev_attr_mod.attr,
+ &dev_attr_ir_current.attr,
+ &dev_attr_output.attr,
+ &dev_attr_lux.attr,
+ &dev_attr_cmd2.attr,
+ NULL
+};
+
+static struct attribute_group m_isl_gr = {
+ .name = "isl29023",
+ .attrs = mid_att_isl
+};
+
+static int isl_set_default_config(struct i2c_client *client)
+{
+ struct isl_device* idev = i2c_get_clientdata(client);
+
+ int ret=0;
+/* We don't know what it does ... */
+// ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xE0);
+// ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0xC3);
+/* Set default to ALS continuous */
+ ret = i2c_smbus_write_byte_data(client, REG_CMD_1, 0xA0);
+ if (ret < 0)
+ return -EINVAL;
+/* Range: 0~16000, number of clock cycles: 65536 */
+ ret = i2c_smbus_write_byte_data(client, REG_CMD_2, 0x02); // vivienne
+ if (ret < 0)
+ return -EINVAL;
+ idev->resolution = isl_get_res(client);
+ idev->range = isl_get_range(client);;
+ dbg("isl29023 set_default_config call, \n");
+
+ return 0;
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int isl29023_detect(struct i2c_client *client/*, int kind,
+ struct i2c_board_info *info*/)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int vendor, device, revision;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+ //printk(KERN_INFO MODULE_NAME ": %s isl29023 detact call, kind:%d type:%s addr:%x \n", __func__, kind, info->type, info->addr);
+
+ /* if (kind <= 0)*/ {
+
+
+ vendor = i2c_smbus_read_word_data(client,
+ ISL29023_REG_VENDOR_REV);
+ dbg("read vendor=%d(0x%x)\n", vendor,vendor);
+ if (0x0FFFF == vendor)
+ {
+ dbg("find isl29023!\n");
+ return 0;
+ } else {
+ return -ENODEV;
+ }
+ vendor >>= 8;
+ revision = vendor >> ISL29023_REV_SHIFT;
+ vendor &= ISL29023_VENDOR_MASK;
+ if (vendor != ISL29023_VENDOR)
+ {
+ dbg("real_vendor=0x%x,tvendor=0x%x\n",vendor,ISL29023_VENDOR);
+ return -ENODEV;
+ }
+
+ device = i2c_smbus_read_word_data(client,
+ ISL29023_REG_DEVICE);
+ dbg("device=%x\n", device);
+ device >>= 8;
+ if (device != ISL29023_DEVICE)
+ {
+ dbg("real_device=0x%x, tdevice=0x%x\n", device, ISL29023_DEVICE);
+ return -ENODEV;
+ }
+
+ if (revision != ISL29023_REV)
+ {
+ dbg("Unknown revision %d\n",
+ revision);
+ }
+ } /*else
+ dev_dbg(&adapter->dev, "detection forced\n");*/
+
+ // strlcpy(info->type, "isl29023", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+int isl_input_open(struct input_dev* input)
+{
+ return 0;
+}
+
+void isl_input_close(struct input_dev* input)
+{
+}
+
+static void isl_input_lux_poll(struct input_polled_dev *dev)
+{
+ struct isl_device* idev = dev->private;
+ struct input_dev* input = idev->input_poll_dev->input;
+ struct i2c_client* client = idev->client;
+
+ if (l_enable != 0)
+ {
+ mutex_lock(&mutex);
+ //pm_runtime_get_sync(dev);
+ input_report_abs(input, ABS_MISC, isl_get_lux_data(client));
+ input_sync(input);
+ //pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ }
+}
+
+static struct i2c_device_id isl29023_id[] = {
+ {"isl29023", 0},
+ {}
+};
+
+static int isl29023_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ dev_dbg(dev, "suspend\n");
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ isl_set_mod(client, ISL_MOD_POWERDOWN);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 suspend call, \n", __func__);
+ return 0;
+}
+
+static int isl29023_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ dev_dbg(dev, "resume\n");
+
+ mutex_lock(&mutex);
+ pm_runtime_get_sync(dev);
+ isl_set_mod(client, last_mod);
+ pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 resume call, \n", __func__);
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(i2c, isl29023_id);
+
+/*static const struct dev_pm_ops isl29023_pm_ops = {
+ .runtime_suspend = isl29023_runtime_suspend,
+ .runtime_resume = isl29023_runtime_resume,
+};
+
+static struct i2c_board_info isl_info = {
+ I2C_BOARD_INFO("isl29023", 0x44),
+};
+
+static struct i2c_driver isl29023_driver = {
+ .driver = {
+ .name = "isl29023",
+ .pm = &isl29023_pm_ops,
+ },
+ .probe = isl29023_probe,
+ .remove = isl29023_remove,
+ .id_table = isl29023_id,
+ .detect = isl29023_detect,
+ //.address_data = &addr_data,
+};*/
+
+static int mmad_open(struct inode *inode, struct file *file)
+{
+ dbg("Open the l-sensor node...\n");
+ return 0;
+}
+
+static int mmad_release(struct inode *inode, struct file *file)
+{
+ dbg("Close the l-sensor node...\n");
+ return 0;
+}
+
+static ssize_t mmad_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf)
+{
+ int lux_data = 0;
+
+ mutex_lock(&mutex);
+ lux_data = isl_get_lux_data(l_sensorconfig->client);
+ mutex_unlock(&mutex);
+ if (lux_data < 0)
+ {
+ errlog("Failed to read lux data!\n");
+ return -1;
+ }
+ copy_to_user(buf, &lux_data, sizeof(lux_data));
+ return sizeof(lux_data);
+}
+
+static long
+mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ //char rwbuf[5];
+ short enable; //amsr = -1;
+ unsigned int uval;
+
+ dbg("l-sensor ioctr...\n");
+ //memset(rwbuf, 0, sizeof(rwbuf));
+ switch (cmd) {
+ case LIGHT_IOCTL_SET_ENABLE:
+ // enable/disable sensor
+ if (copy_from_user(&enable, argp, sizeof(short)))
+ {
+ printk(KERN_ERR "Can't get enable flag!!!\n");
+ return -EFAULT;
+ }
+ dbg("enable=%d\n",enable);
+ if ((enable >=0) && (enable <=1))
+ {
+ dbg("driver: disable/enable(%d) gsensor.\n", enable);
+
+ //l_sensorconfig.sensor_enable = enable;
+ dbg("Should to implement d/e the light sensor!\n");
+ l_enable = enable;
+
+ } else {
+ printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ break;
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = ISL29023_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ dbg("Isl29023_driver_id:%d\n",uval);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static struct file_operations mmad_fops = {
+ .owner = THIS_MODULE,
+ .open = mmad_open,
+ .release = mmad_release,
+ .read = mmad_read,
+ .unlocked_ioctl = mmad_ioctl,
+};
+
+
+static struct miscdevice mmad_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lsensor_ctrl",
+ .fops = &mmad_fops,
+};
+
+static void isl29023_early_suspend(struct early_suspend *h)
+{ + struct i2c_client *client = l_sensorconfig->client;
+
+ dbg("start\n");
+ mutex_lock(&mutex);
+ //pm_runtime_get_sync(dev);
+ isl_set_mod(client, ISL_MOD_POWERDOWN);
+ //pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ dbg("exit\n");
+} + +static void isl29023_late_resume(struct early_suspend *h)
+{
+ struct i2c_client *client = l_sensorconfig->client;
+
+ dbg("start\n");
+ mutex_lock(&mutex);
+ //pm_runtime_get_sync(dev);
+ isl_set_mod(client, last_mod);
+ isl_set_default_config(client);
+ //pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ dbg("exit\n");
+} +
+
+static int
+isl29023_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/)
+{
+ int res=0;
+
+ struct isl_device* idev = kzalloc(sizeof(struct isl_device), GFP_KERNEL);
+ if(!idev)
+ return -ENOMEM;
+
+ l_sensorconfig = idev;
+ android_lsensor_kobj = kobject_create_and_add("android_lsensor", NULL);
+ if (android_lsensor_kobj == NULL) {
+ errlog(
+ "lsensor_sysfs_init:"\
+ "subsystem_register failed\n");
+ res = -ENOMEM;
+ goto err_kobjetc_create;
+ }
+ res = sysfs_create_group(android_lsensor_kobj, &m_isl_gr);
+ if (res) {
+ //pr_warn("isl29023: device create file failed!!\n");
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 device create file failed\n", __func__);
+ res = -EINVAL;
+ goto err_sysfs_create;
+ }
+
+/* last mod is ALS continuous */
+ last_mod = 5;
+ //pm_runtime_enable(&client->dev);
+ idev->input_poll_dev = input_allocate_polled_device();
+ if(!idev->input_poll_dev)
+ {
+ res = -ENOMEM;
+ goto err_input_allocate_device;
+ }
+ idev->client = client;
+ idev->input_poll_dev->private = idev;
+ idev->input_poll_dev->poll = isl_input_lux_poll;
+ idev->input_poll_dev->poll_interval = 100;//50;
+ idev->input_poll_dev->input->open = isl_input_open;
+ idev->input_poll_dev->input->close = isl_input_close;
+ idev->input_poll_dev->input->name = "lsensor_lux";
+ idev->input_poll_dev->input->id.bustype = BUS_I2C;
+ idev->input_poll_dev->input->dev.parent = &client->dev;
+ input_set_drvdata(idev->input_poll_dev->input, idev);
+ input_set_capability(idev->input_poll_dev->input, EV_ABS, ABS_MISC);
+ input_set_abs_params(idev->input_poll_dev->input, ABS_MISC, 0, 16000, 0, 0);
+ i2c_set_clientdata(client, idev);
+ /* set default config after set_clientdata */
+ res = isl_set_default_config(client);
+ res = misc_register(&mmad_device);
+ if (res) {
+ errlog("mmad_device register failed\n");
+ goto err_misc_register;
+ }
+ res = input_register_polled_device(idev->input_poll_dev);
+ if(res < 0)
+ goto err_input_register_device;
+ // suspend/resume register
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ idev->earlysuspend.suspend = isl29023_early_suspend;
+ idev->earlysuspend.resume = isl29023_late_resume;
+ register_early_suspend(&(idev->earlysuspend));
+#endif +
+ dbg("isl29023 probe succeed!\n");
+ return 0;
+err_input_register_device:
+ misc_deregister(&mmad_device);
+ input_free_polled_device(idev->input_poll_dev);
+err_misc_register:
+err_input_allocate_device:
+ //__pm_runtime_disable(&client->dev, false);
+err_sysfs_create:
+ kobject_del(android_lsensor_kobj);
+err_kobjetc_create:
+ kfree(idev);
+ return res;
+}
+
+static int isl29023_remove(struct i2c_client *client)
+{
+ struct isl_device* idev = i2c_get_clientdata(client);
+
+ //unregister_early_suspend(&(idev->earlysuspend));
+ misc_deregister(&mmad_device);
+ input_unregister_polled_device(idev->input_poll_dev);
+ input_free_polled_device(idev->input_poll_dev);
+ sysfs_remove_group(android_lsensor_kobj, &m_isl_gr);
+ kobject_del(android_lsensor_kobj);
+ //__pm_runtime_disable(&client->dev, false);
+ kfree(idev);
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 remove call, \n", __func__);
+ return 0;
+}
+
+//****************add platform_device & platform_driver for suspend &resume 2013-7-2
+static int ls_probe(struct platform_device *pdev){
+ //printk("<<<%s\n", __FUNCTION__);
+ return 0;
+}
+static int ls_remove(struct platform_device *pdev){
+ //printk("<<<%s\n", __FUNCTION__);
+ return 0;
+}
+static int ls_suspend(struct platform_device *pdev, pm_message_t state){
+ printk("<<<%s\n", __FUNCTION__);
+ struct i2c_client *client = l_sensorconfig->client;
+
+ mutex_lock(&mutex);
+
+ isl_set_mod(client, ISL_MOD_POWERDOWN);
+
+ mutex_unlock(&mutex);
+
+
+ return 0;
+}
+
+static int ls_resume(struct platform_device *pdev){
+ //return 0;
+ int ret = 0;
+ int count = 0;
+ printk("<<<%s\n", __FUNCTION__);
+ struct i2c_client *client = l_sensorconfig->client;
+
+
+
+
+RETRY:
+ mutex_lock(&mutex);
+ //pm_runtime_get_sync(dev);
+ isl_set_mod(client, last_mod);
+ ret = isl_set_default_config(client);
+ //pm_runtime_put_sync(dev);
+ mutex_unlock(&mutex);
+ if (ret < 0){
+ printk("%s isl_set_default_config fail!\n", __FUNCTION__);
+ count++;
+ if (count < 5){
+ mdelay(2);
+ goto RETRY;
+ }
+ else
+ return ret;
+ }
+ return 0;
+
+}
+static void lsdev_release(struct device *dev)
+{
+ return;
+}
+static struct platform_device lsdev = {
+ .name = "lsdevice",
+ .id = -1,
+ .dev = {
+ .release = lsdev_release,
+ },
+};
+static struct platform_driver lsdrv = {
+ .probe = ls_probe,
+ .remove = ls_remove,
+ .suspend = ls_suspend,
+ .resume = ls_resume,
+ .driver = {
+ .name = "lsdevice",
+ },
+};
+//********************************************************************
+
+static int __init sensor_isl29023_init(void)
+{
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 init call, \n", __func__);
+ /*
+ * Force device to initialize: i2c-15 0x44
+ * If i2c_new_device is not called, even isl29023_detect will not run
+ * TODO: rework to automatically initialize the device
+ */
+ //i2c_new_device(i2c_get_adapter(15), &isl_info);
+ //return i2c_add_driver(&isl29023_driver);
+ if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME)))
+ {
+ printk(KERN_EMERG"Can't register gsensor i2c device!\n");
+ return -1;
+ }
+ if (isl29023_detect(this_client))
+ {
+ errlog("Can't find light sensor isl29023!\n");
+ goto detect_fail;
+ }
+ if(isl29023_probe(this_client))
+ {
+ errlog("Erro for probe!\n");
+ goto detect_fail;
+ }
+ int ret = 0;
+ ret = platform_device_register(&lsdev);
+ if (ret){
+ printk("<<<platform_device_register fail!\n");
+ return ret;
+ }
+ ret = platform_driver_register(&lsdrv);
+ if (ret){
+ printk("<<<platform_driver_register fail!\n");
+ platform_device_unregister(&lsdev);
+ return ret;
+ }
+
+ return 0;
+
+detect_fail:
+ sensor_i2c_unregister_device(this_client);
+ return -1;
+}
+
+static void __exit sensor_isl29023_exit(void)
+{
+ printk(KERN_INFO MODULE_NAME ": %s isl29023 exit call \n", __func__);
+ isl29023_remove(this_client);
+ sensor_i2c_unregister_device(this_client);
+ platform_driver_unregister(&lsdrv);
+ platform_device_unregister(&lsdev);
+ //i2c_del_driver(&isl29023_driver);
+}
+
+module_init(sensor_isl29023_init);
+module_exit(sensor_isl29023_exit);
+
+MODULE_AUTHOR("mdigioia");
+MODULE_ALIAS("isl29023 ALS");
+MODULE_DESCRIPTION("Intersil isl29023 ALS Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/Makefile new file mode 100755 index 00000000..774b6c9c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/Makefile @@ -0,0 +1,35 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_kionix_accel
+
+$(MY_MODULE_NAME)-objs := kionix_accel.o
+obj-m := $(MY_MODULE_NAME).o
+
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.c b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.c new file mode 100755 index 00000000..ddb5bbcb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.c @@ -0,0 +1,2427 @@ +/* drivers/input/misc/kionix_accel.c - Kionix accelerometer driver
+ *
+ * Copyright (C) 2012 Kionix, Inc.
+ * Written by Kuching Tan <kuchingtan@kionix.com>
+ *
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+//#include <linux/input/kionix_accel.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+#include "kionix_accel.h"
+#include "../sensor.h"
+
+
+
+/* Debug Message Flags */
+#define KIONIX_KMSG_ERR 1 /* Print kernel debug message for error */
+#define KIONIX_KMSG_INF 1 /* Print kernel debug message for info */
+
+#if KIONIX_KMSG_ERR
+#define KMSGERR(format, ...) \
+ dev_err(format, ## __VA_ARGS__)
+ //printk(format, ## __VA_ARGS__)
+#else
+#define KMSGERR(format, ...)
+#endif
+
+#if KIONIX_KMSG_INF
+#define KMSGINF(format, ...) \
+ dev_info(format, ## __VA_ARGS__)
+ //printk(format, ## __VA_ARGS__)
+#else
+#define KMSGINF(format, ...)
+#endif
+
+
+/******************************************************************************
+ * Accelerometer WHO_AM_I return value
+ *****************************************************************************/
+#define KIONIX_ACCEL_WHO_AM_I_KXTE9 0x00
+#define KIONIX_ACCEL_WHO_AM_I_KXTF9 0x01
+#define KIONIX_ACCEL_WHO_AM_I_KXTI9_1001 0x04
+#define KIONIX_ACCEL_WHO_AM_I_KXTIK_1004 0x05
+#define KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005 0x07
+#define KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007 0x08
+#define KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008 0x0A
+#define KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009 0x09
+#define KIONIX_ACCEL_WHO_AM_I_KXCJK_1013 0x11
+
+/******************************************************************************
+ * Accelerometer Grouping
+ *****************************************************************************/
+#define KIONIX_ACCEL_GRP1 1 /* KXTE9 */
+#define KIONIX_ACCEL_GRP2 2 /* KXTF9/I9-1001/J9-1005 */
+#define KIONIX_ACCEL_GRP3 3 /* KXTIK-1004 */
+#define KIONIX_ACCEL_GRP4 4 /* KXTJ9-1007/KXCJ9-1008 */
+#define KIONIX_ACCEL_GRP5 5 /* KXTJ2-1009 */
+#define KIONIX_ACCEL_GRP6 6 /* KXCJK-1013 */
+
+/******************************************************************************
+ * Registers for Accelerometer Group 1 & 2 & 3
+ *****************************************************************************/
+#define ACCEL_WHO_AM_I 0x0F
+
+/*****************************************************************************/
+/* Registers for Accelerometer Group 1 */
+/*****************************************************************************/
+/* Output Registers */
+#define ACCEL_GRP1_XOUT 0x12
+/* Control Registers */
+#define ACCEL_GRP1_CTRL_REG1 0x1B
+/* CTRL_REG1 */
+#define ACCEL_GRP1_PC1_OFF 0x7F
+#define ACCEL_GRP1_PC1_ON (1 << 7)
+#define ACCEL_GRP1_ODR40 (3 << 3)
+#define ACCEL_GRP1_ODR10 (2 << 3)
+#define ACCEL_GRP1_ODR3 (1 << 3)
+#define ACCEL_GRP1_ODR1 (0 << 3)
+#define ACCEL_GRP1_ODR_MASK (3 << 3)
+
+/*****************************************************************************/
+/* Registers for Accelerometer Group 2 & 3 */
+/*****************************************************************************/
+/* Output Registers */
+#define ACCEL_GRP2_XOUT_L 0x06
+/* Control Registers */
+#define ACCEL_GRP2_INT_REL 0x1A
+#define ACCEL_GRP2_CTRL_REG1 0x1B
+#define ACCEL_GRP2_INT_CTRL1 0x1E
+#define ACCEL_GRP2_DATA_CTRL 0x21
+/* CTRL_REG1 */
+#define ACCEL_GRP2_PC1_OFF 0x7F
+#define ACCEL_GRP2_PC1_ON (1 << 7)
+#define ACCEL_GRP2_DRDYE (1 << 5)
+#define ACCEL_GRP2_G_8G (2 << 3)
+#define ACCEL_GRP2_G_4G (1 << 3)
+#define ACCEL_GRP2_G_2G (0 << 3)
+#define ACCEL_GRP2_G_MASK (3 << 3)
+#define ACCEL_GRP2_RES_8BIT (0 << 6)
+#define ACCEL_GRP2_RES_12BIT (1 << 6)
+#define ACCEL_GRP2_RES_MASK (1 << 6)
+/* INT_CTRL1 */
+#define ACCEL_GRP2_IEA (1 << 4)
+#define ACCEL_GRP2_IEN (1 << 5)
+/* DATA_CTRL_REG */
+#define ACCEL_GRP2_ODR12_5 0x00
+#define ACCEL_GRP2_ODR25 0x01
+#define ACCEL_GRP2_ODR50 0x02
+#define ACCEL_GRP2_ODR100 0x03
+#define ACCEL_GRP2_ODR200 0x04
+#define ACCEL_GRP2_ODR400 0x05
+#define ACCEL_GRP2_ODR800 0x06
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Registers for Accelerometer Group 4 & 5 & 6 */
+/*****************************************************************************/
+/* Output Registers */
+#define ACCEL_GRP4_XOUT_L 0x06
+/* Control Registers */
+#define ACCEL_GRP4_INT_REL 0x1A
+#define ACCEL_GRP4_CTRL_REG1 0x1B
+#define ACCEL_GRP4_INT_CTRL1 0x1E
+#define ACCEL_GRP4_DATA_CTRL 0x21
+/* CTRL_REG1 */
+#define ACCEL_GRP4_PC1_OFF 0x7F
+#define ACCEL_GRP4_PC1_ON (1 << 7)
+#define ACCEL_GRP4_DRDYE (1 << 5)
+#define ACCEL_GRP4_G_8G (2 << 3)
+#define ACCEL_GRP4_G_4G (1 << 3)
+#define ACCEL_GRP4_G_2G (0 << 3)
+#define ACCEL_GRP4_G_MASK (3 << 3)
+#define ACCEL_GRP4_RES_8BIT (0 << 6)
+#define ACCEL_GRP4_RES_12BIT (1 << 6)
+#define ACCEL_GRP4_RES_MASK (1 << 6)
+/* INT_CTRL1 */
+#define ACCEL_GRP4_IEA (1 << 4)
+#define ACCEL_GRP4_IEN (1 << 5)
+/* DATA_CTRL_REG */
+#define ACCEL_GRP4_ODR0_781 0x08
+#define ACCEL_GRP4_ODR1_563 0x09
+#define ACCEL_GRP4_ODR3_125 0x0A
+#define ACCEL_GRP4_ODR6_25 0x0B
+#define ACCEL_GRP4_ODR12_5 0x00
+#define ACCEL_GRP4_ODR25 0x01
+#define ACCEL_GRP4_ODR50 0x02
+#define ACCEL_GRP4_ODR100 0x03
+#define ACCEL_GRP4_ODR200 0x04
+#define ACCEL_GRP4_ODR400 0x05
+#define ACCEL_GRP4_ODR800 0x06
+#define ACCEL_GRP4_ODR1600 0x07
+/*****************************************************************************/
+
+/* Input Event Constants */
+#define ACCEL_G_MAX 8096
+#define ACCEL_FUZZ 3
+#define ACCEL_FLAT 3
+/* I2C Retry Constants */
+#define KIONIX_I2C_RETRY_COUNT 10 /* Number of times to retry i2c */
+#define KIONIX_I2C_RETRY_TIMEOUT 1 /* Timeout between retry (miliseconds) */
+
+/* Earlysuspend Contants */
+#define KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT 5000 /* Timeout (miliseconds) */
+
+/*
+ * The following table lists the maximum appropriate poll interval for each
+ * available output data rate (ODR).
+ */
+static const struct {
+ unsigned int cutoff;
+ u8 mask;
+} kionix_accel_grp1_odr_table[] = {
+ { 100, ACCEL_GRP1_ODR40 },
+ { 334, ACCEL_GRP1_ODR10 },
+ { 1000, ACCEL_GRP1_ODR3 },
+ { 0, ACCEL_GRP1_ODR1 },
+};
+
+static const struct {
+ unsigned int cutoff;
+ u8 mask;
+} kionix_accel_grp2_odr_table[] = {
+ { 3, ACCEL_GRP2_ODR800 },
+ { 5, ACCEL_GRP2_ODR400 },
+ { 10, ACCEL_GRP2_ODR200 },
+ { 20, ACCEL_GRP2_ODR100 },
+ { 40, ACCEL_GRP2_ODR50 },
+ { 80, ACCEL_GRP2_ODR25 },
+ { 0, ACCEL_GRP2_ODR12_5},
+};
+
+static const struct {
+ unsigned int cutoff;
+ u8 mask;
+} kionix_accel_grp4_odr_table[] = {
+ { 2, ACCEL_GRP4_ODR1600 },
+ { 3, ACCEL_GRP4_ODR800 },
+ { 5, ACCEL_GRP4_ODR400 },
+ { 10, ACCEL_GRP4_ODR200 },
+ { 20, ACCEL_GRP4_ODR100 },
+ { 40, ACCEL_GRP4_ODR50 },
+ { 80, ACCEL_GRP4_ODR25 },
+ { 160, ACCEL_GRP4_ODR12_5},
+ { 320, ACCEL_GRP4_ODR6_25},
+ { 640, ACCEL_GRP4_ODR3_125},
+ { 1280, ACCEL_GRP4_ODR1_563},
+ { 0, ACCEL_GRP4_ODR0_781},
+};
+
+enum {
+ accel_grp1_ctrl_reg1 = 0,
+ accel_grp1_regs_count,
+};
+
+enum {
+ accel_grp2_ctrl_reg1 = 0,
+ accel_grp2_data_ctrl,
+ accel_grp2_int_ctrl,
+ accel_grp2_regs_count,
+};
+
+enum {
+ accel_grp4_ctrl_reg1 = 0,
+ accel_grp4_data_ctrl,
+ accel_grp4_int_ctrl,
+ accel_grp4_regs_count,
+};
+
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define GSENSOR_MAJOR 161
+static struct i2c_client *this_client = NULL;
+static struct platform_device *this_pdev;
+static struct kionix_accel_platform_data kionix_accel_pdata = {
+ .min_interval = 5,
+ .poll_interval = 200,
+ .accel_direction = 7,
+ .accel_irq_use_drdy = 0,
+ .accel_res = KIONIX_ACCEL_RES_12BIT,
+ .accel_g_range = KIONIX_ACCEL_G_4G,
+};
+/*
+struct kionix_config
+{
+ int op;
+ int int_gpio; //0-3
+ int xyz_axis[3][2]; // (axis,direction)
+ int rxyz_axis[3][2];
+ int irq;
+ struct proc_dir_entry* sensor_proc;
+ int sensorlevel;
+ int shake_enable; // 1--enable shake, 0--disable shake
+ int manual_rotation; // 0--landance, 90--vertical
+ struct input_dev *input_dev;
+ //struct work_struct work;
+ struct delayed_work work; // for polling
+ struct workqueue_struct *queue;
+ int isdbg; // 0-- no debug log, 1--show debug log
+ int sensor_samp; // 1,2,4,8,16,32,64,120
+ int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor
+ int test_pass;
+ spinlock_t spinlock;
+ int pollcnt; // the counts of polling
+ int offset[3];
+};
+
+static struct kionix_config l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },
+ .irq = 6,
+ .int_gpio = 3,
+ .sensor_proc = NULL,
+ //.sensorlevel = SENSOR_GRAVITYGAME_MODE,
+ .shake_enable = 0, // default enable shake
+ .isdbg = 0,
+ .sensor_samp = 10, // 4sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds
+ .offset = {0,0,0},
+};
+*/
+
+struct kionix_accel_driver {
+ struct i2c_client *client;
+ struct kionix_accel_platform_data accel_pdata;
+ struct input_dev *input_dev;
+ struct delayed_work accel_work;
+ struct workqueue_struct *accel_workqueue;
+ wait_queue_head_t wqh_suspend;
+
+ int accel_data[3];
+ int accel_cali[3];
+ u8 axis_map_x;
+ u8 axis_map_y;
+ u8 axis_map_z;
+ bool negate_x;
+ bool negate_y;
+ bool negate_z;
+ u8 shift;
+
+ unsigned int poll_interval;
+ unsigned int poll_delay;
+ unsigned int accel_group;
+ u8 *accel_registers;
+
+ atomic_t accel_suspended;
+ atomic_t accel_suspend_continue;
+ atomic_t accel_enabled;
+ atomic_t accel_input_event;
+ atomic_t accel_enable_resume;
+ struct mutex mutex_earlysuspend;
+ struct mutex mutex_resume;
+ struct mutex mutex_subinput;
+ rwlock_t rwlock_accel_data;
+
+ bool accel_drdy;
+
+ /* Function callback */
+ void (*kionix_accel_report_accel_data)(struct kionix_accel_driver *acceld);
+ int (*kionix_accel_update_odr)(struct kionix_accel_driver *acceld, unsigned int poll_interval);
+ int (*kionix_accel_power_on_init)(struct kionix_accel_driver *acceld);
+ int (*kionix_accel_operate)(struct kionix_accel_driver *acceld);
+ int (*kionix_accel_standby)(struct kionix_accel_driver *acceld);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+};
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static void kionix_accel_update_direction(struct kionix_accel_driver *acceld);
+static int get_axisset(struct kionix_accel_driver *acceld)
+{
+ char varbuf[64];
+ int n;
+ int ubootvar[3][3];
+ int varlen;
+ int err;
+
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+ if (wmt_getsyspara("wmt.io.kionixgsensor", varbuf, &varlen)) {
+ printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n");
+ return -1;
+ kionix_accel_update_direction(acceld);//return -1;
+ } else {
+ sscanf(varbuf, "%d:%d:%d:%d:%d:%d",
+ &ubootvar[0][0],
+ &ubootvar[0][1],
+ &ubootvar[1][0],
+ &ubootvar[1][1],
+ &ubootvar[2][0],
+ &ubootvar[2][1]);
+
+ acceld->axis_map_x = ubootvar[0][0];
+ acceld->negate_x = ubootvar[0][1]<0?1:0;
+ acceld->axis_map_y = ubootvar[1][0];
+ acceld->negate_y = ubootvar[1][1]<0?1:0;
+ acceld->axis_map_z = ubootvar[2][0];
+ acceld->negate_z = ubootvar[2][1]<0?1:0;
+ /*kionix_accel_pdata.accel_direction = direction;
+ printk(KERN_ERR"accel_direction is %d,g_range is %d,res is %d\n",kionix_accel_pdata.accel_direction,kionix_accel_pdata.accel_g_range,kionix_accel_pdata.accel_res);*/
+
+ }
+ return 0;
+}
+
+static int kionix_i2c_read(struct i2c_client *client, u8 addr, u8 *data, int len)
+{
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 1,
+ .buf = &addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = client->flags | I2C_M_RD,
+ .len = len,
+ .buf = data,
+ },
+ };
+
+ return i2c_transfer(client->adapter, msgs, 2);
+}
+
+static int kionix_i2c_write(struct i2c_client *client, u8 addr, u8 *data, int len)
+{
+ char wrData[12] = {0};
+ /*
+ struct i2c_msg msgs =
+ {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,};
+*/
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = len+1,
+ .buf = wrData,
+ },
+ };
+
+ if (!client || (!data))
+ {
+ printk("%s NULL client!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ wrData[0] = addr;
+ strncpy(&wrData[1], data, len);
+
+ if (i2c_transfer(client->adapter, &msgs, 1) < 0) {
+ printk( "%s: transfer failed.", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int kionix_i2c_writebyte(struct i2c_client *client, u8 addr, u8 data)
+{
+ char wrData[2] = {0};
+ /*
+ struct i2c_msg msgs =
+ {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,};
+*/
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = client->flags,
+ .len = 2,
+ .buf = &wrData[0],
+ },
+ };
+
+ if (!client)
+ {
+ printk("%s NULL client!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ wrData[0] = addr;
+ //strncpy(&wrData[1], data, len);
+ wrData[1] = data;
+
+ if (i2c_transfer(client->adapter, &msgs, 1) < 0) {
+ printk( "%s: transfer failed.", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int kionix_strtok(const char *buf, size_t count, char **token, const int token_nr)
+{
+ char *buf2 = (char *)kzalloc((count + 1) * sizeof(char), GFP_KERNEL);
+ char **token2 = token;
+ unsigned int num_ptr = 0, num_nr = 0, num_neg = 0;
+ int i = 0, start = 0, end = (int)count;
+
+ strcpy(buf2, buf);
+
+ /* We need to breakup the string into separate chunks in order for kstrtoint
+ * or strict_strtol to parse them without returning an error. Stop when the end of
+ * the string is reached or when enough value is read from the string */
+ while((start < end) && (i < token_nr)) {
+ /* We found a negative sign */
+ if(*(buf2 + start) == '-') {
+ /* Previous char(s) are numeric, so we store their value first before proceed */
+ if(num_nr > 0) {
+ /* If there is a pending negative sign, we adjust the variables to account for it */
+ if(num_neg) {
+ num_ptr--;
+ num_nr++;
+ }
+ *token2 = (char *)kzalloc((num_nr + 2) * sizeof(char), GFP_KERNEL);
+ strncpy(*token2, (const char *)(buf2 + num_ptr), (size_t) num_nr);
+ *(*token2+num_nr) = '\n';
+ i++;
+ token2++;
+ /* Reset */
+ num_ptr = num_nr = 0;
+ }
+ /* This indicates that there is a pending negative sign in the string */
+ num_neg = 1;
+ }
+ /* We found a numeric */
+ else if((*(buf2 + start) >= '0') && (*(buf2 + start) <= '9')) {
+ /* If the previous char(s) are not numeric, set num_ptr to current char */
+ if(num_nr < 1)
+ num_ptr = start;
+ num_nr++;
+ }
+ /* We found an unwanted character */
+ else {
+ /* Previous char(s) are numeric, so we store their value first before proceed */
+ if(num_nr > 0) {
+ if(num_neg) {
+ num_ptr--;
+ num_nr++;
+ }
+ *token2 = (char *)kzalloc((num_nr + 2) * sizeof(char), GFP_KERNEL);
+ strncpy(*token2, (const char *)(buf2 + num_ptr), (size_t) num_nr);
+ *(*token2+num_nr) = '\n';
+ i++;
+ token2++;
+ }
+ /* Reset all the variables to start afresh */
+ num_ptr = num_nr = num_neg = 0;
+ }
+ start++;
+ }
+
+ kfree(buf2);
+
+ return (i == token_nr) ? token_nr : -1;
+}
+
+static int kionix_accel_grp1_power_on_init(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP1_CTRL_REG1, acceld->accel_registers[accel_grp1_ctrl_reg1] | ACCEL_GRP1_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+ else {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP1_CTRL_REG1, acceld->accel_registers[accel_grp1_ctrl_reg1]);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp1_operate(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, \
+ acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP1_PC1_ON);
+ if (err < 0)
+ return err;
+
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return 0;
+}
+
+static int kionix_accel_grp1_standby(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ cancel_delayed_work_sync(&acceld->accel_work);
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void kionix_accel_grp1_report_accel_data(struct kionix_accel_driver *acceld)
+{
+ u8 accel_data[3];
+ s16 x, y, z;
+ int err;
+ struct input_dev *input_dev = acceld->input_dev;
+ int loop = KIONIX_I2C_RETRY_COUNT;
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ {
+ while(loop) {
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ err = kionix_i2c_read(acceld->client, ACCEL_GRP1_XOUT, accel_data, 6);
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err);
+ }
+ else {
+ write_lock(&acceld->rwlock_accel_data);
+
+ x = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_x] >> 2)) - 32)) << 6;
+ y = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_y] >> 2)) - 32)) << 6;
+ z = ((s16) le16_to_cpu(((s16)(accel_data[acceld->axis_map_z] >> 2)) - 32)) << 6;
+
+ acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x];
+ acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y];
+ acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z];
+
+ if(atomic_read(&acceld->accel_input_event) > 0) {
+ input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]);
+ input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]);
+ input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]);
+ input_sync(acceld->input_dev);
+ }
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+ }
+ else
+ {
+ atomic_inc(&acceld->accel_enable_resume);
+ }
+ }
+}
+
+static int kionix_accel_grp1_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval)
+{
+ int err;
+ int i;
+ u8 odr;
+
+ /* Use the lowest ODR that can support the requested poll interval */
+ for (i = 0; i < ARRAY_SIZE(kionix_accel_grp1_odr_table); i++) {
+ odr = kionix_accel_grp1_odr_table[i].mask;
+ if (poll_interval < kionix_accel_grp1_odr_table[i].cutoff)
+ break;
+ }
+
+ /* Do not need to update CTRL_REG1 register if the ODR is not changed */
+ if((acceld->accel_registers[accel_grp1_ctrl_reg1] & ACCEL_GRP1_ODR_MASK) == odr)
+ return 0;
+ else {
+ acceld->accel_registers[accel_grp1_ctrl_reg1] &= ~ACCEL_GRP1_ODR_MASK;
+ acceld->accel_registers[accel_grp1_ctrl_reg1] |= odr;
+ }
+
+ /* Do not need to update CTRL_REG1 register if the sensor is not currently turn on */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP1_CTRL_REG1, \
+ acceld->accel_registers[accel_grp1_ctrl_reg1] | ACCEL_GRP1_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp2_power_on_init(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ /* ensure that PC1 is cleared before updating control registers */
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_DATA_CTRL, acceld->accel_registers[accel_grp2_data_ctrl]);
+ if (err < 0)
+ return err;
+
+ /* only write INT_CTRL_REG1 if in irq mode */
+ if (acceld->client->irq) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_INT_CTRL1, acceld->accel_registers[accel_grp2_int_ctrl]);
+ if (err < 0)
+ return err;
+ }
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+ else {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1]);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp2_operate(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, \
+ acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON);
+ if (err < 0)
+ return err;
+
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return 0;
+}
+
+static int kionix_accel_grp2_standby(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ if(acceld->accel_drdy == 0)
+ cancel_delayed_work_sync(&acceld->accel_work);
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void kionix_accel_grp2_report_accel_data(struct kionix_accel_driver *acceld)
+{
+ struct { union {
+ s16 accel_data_s16[3];
+ s8 accel_data_s8[6];
+ }; } accel_data;
+ s16 x, y, z;
+ int err;
+ struct input_dev *input_dev = acceld->input_dev;
+ int loop;
+
+ /* Only read the output registers if enabled */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ err = kionix_i2c_read(acceld->client, ACCEL_GRP2_XOUT_L, (u8 *)accel_data.accel_data_s16, 6);
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err);
+ }
+ else {
+ write_lock(&acceld->rwlock_accel_data);
+
+ x = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_x])) >> acceld->shift;
+ y = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_y])) >> acceld->shift;
+ z = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_z])) >> acceld->shift;
+
+ acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x];
+ acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y];
+ acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z];
+
+ if(atomic_read(&acceld->accel_input_event) > 0) {
+ input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]);
+ input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]);
+ input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]);
+ input_sync(acceld->input_dev);
+ }
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+ }
+ else
+ {
+ atomic_inc(&acceld->accel_enable_resume);
+ }
+ }
+
+ /* Clear the interrupt if using drdy */
+ if(acceld->accel_drdy == 1) {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP2_INT_REL);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0)
+ KMSGERR(&acceld->client->dev, "%s: clear interrupt error = %d\n", __func__, err);
+ }
+}
+
+static void kionix_accel_grp2_update_g_range(struct kionix_accel_driver *acceld)
+{
+ acceld->accel_registers[accel_grp2_ctrl_reg1] &= ~ACCEL_GRP2_G_MASK;
+
+ switch (acceld->accel_pdata.accel_g_range) {
+ case KIONIX_ACCEL_G_8G:
+ case KIONIX_ACCEL_G_6G:
+ acceld->shift = 2;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_8G;
+ break;
+ case KIONIX_ACCEL_G_4G:
+ acceld->shift = 3;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_4G;
+ break;
+ case KIONIX_ACCEL_G_2G:
+ default:
+ acceld->shift = 4;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_G_2G;
+ break;
+ }
+
+ return;
+}
+
+static int kionix_accel_grp2_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval)
+{
+ int err;
+ int i;
+ u8 odr;
+
+ /* Use the lowest ODR that can support the requested poll interval */
+ for (i = 0; i < ARRAY_SIZE(kionix_accel_grp2_odr_table); i++) {
+ odr = kionix_accel_grp2_odr_table[i].mask;
+ if (poll_interval < kionix_accel_grp2_odr_table[i].cutoff)
+ break;
+ }
+
+ /* Do not need to update DATA_CTRL_REG register if the ODR is not changed */
+ if(acceld->accel_registers[accel_grp2_data_ctrl] == odr)
+ return 0;
+ else
+ acceld->accel_registers[accel_grp2_data_ctrl] = odr;
+
+ /* Do not need to update DATA_CTRL_REG register if the sensor is not currently turn on */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_DATA_CTRL, acceld->accel_registers[accel_grp2_data_ctrl]);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP2_CTRL_REG1, acceld->accel_registers[accel_grp2_ctrl_reg1] | ACCEL_GRP2_PC1_ON);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp4_power_on_init(struct kionix_accel_driver *acceld)
+{
+ int err;
+ char rxData[2] = {0};
+ /* ensure that PC1 is cleared before updating control registers */
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, 0);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, 0);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d ,%s: ACCEL_GRP4_CTRL_REG1 is %d",__LINE__,__FUNCTION__,rxData[0]);*/
+
+ if (err < 0)
+ return err;
+
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",__LINE__,__FUNCTION__,rxData[0],rxData[1]);*/
+
+ if (err < 0)
+ return err;
+
+ /* only write INT_CTRL_REG1 if in irq mode */
+ if (acceld->client->irq) {
+ err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_INT_CTRL1, acceld->accel_registers[accel_grp4_int_ctrl]);
+ if (err < 0)
+ return err;
+ }
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",rxData[0],rxData[1]);*/
+
+ if (err < 0)
+ return err;
+ }
+ else {
+ /*err = i2c_smbus_write_byte_data(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1]);*/
+
+ err = kionix_i2c_writebyte(acceld->client,
+ ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1]);
+ /*kionix_i2c_read(acceld->client,ACCEL_GRP4_CTRL_REG1,rxData,1);
+ printk(KERN_ERR"%d,%s: ACCEL_GRP4_CTRL_REG1 now is %d,wanted value is %d",__LINE__,__FUNCTION__,rxData[0],acceld->accel_registers[accel_grp4_ctrl_reg1]);*/
+
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int kionix_accel_grp4_operate(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ /*err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, \
+ acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);*/
+
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, \
+ acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ if (err < 0)
+ return err;
+
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return 0;
+}
+
+static int kionix_accel_grp4_standby(struct kionix_accel_driver *acceld)
+{
+ int err;
+
+ if(acceld->accel_drdy == 0)
+ cancel_delayed_work_sync(&acceld->accel_work);
+
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void kionix_accel_grp4_report_accel_data(struct kionix_accel_driver *acceld)
+{
+ struct { union {
+ s16 accel_data_s16[3];
+ s8 accel_data_s8[6];
+ }; } accel_data;
+ s16 x, y, z;
+ int err;
+ struct input_dev *input_dev = acceld->input_dev;
+ int loop;
+
+ /* Only read the output registers if enabled */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ err = kionix_i2c_read(acceld->client, ACCEL_GRP4_XOUT_L, (u8 *)accel_data.accel_data_s16, 6);
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: read data output error = %d\n", __func__, err);
+ }
+ else {
+ write_lock(&acceld->rwlock_accel_data);
+
+ x = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_x])) >> acceld->shift;
+ y = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_y])) >> acceld->shift;
+ z = ((s16) le16_to_cpu(accel_data.accel_data_s16[acceld->axis_map_z])) >> acceld->shift;
+
+ acceld->accel_data[acceld->axis_map_x] = (acceld->negate_x ? -x : x) + acceld->accel_cali[acceld->axis_map_x];
+ acceld->accel_data[acceld->axis_map_y] = (acceld->negate_y ? -y : y) + acceld->accel_cali[acceld->axis_map_y];
+ acceld->accel_data[acceld->axis_map_z] = (acceld->negate_z ? -z : z) + acceld->accel_cali[acceld->axis_map_z];
+
+ //printk(KERN_ERR"x:%d,y:%d,z:%d",x,y,z);
+
+ if(atomic_read(&acceld->accel_input_event) > 0) {
+ input_report_abs(acceld->input_dev, ABS_X, acceld->accel_data[acceld->axis_map_x]);
+ input_report_abs(acceld->input_dev, ABS_Y, acceld->accel_data[acceld->axis_map_y]);
+ input_report_abs(acceld->input_dev, ABS_Z, acceld->accel_data[acceld->axis_map_z]);
+ input_sync(acceld->input_dev);
+ }
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+ }
+ else
+ {
+ atomic_inc(&acceld->accel_enable_resume);
+ }
+ }
+
+ /* Clear the interrupt if using drdy */
+ if(acceld->accel_drdy == 1) {
+ loop = KIONIX_I2C_RETRY_COUNT;
+ while(loop) {
+ err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP4_INT_REL);
+ if(err < 0){
+ loop--;
+ mdelay(KIONIX_I2C_RETRY_TIMEOUT);
+ }
+ else
+ loop = 0;
+ }
+ if (err < 0)
+ KMSGERR(&acceld->client->dev, "%s: clear interrupt error = %d\n", __func__, err);
+ }
+}
+
+static void kionix_accel_grp4_update_g_range(struct kionix_accel_driver *acceld)
+{
+ acceld->accel_registers[accel_grp4_ctrl_reg1] &= ~ACCEL_GRP4_G_MASK;
+ //printk(KERN_ERR"kionix_accel_grp4_update_g_range is %d",acceld->accel_pdata.accel_g_range);
+ switch (acceld->accel_pdata.accel_g_range) {
+ case KIONIX_ACCEL_G_8G:
+ case KIONIX_ACCEL_G_6G:
+ //acceld->shift = 2;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_8G;
+ break;
+ case KIONIX_ACCEL_G_4G:
+ //acceld->shift = 4;//3;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_4G;
+ break;
+ case KIONIX_ACCEL_G_2G:
+ default:
+ //acceld->shift = 4;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_G_2G;
+ break;
+ }
+
+ return;
+}
+
+static int kionix_accel_grp4_update_odr(struct kionix_accel_driver *acceld, unsigned int poll_interval)
+{
+ int err;
+ int i;
+ u8 odr;
+
+ /* Use the lowest ODR that can support the requested poll interval */
+ for (i = 0; i < ARRAY_SIZE(kionix_accel_grp4_odr_table); i++) {
+ odr = kionix_accel_grp4_odr_table[i].mask;
+ if (poll_interval < kionix_accel_grp4_odr_table[i].cutoff)
+ break;
+ }
+
+ /* Do not need to update DATA_CTRL_REG register if the ODR is not changed */
+ if(acceld->accel_registers[accel_grp4_data_ctrl] == odr)
+ return 0;
+ else
+ acceld->accel_registers[accel_grp4_data_ctrl] = odr;
+
+ /* Do not need to update DATA_CTRL_REG register if the sensor is not currently turn on */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, 0);
+
+
+ if (err < 0)
+ return err;
+
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_DATA_CTRL, acceld->accel_registers[accel_grp4_data_ctrl]);
+ if (err < 0)
+ return err;
+
+ //err = i2c_smbus_write_byte_data(acceld->client, ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ err = kionix_i2c_writebyte(acceld->client, ACCEL_GRP4_CTRL_REG1, acceld->accel_registers[accel_grp4_ctrl_reg1] | ACCEL_GRP4_PC1_ON);
+ if (err < 0)
+ return err;
+ //#############
+ err = i2c_smbus_read_byte_data(acceld->client, ACCEL_GRP4_DATA_CTRL);
+ if (err < 0)
+ return err;
+ switch(err) {
+ case ACCEL_GRP4_ODR0_781:
+ dev_info(&acceld->client->dev, "ODR = 0.781 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR1_563:
+ dev_info(&acceld->client->dev, "ODR = 1.563 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR3_125:
+ dev_info(&acceld->client->dev, "ODR = 3.125 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR6_25:
+ dev_info(&acceld->client->dev, "ODR = 6.25 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR12_5:
+ dev_info(&acceld->client->dev, "ODR = 12.5 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR25:
+ dev_info(&acceld->client->dev, "ODR = 25 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR50:
+ dev_info(&acceld->client->dev, "ODR = 50 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR100:
+ dev_info(&acceld->client->dev, "ODR = 100 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR200:
+ dev_info(&acceld->client->dev, "ODR = 200 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR400:
+ dev_info(&acceld->client->dev, "ODR = 400 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR800:
+ dev_info(&acceld->client->dev, "ODR = 800 Hz\n");
+ break;
+ case ACCEL_GRP4_ODR1600:
+ dev_info(&acceld->client->dev, "ODR = 1600 Hz\n");
+ break;
+ default:
+ dev_info(&acceld->client->dev, "Unknown ODR\n");
+ break;
+ }
+ //#############
+ }
+
+ return 0;
+}
+
+static int kionix_accel_power_on(struct kionix_accel_driver *acceld)
+{
+ if (acceld->accel_pdata.power_on)
+ return acceld->accel_pdata.power_on();
+
+ return 0;
+}
+
+static void kionix_accel_power_off(struct kionix_accel_driver *acceld)
+{
+ if (acceld->accel_pdata.power_off)
+ acceld->accel_pdata.power_off();
+}
+
+static irqreturn_t kionix_accel_isr(int irq, void *dev)
+{
+ struct kionix_accel_driver *acceld = dev;
+
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, 0);
+
+ return IRQ_HANDLED;
+}
+
+static void kionix_accel_work(struct work_struct *work)
+{
+ struct kionix_accel_driver *acceld = container_of((struct delayed_work *)work, struct kionix_accel_driver, accel_work);
+
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay);
+
+ acceld->kionix_accel_report_accel_data(acceld);
+}
+
+static void kionix_accel_update_direction(struct kionix_accel_driver *acceld)
+{
+ unsigned int direction = acceld->accel_pdata.accel_direction;
+ unsigned int accel_group = acceld->accel_group;
+
+ write_lock(&acceld->rwlock_accel_data);
+ acceld->axis_map_x = ((direction-1)%2);
+ acceld->axis_map_y = (direction%2);
+ acceld->axis_map_z = 2;
+ acceld->negate_z = ((direction-1)/4);
+ switch(accel_group) {
+ case KIONIX_ACCEL_GRP3:
+ case KIONIX_ACCEL_GRP6:
+ acceld->negate_x = (((direction+2)/2)%2);
+ acceld->negate_y = (((direction+5)/4)%2);
+ break;
+ case KIONIX_ACCEL_GRP5:
+ acceld->axis_map_x = (direction%2);
+ acceld->axis_map_y = ((direction-1)%2);
+ acceld->negate_x = (((direction+1)/2)%2);
+ acceld->negate_y = (((direction/2)+((direction-1)/4))%2);
+ break;
+ default:
+ acceld->negate_x = ((direction/2)%2);
+ acceld->negate_y = (((direction+1)/4)%2);
+ break;
+ }
+ write_unlock(&acceld->rwlock_accel_data);
+ return;
+}
+
+static int kionix_accel_enable(struct kionix_accel_driver *acceld)
+{
+ int err = 0;
+ long remaining;
+
+ mutex_lock(&acceld->mutex_earlysuspend);
+
+ atomic_set(&acceld->accel_suspend_continue, 0);
+
+ /* Make sure that the sensor had successfully resumed before enabling it */
+ if(atomic_read(&acceld->accel_suspended) == 1) {
+ KMSGINF(&acceld->client->dev, "%s: waiting for resume\n", __func__);
+ remaining = wait_event_interruptible_timeout(acceld->wqh_suspend, \
+ atomic_read(&acceld->accel_suspended) == 0, \
+ msecs_to_jiffies(KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT));
+
+ if(atomic_read(&acceld->accel_suspended) == 1) {
+ KMSGERR(&acceld->client->dev, "%s: timeout waiting for resume\n", __func__);
+ err = -ETIME;
+ goto exit;
+ }
+ }
+
+ err = acceld->kionix_accel_operate(acceld);
+
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kionix_accel_operate returned err = %d\n", __func__, err);
+ goto exit;
+ }
+
+ atomic_inc(&acceld->accel_enabled);
+
+exit:
+ mutex_unlock(&acceld->mutex_earlysuspend);
+
+ return err;
+}
+
+static int kionix_accel_disable(struct kionix_accel_driver *acceld)
+{
+ int err = 0;
+
+ mutex_lock(&acceld->mutex_resume);
+
+ atomic_set(&acceld->accel_suspend_continue, 1);
+
+ if(atomic_read(&acceld->accel_enabled) > 0){
+ if(atomic_dec_and_test(&acceld->accel_enabled)) {
+ if(atomic_read(&acceld->accel_enable_resume) > 0)
+ atomic_set(&acceld->accel_enable_resume, 0);
+ err = acceld->kionix_accel_standby(acceld);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kionix_accel_standby returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ wake_up_interruptible(&acceld->wqh_suspend);
+ }
+ }
+
+exit:
+ mutex_unlock(&acceld->mutex_resume);
+
+ return err;
+}
+
+static int kionix_accel_input_open(struct input_dev *input)
+{
+ struct kionix_accel_driver *acceld = input_get_drvdata(input);
+
+ atomic_inc(&acceld->accel_input_event);
+
+ return 0;
+}
+
+static void kionix_accel_input_close(struct input_dev *dev)
+{
+ struct kionix_accel_driver *acceld = input_get_drvdata(dev);
+
+ atomic_dec(&acceld->accel_input_event);
+}
+
+static void __devinit kionix_accel_init_input_device(struct kionix_accel_driver *acceld,
+ struct input_dev *input_dev)
+{
+ __set_bit(EV_ABS, input_dev->evbit);
+ input_set_abs_params(input_dev, ABS_X, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT);
+ input_set_abs_params(input_dev, ABS_Y, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT);
+ input_set_abs_params(input_dev, ABS_Z, -ACCEL_G_MAX, ACCEL_G_MAX, ACCEL_FUZZ, ACCEL_FLAT);
+
+ input_dev->name = "g-sensor";//KIONIX_ACCEL_NAME;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &acceld->client->dev;
+}
+
+static int __devinit kionix_accel_setup_input_device(struct kionix_accel_driver *acceld)
+{
+ struct input_dev *input_dev;
+ int err;
+
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ KMSGERR(&acceld->client->dev, "input_allocate_device failed\n");
+ printk("kionix_accel_probe: Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ acceld->input_dev = input_dev;
+
+ input_dev->open = kionix_accel_input_open;
+ input_dev->close = kionix_accel_input_close;
+ input_set_drvdata(input_dev, acceld);
+
+ kionix_accel_init_input_device(acceld, input_dev);
+
+ err = input_register_device(acceld->input_dev);
+ if (err) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: input_register_device returned err = %d\n", __func__, err);
+ printk("kionix_accel_probe: Failed to register input device\n");
+ input_free_device(acceld->input_dev);
+ return err;
+ }
+
+ return 0;
+}
+
+/* Returns the enable state of device */
+static ssize_t kionix_accel_get_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", atomic_read(&acceld->accel_enabled) > 0 ? 1 : 0);
+}
+
+/* Allow users to enable/disable the device */
+static ssize_t kionix_accel_set_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ char *buf2;
+ const int enable_count = 1;
+ unsigned long enable;
+ int err = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ if(kionix_strtok(buf, count, &buf2, enable_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: No enable data being read. " \
+ "No enable data will be updated.\n", __func__);
+ }
+
+ else {
+ /* Removes any leading negative sign */
+ while(*buf2 == '-')
+ buf2++;
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtouint((const char *)buf2, 10, (unsigned int *)&enable);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtouint returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #else
+ err = strict_strtoul((const char *)buf2, 10, &enable);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtoul returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #endif
+
+ if(enable)
+ err = kionix_accel_enable(acceld);
+ else
+ err = kionix_accel_disable(acceld);
+ }
+
+exit:
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ return (err < 0) ? err : count;
+}
+
+/* Returns currently selected poll interval (in ms) */
+static ssize_t kionix_accel_get_delay(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", acceld->poll_interval);
+}
+
+/* Allow users to select a new poll interval (in ms) */
+static ssize_t kionix_accel_set_delay(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ char *buf2;
+ const int delay_count = 1;
+ unsigned long interval;
+ int err = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ if(kionix_strtok(buf, count, &buf2, delay_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: No delay data being read. " \
+ "No delay data will be updated.\n", __func__);
+ }
+
+ else {
+ /* Removes any leading negative sign */
+ while(*buf2 == '-')
+ buf2++;
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtouint((const char *)buf2, 10, (unsigned int *)&interval);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtouint returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #else
+ err = strict_strtoul((const char *)buf2, 10, &interval);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtoul returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #endif
+
+ if(acceld->accel_drdy == 1)
+ disable_irq(client->irq);
+
+ /*
+ * Set current interval to the greater of the minimum interval or
+ * the requested interval
+ */
+ acceld->poll_interval = max((unsigned int)interval, acceld->accel_pdata.min_interval);
+ acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval);
+
+ err = acceld->kionix_accel_update_odr(acceld, acceld->poll_interval);
+
+ if(acceld->accel_drdy == 1)
+ enable_irq(client->irq);
+ }
+
+exit:
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+
+ return (err < 0) ? err : count;
+}
+
+/* Returns the direction of device */
+static ssize_t kionix_accel_get_direct(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", acceld->accel_pdata.accel_direction);
+}
+
+/* Allow users to change the direction the device */
+static ssize_t kionix_accel_set_direct(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ char *buf2;
+ const int direct_count = 1;
+ unsigned long direction;
+ int err = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ if(kionix_strtok(buf, count, &buf2, direct_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: No direction data being read. " \
+ "No direction data will be updated.\n", __func__);
+ }
+
+ else {
+ /* Removes any leading negative sign */
+ while(*buf2 == '-')
+ buf2++;
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtouint((const char *)buf2, 10, (unsigned int *)&direction);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtouint returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #else
+ err = strict_strtoul((const char *)buf2, 10, &direction);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtoul returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ #endif
+
+ if(direction < 1 || direction > 8)
+ KMSGERR(&acceld->client->dev, "%s: invalid direction = %d\n", __func__, (unsigned int) direction);
+
+ else {
+ acceld->accel_pdata.accel_direction = (u8) direction;
+ kionix_accel_update_direction(acceld);
+ }
+ }
+
+exit:
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+ return (err < 0) ? err : count;
+}
+
+/* Returns the data output of device */
+static ssize_t kionix_accel_get_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ int x, y, z;
+
+ read_lock(&acceld->rwlock_accel_data);
+
+ x = acceld->accel_data[acceld->axis_map_x];
+ y = acceld->accel_data[acceld->axis_map_y];
+ z = acceld->accel_data[acceld->axis_map_z];
+
+ read_unlock(&acceld->rwlock_accel_data);
+
+ return sprintf(buf, "%d %d %d\n", x, y, z);
+}
+
+/* Returns the calibration value of the device */
+static ssize_t kionix_accel_get_cali(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ int calibration[3];
+
+ read_lock(&acceld->rwlock_accel_data);
+
+ calibration[0] = acceld->accel_cali[acceld->axis_map_x];
+ calibration[1] = acceld->accel_cali[acceld->axis_map_y];
+ calibration[2] = acceld->accel_cali[acceld->axis_map_z];
+
+ read_unlock(&acceld->rwlock_accel_data);
+
+ return sprintf(buf, "%d %d %d\n", calibration[0], calibration[1], calibration[2]);
+}
+
+/* Allow users to change the calibration value of the device */
+static ssize_t kionix_accel_set_cali(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(client);
+ struct input_dev *input_dev = acceld->input_dev;
+ const int cali_count = 3; /* How many calibration that we expect to get from the string */
+ char **buf2;
+ long calibration[cali_count];
+ int err = 0, i = 0;
+
+ /* Lock the device to prevent races with open/close (and itself) */
+ //mutex_lock(&input_dev->mutex);
+ mutex_lock(&acceld->mutex_subinput);
+ buf2 = (char **)kzalloc(cali_count * sizeof(char *), GFP_KERNEL);
+
+ if(kionix_strtok(buf, count, buf2, cali_count) < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: Not enough calibration data being read. " \
+ "No calibration data will be updated.\n", __func__);
+ }
+ else {
+ /* Convert string to integers */
+ for(i = 0 ; i < cali_count ; i++) {
+ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
+ err = kstrtoint((const char *)*(buf2+i), 10, (int *)&calibration[i]);
+ if(err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: kstrtoint returned err = %d." \
+ "No calibration data will be updated.\n", __func__ , err);
+ goto exit;
+ }
+ #else
+ err = strict_strtol((const char *)*(buf2+i), 10, &calibration[i]);
+ if(err < 0) {
+ KMSGERR(&acceld->client->dev, \
+ "%s: strict_strtol returned err = %d." \
+ "No calibration data will be updated.\n", __func__ , err);
+ goto exit;
+ }
+ #endif
+ }
+
+ write_lock(&acceld->rwlock_accel_data);
+
+ acceld->accel_cali[acceld->axis_map_x] = (int)calibration[0];
+ acceld->accel_cali[acceld->axis_map_y] = (int)calibration[1];
+ acceld->accel_cali[acceld->axis_map_z] = (int)calibration[2];
+
+ write_unlock(&acceld->rwlock_accel_data);
+ }
+
+exit:
+ for(i = 0 ; i < cali_count ; i++)
+ kfree(*(buf2+i));
+
+ kfree(buf2);
+
+ //mutex_unlock(&input_dev->mutex);
+ mutex_unlock(&acceld->mutex_subinput);
+
+ return (err < 0) ? err : count;
+}
+
+static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kionix_accel_get_enable, kionix_accel_set_enable);
+static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kionix_accel_get_delay, kionix_accel_set_delay);
+static DEVICE_ATTR(direct, S_IRUGO|S_IWUSR, kionix_accel_get_direct, kionix_accel_set_direct);
+static DEVICE_ATTR(data, S_IRUGO, kionix_accel_get_data, NULL);
+static DEVICE_ATTR(cali, S_IRUGO|S_IWUSR, kionix_accel_get_cali, kionix_accel_set_cali);
+
+static struct attribute *kionix_accel_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_direct.attr,
+ &dev_attr_data.attr,
+ &dev_attr_cali.attr,
+ NULL
+};
+
+static struct attribute_group kionix_accel_attribute_group = {
+ .attrs = kionix_accel_attributes
+};
+
+static int kionix_chip_id[] ={
+ KIONIX_ACCEL_WHO_AM_I_KXTE9,
+ KIONIX_ACCEL_WHO_AM_I_KXTF9,
+ KIONIX_ACCEL_WHO_AM_I_KXTI9_1001,
+ KIONIX_ACCEL_WHO_AM_I_KXTIK_1004,
+ KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005,
+ KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007,
+ KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008,
+ KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009,
+ KIONIX_ACCEL_WHO_AM_I_KXCJK_1013
+};
+
+static int iskionix()
+{
+ char rxData[2] = {0};
+ int ret = 0;
+ int i = 0;
+
+ ret = kionix_i2c_read(this_client,ACCEL_WHO_AM_I,rxData,1); //maybe should 2 success // -5 ioerror!!
+ printk(KERN_ERR"<<<<%s ret:%d val 0x%x\n", __FUNCTION__, ret, rxData[0]);
+ if (ret <= 0) // 2 ?
+ {
+ return -1;
+ }
+ for(i = 0 ; i < sizeof(kionix_chip_id)/sizeof(kionix_chip_id[0]);i++)
+ if(rxData[0] == kionix_chip_id[i])
+ return 0;
+
+ return -1;
+}
+
+static int __devinit kionix_verify(struct kionix_accel_driver *acceld)
+{
+ int retval = i2c_smbus_read_byte_data(acceld->client, ACCEL_WHO_AM_I);
+
+#if KIONIX_KMSG_INF
+ switch (retval) {
+ case KIONIX_ACCEL_WHO_AM_I_KXTE9:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTE9.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTF9:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTF9.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTI9_1001:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTI9-1001.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTIK_1004:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTIK-1004.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ9-1005.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ9-1007.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXCJ9-1008.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXTJ2-1009.\n");
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXCJK_1013:
+ KMSGINF(&acceld->client->dev, "this accelerometer is a KXCJK-1013.\n");
+ break;
+ default:
+ break;
+ }
+#endif
+
+ return retval;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void kionix_accel_earlysuspend_suspend(struct early_suspend *h)
+{
+ struct kionix_accel_driver *acceld = container_of(h, struct kionix_accel_driver, early_suspend);
+ long remaining;
+
+ mutex_lock(&acceld->mutex_earlysuspend);
+
+ /* Only continue to suspend if enable did not intervene */
+ if(atomic_read(&acceld->accel_suspend_continue) > 0) {
+ /* Make sure that the sensor had successfully disabled before suspending it */
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ KMSGINF(&acceld->client->dev, "%s: waiting for disable\n", __func__);
+ remaining = wait_event_interruptible_timeout(acceld->wqh_suspend, \
+ atomic_read(&acceld->accel_enabled) < 1, \
+ msecs_to_jiffies(KIONIX_ACCEL_EARLYSUSPEND_TIMEOUT));
+
+ if(atomic_read(&acceld->accel_enabled) > 0) {
+ KMSGERR(&acceld->client->dev, "%s: timeout waiting for disable\n", __func__);
+ }
+ }
+
+ kionix_accel_power_off(acceld);
+
+ atomic_set(&acceld->accel_suspended, 1);
+ }
+
+ mutex_unlock(&acceld->mutex_earlysuspend);
+
+ return;
+}
+
+void kionix_accel_earlysuspend_resume(struct early_suspend *h)
+{
+ struct kionix_accel_driver *acceld = container_of(h, struct kionix_accel_driver, early_suspend);
+ int err;
+
+ mutex_lock(&acceld->mutex_resume);
+
+ if(atomic_read(&acceld->accel_suspended) == 1) {
+ err = kionix_accel_power_on(acceld);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on returned err = %d\n", __func__, err);
+ goto exit;
+ }
+
+ /* Only needs to reinitialized the registers if Vdd is pulled low during suspend */
+ if(err > 0) {
+ err = acceld->kionix_accel_power_on_init(acceld);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on_init returned err = %d\n", __func__, err);
+ goto exit;
+ }
+ }
+
+ atomic_set(&acceld->accel_suspended, 0);
+ }
+
+ wake_up_interruptible(&acceld->wqh_suspend);
+
+exit:
+ mutex_unlock(&acceld->mutex_resume);
+
+ return;
+}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+static int kionix_open(struct inode *inode, struct file *file)
+{
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+ //KMSGINF("Open the g-sensor node...\n");
+ kionix_accel_input_open(acceld->input_dev);
+ return 0;
+}
+
+static int kionix_release(struct inode *inode, struct file *file)
+{
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+ //KMSGINF("Close the g-sensor node...\n");
+ kionix_accel_input_close(acceld->input_dev);
+ return 0;
+}
+
+static long
+kionix_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ char rwbuf[5];
+ short delay, enable; //amsr = -1;
+ unsigned int uval = 0;
+
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+
+ //KMSGINF("g-sensor ioctr...\n");
+ memset(rwbuf, 0, sizeof(rwbuf));
+ switch (cmd) {
+ case ECS_IOCTL_APP_SET_DELAY:
+ // set the rate of g-sensor
+ if (copy_from_user(&delay, argp, sizeof(short)))
+ {
+ printk(KERN_ALERT "Can't get set delay!!!\n");
+ return -EFAULT;
+ }
+ klog("Get delay=%d\n", delay);
+
+ if ((delay >=0) && (delay < 20))
+ {
+ delay = 20;
+ } else if (delay > 200)
+ {
+ delay = 200;
+ }
+ //l_sensorconfig.sensor_samp = 1000/delay;
+ acceld->poll_interval = 1000/delay;
+ acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval);
+ acceld->kionix_accel_update_odr(acceld, acceld->poll_interval);
+ break;
+ case ECS_IOCTL_APP_SET_AFLAG:
+ // enable/disable sensor
+ if (copy_from_user(&enable, argp, sizeof(short)))
+ {
+ printk(KERN_ERR "Can't get enable flag!!!\n");
+ return -EFAULT;
+ }
+ klog("enable=%d\n",enable);
+ if ((enable >=0) && (enable <=1))
+ {
+ //KMSGINF("driver: disable/enable(%d) gsensor.\n", enable);
+
+ //l_sensorconfig.sensor_enable = enable;
+ if(enable)
+ kionix_accel_enable(acceld);
+ else
+ kionix_accel_disable(acceld);
+
+ } else {
+ printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ break;
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = KIONIX_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ //KMSGINF("kionix_driver_id:%d\n",uval);
+ break;
+ case WMT_IOCTL_SENOR_GET_RESOLUTION:
+
+ uval = (12<<8) | 8; // 8bit:4g 0xxx xx //mma8452Q
+ if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ printk("<<<<<<<resolution:0x%x\n",uval);
+ default:
+ break;
+ }
+
+
+
+ return 0;
+}
+
+static struct file_operations kionix_fops = {
+ .owner = THIS_MODULE,
+ .open = kionix_open,
+ .release = kionix_release,
+ .unlocked_ioctl = kionix_ioctl,
+};
+
+
+static struct miscdevice kionix_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sensor_ctrl",
+ .fops = &kionix_fops,
+};
+
+static int sensor_writeproc( struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data )
+{
+ return 0;
+}
+
+static int sensor_readproc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
+
+
+
+
+/*static int __devinit kionix_accel_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)*/
+static int kionix_accel_probe(struct platform_device *pdev)
+{
+ const struct kionix_accel_platform_data *accel_pdata = this_client->dev.platform_data;
+ struct kionix_accel_driver *acceld;
+ int err;
+ struct proc_dir_entry *proc_dir, *proc_entry;
+/*
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) {
+ KMSGERR(&client->dev, "client is not i2c capable. Abort.\n");
+ return -ENXIO;
+ }
+*/
+ if (!accel_pdata) {
+ KMSGERR(&this_client->dev, "platform data is NULL. Abort.\n");
+ return -EINVAL;
+ }
+
+ acceld = kzalloc(sizeof(*acceld), GFP_KERNEL);
+ if (acceld == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for module data. Abort.\n");
+ return -ENOMEM;
+ }
+
+ acceld->client = this_client;
+ acceld->accel_pdata = *accel_pdata;
+
+ i2c_set_clientdata(this_client, acceld);
+
+ err = kionix_accel_power_on(acceld);
+ if (err < 0)
+ goto err_free_mem;
+
+ if (accel_pdata->init) {
+ err = accel_pdata->init();
+ if (err < 0)
+ goto err_accel_pdata_power_off;
+ }
+
+ err = kionix_verify(acceld);
+ if (err < 0) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_verify returned err = %d. Abort.\n", __func__, err);
+ goto err_accel_pdata_exit;
+ }
+
+ /* Setup group specific configuration and function callback */
+ switch (err) {
+ case KIONIX_ACCEL_WHO_AM_I_KXTE9:
+ acceld->accel_group = KIONIX_ACCEL_GRP1;
+ acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp1_regs_count, GFP_KERNEL);
+ if (acceld->accel_registers == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for accel_registers. Abort.\n");
+ goto err_accel_pdata_exit;
+ }
+ acceld->accel_drdy = 0;
+ acceld->kionix_accel_report_accel_data = kionix_accel_grp1_report_accel_data;
+ acceld->kionix_accel_update_odr = kionix_accel_grp1_update_odr;
+ acceld->kionix_accel_power_on_init = kionix_accel_grp1_power_on_init;
+ acceld->kionix_accel_operate = kionix_accel_grp1_operate;
+ acceld->kionix_accel_standby = kionix_accel_grp1_standby;
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTF9:
+ case KIONIX_ACCEL_WHO_AM_I_KXTI9_1001:
+ case KIONIX_ACCEL_WHO_AM_I_KXTIK_1004:
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1005:
+ if(err == KIONIX_ACCEL_WHO_AM_I_KXTIK_1004)
+ acceld->accel_group = KIONIX_ACCEL_GRP3;
+ else
+ acceld->accel_group = KIONIX_ACCEL_GRP2;
+ acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp2_regs_count, GFP_KERNEL);
+ if (acceld->accel_registers == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for accel_registers. Abort.\n");
+ goto err_accel_pdata_exit;
+ }
+ switch(acceld->accel_pdata.accel_res) {
+ case KIONIX_ACCEL_RES_6BIT:
+ case KIONIX_ACCEL_RES_8BIT:
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_RES_8BIT;
+ break;
+ case KIONIX_ACCEL_RES_12BIT:
+ default:
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_RES_12BIT;
+ break;
+ }
+ if(acceld->accel_pdata.accel_irq_use_drdy && this_client->irq) {
+ acceld->accel_registers[accel_grp2_int_ctrl] |= ACCEL_GRP2_IEN | ACCEL_GRP2_IEA;
+ acceld->accel_registers[accel_grp2_ctrl_reg1] |= ACCEL_GRP2_DRDYE;
+ acceld->accel_drdy = 1;
+ }
+ else
+ acceld->accel_drdy = 0;
+ kionix_accel_grp2_update_g_range(acceld);
+ acceld->kionix_accel_report_accel_data = kionix_accel_grp2_report_accel_data;
+ acceld->kionix_accel_update_odr = kionix_accel_grp2_update_odr;
+ acceld->kionix_accel_power_on_init = kionix_accel_grp2_power_on_init;
+ acceld->kionix_accel_operate = kionix_accel_grp2_operate;
+ acceld->kionix_accel_standby = kionix_accel_grp2_standby;
+ break;
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ9_1007:
+ case KIONIX_ACCEL_WHO_AM_I_KXCJ9_1008:
+ case KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009:
+ case KIONIX_ACCEL_WHO_AM_I_KXCJK_1013:
+ if(err == KIONIX_ACCEL_WHO_AM_I_KXTJ2_1009)
+ acceld->accel_group = KIONIX_ACCEL_GRP5;
+ else if(err == KIONIX_ACCEL_WHO_AM_I_KXCJK_1013)
+ acceld->accel_group = KIONIX_ACCEL_GRP6;
+ else
+ acceld->accel_group = KIONIX_ACCEL_GRP4;
+ acceld->accel_registers = kzalloc(sizeof(u8)*accel_grp4_regs_count, GFP_KERNEL);
+ if (acceld->accel_registers == NULL) {
+ KMSGERR(&this_client->dev, \
+ "failed to allocate memory for accel_registers. Abort.\n");
+ goto err_accel_pdata_exit;
+ }
+ switch(acceld->accel_pdata.accel_res) {
+ case KIONIX_ACCEL_RES_6BIT:
+ case KIONIX_ACCEL_RES_8BIT:
+ acceld->shift = 0;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_RES_8BIT;
+ break;
+ case KIONIX_ACCEL_RES_12BIT:
+ acceld->shift = 4;
+ default:
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_RES_12BIT;
+ break;
+ }
+ if(acceld->accel_pdata.accel_irq_use_drdy && this_client->irq) {
+ acceld->accel_registers[accel_grp4_int_ctrl] |= ACCEL_GRP4_IEN | ACCEL_GRP4_IEA;
+ acceld->accel_registers[accel_grp4_ctrl_reg1] |= ACCEL_GRP4_DRDYE;
+ acceld->accel_drdy = 1;
+ }
+ else
+ acceld->accel_drdy = 0;
+ kionix_accel_grp4_update_g_range(acceld);
+ acceld->kionix_accel_report_accel_data = kionix_accel_grp4_report_accel_data;
+ acceld->kionix_accel_update_odr = kionix_accel_grp4_update_odr;
+ acceld->kionix_accel_power_on_init = kionix_accel_grp4_power_on_init;
+ acceld->kionix_accel_operate = kionix_accel_grp4_operate;
+ acceld->kionix_accel_standby = kionix_accel_grp4_standby;
+ break;
+ default:
+ KMSGERR(&acceld->client->dev, \
+ "%s: unsupported device, who am i = %d. Abort.\n", __func__, err);
+ goto err_accel_pdata_exit;
+ }
+
+ err = kionix_accel_setup_input_device(acceld);
+ if (err)
+ goto err_free_accel_registers;
+
+//add
+ /*this_pdev = pdev;
+ l_sensorconfig.input_dev = acceld->input_dev;*/
+
+ err = misc_register(&kionix_device);
+ if (err) {
+ printk(KERN_ERR
+ "kionix_accel_probe: kionix_device register failed\n");
+ goto exit_misc_device_register_failed;
+ }
+
+ //dev_set_drvdata(&pdev->dev, &l_sensorconfig);
+//end add
+
+
+ atomic_set(&acceld->accel_suspended, 0);
+ atomic_set(&acceld->accel_suspend_continue, 1);
+ atomic_set(&acceld->accel_enabled, 0);
+ atomic_set(&acceld->accel_input_event, 0);
+ atomic_set(&acceld->accel_enable_resume, 0);
+
+ mutex_init(&acceld->mutex_earlysuspend);
+ mutex_init(&acceld->mutex_resume);
+
+ mutex_init(&acceld->mutex_subinput);//add 2014-6-12
+
+ rwlock_init(&acceld->rwlock_accel_data);
+
+ acceld->poll_interval = acceld->accel_pdata.poll_interval;
+ acceld->poll_delay = msecs_to_jiffies(acceld->poll_interval);
+ acceld->kionix_accel_update_odr(acceld, acceld->poll_interval);
+ get_axisset(acceld);//kionix_accel_update_direction(acceld);
+
+ proc_dir = proc_mkdir("sensors", NULL);
+ if (proc_dir == NULL)
+ KMSGERR(&this_client->dev, "failed to create /proc/sensors\n");
+ else {
+ proc_entry = create_proc_entry( "accelinfo", 0644, proc_dir);
+ if (proc_entry == NULL)
+ KMSGERR(&this_client->dev, "failed to create /proc/cpu/accelinfo\n");
+ }
+
+/*
+ proc_dir = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL);//&proc_root
+ if (proc_dir != NULL)
+ {
+ proc_dir->write_proc = sensor_writeproc;
+ proc_dir->read_proc = sensor_readproc;
+ }
+*/
+ acceld->accel_workqueue = create_singlethread_workqueue("Kionix Accel Workqueue");
+ INIT_DELAYED_WORK(&acceld->accel_work, kionix_accel_work);
+ init_waitqueue_head(&acceld->wqh_suspend);
+
+ if (acceld->accel_drdy) {
+ err = request_threaded_irq(this_client->irq, NULL, kionix_accel_isr, \
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, \
+ KIONIX_ACCEL_IRQ, acceld);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: request_threaded_irq returned err = %d\n", __func__, err);
+ KMSGERR(&acceld->client->dev, "%s: running in software polling mode instead\n", __func__);
+ acceld->accel_drdy = 0;
+ }
+ KMSGINF(&acceld->client->dev, "running in hardware interrupt mode\n");
+ } else {
+ KMSGINF(&acceld->client->dev, "running in software polling mode\n");
+ }
+
+ err = acceld->kionix_accel_power_on_init(acceld);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: kionix_accel_power_on_init returned err = %d. Abort.\n", __func__, err);
+ goto err_free_irq;
+ }
+
+ err = sysfs_create_group(&this_client->dev.kobj, &kionix_accel_attribute_group);
+ if (err) {
+ KMSGERR(&acceld->client->dev, "%s: sysfs_create_group returned err = %d. Abort.\n", __func__, err);
+ goto err_free_irq;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ /* The higher the level, the earlier it resume, and the later it suspend */
+ acceld->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50;
+ acceld->early_suspend.suspend = kionix_accel_earlysuspend_suspend;
+ acceld->early_suspend.resume = kionix_accel_earlysuspend_resume;
+ register_early_suspend(&acceld->early_suspend);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+
+ // satrt the polling work
+ if(acceld->accel_drdy == 0)
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay);
+ return 0;
+
+exit_misc_device_register_failed:
+err_free_irq:
+ if (acceld->accel_drdy)
+ free_irq(this_client->irq, acceld);
+ destroy_workqueue(acceld->accel_workqueue);
+ input_unregister_device(acceld->input_dev);
+err_free_accel_registers:
+ kfree(acceld->accel_registers);
+err_accel_pdata_exit:
+ if (accel_pdata->exit)
+ accel_pdata->exit();
+err_accel_pdata_power_off:
+ kionix_accel_power_off(acceld);
+err_free_mem:
+ kfree(acceld);
+exit_input_dev_alloc_failed:
+ return err;
+}
+
+static int kionix_accel_remove(struct platform_device *pdev)
+{
+ struct kionix_accel_driver *acceld = i2c_get_clientdata(this_client);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&acceld->early_suspend);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+ if (NULL != acceld->accel_workqueue)
+ {
+ cancel_delayed_work_sync(&acceld->accel_work);
+ flush_workqueue(acceld->accel_workqueue);
+ destroy_workqueue(acceld->accel_workqueue);
+ acceld->accel_workqueue = NULL;
+ }
+ sysfs_remove_group(&this_client->dev.kobj, &kionix_accel_attribute_group);
+ if (acceld->accel_drdy)
+ free_irq(this_client->irq, acceld);
+ //destroy_workqueue(acceld->accel_workqueue);
+ misc_deregister(&kionix_device);
+ input_unregister_device(acceld->input_dev);
+ kfree(acceld->accel_registers);
+ if (acceld->accel_pdata.exit)
+ acceld->accel_pdata.exit();
+ kionix_accel_power_off(acceld);
+ kfree(acceld);
+
+ return 0;
+}
+
+static int __devexit kionix_accel_i2cremove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id kionix_accel_id[] = {
+ { KIONIX_ACCEL_NAME, 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, kionix_accel_id);
+
+static struct i2c_driver kionix_accel_driver = {
+ .driver = {
+ .name = KIONIX_ACCEL_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = kionix_accel_probe,
+ .remove = __devexit_p(kionix_accel_i2cremove),
+ .id_table = kionix_accel_id,
+};
+
+
+static struct platform_device kionix_pdevice = {
+ .name = "kionix",
+ .id = 0,
+ /*.dev = {
+ //.release = mma8452q_platform_release,
+ },*/
+};
+
+//************
+static void kionix_accel_shutdown(struct platform_device *pdev)
+{
+ struct kionix_accel_driver *acceld = NULL;
+ acceld = i2c_get_clientdata(this_client);
+ if (acceld) {
+ printk("<<<<<%s\n", __func__);
+ flush_delayed_work_sync(&acceld->accel_work);
+ cancel_delayed_work_sync(&acceld->accel_work);
+ }
+
+}
+//****add for resume dpm timeout 2014-6-12
+static int kionix_accel_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct kionix_accel_driver *acceld = NULL;
+ acceld = i2c_get_clientdata(this_client);
+ if (acceld) {
+ printk("<<<<<%s\n", __func__);
+ flush_delayed_work_sync(&acceld->accel_work);
+ cancel_delayed_work_sync(&acceld->accel_work);
+ }
+}
+
+int kionix_accel_resume(struct platform_device *pdev)
+{
+ struct kionix_accel_driver *acceld = NULL;
+ acceld = i2c_get_clientdata(this_client);
+ if (acceld) {
+ printk("<<<<<%s\n", __func__);
+ queue_delayed_work(acceld->accel_workqueue, &acceld->accel_work, acceld->poll_delay);
+ }
+}
+//***********************
+static struct platform_driver kionix_driver = {
+ .probe = kionix_accel_probe,
+ .remove = kionix_accel_remove,
+ .shutdown = kionix_accel_shutdown,
+ .suspend = kionix_accel_suspend,
+ .resume = kionix_accel_resume,
+ .driver = {
+ .name = "kionix",
+ },
+};
+
+
+static struct class* l_dev_class = NULL;
+static struct device *l_clsdevice = NULL;
+static int __init kionix_accel_init(void)
+{
+ //return i2c_add_driver(&kionix_accel_driver);
+
+ int ret = 0;
+ struct kionix_accel_driver *acceld;
+
+ acceld = kzalloc(sizeof(*acceld), GFP_KERNEL);
+ if (acceld == NULL) {
+ printk("%s kzalloc fail!\n", __func__);
+ return -ENOMEM;
+ }
+
+ ret = get_axisset(acceld);//
+ if (ret < 0)
+ {
+ printk("%s user choose to no sensor chip!\n", __func__);
+ kfree(acceld);
+ return ret;
+ }
+ kfree(acceld);
+
+ if (!(this_client = sensor_i2c_register_device2(0, KIONIX_ACCEL_I2C_ADDR, KIONIX_ACCEL_NAME,(void*)(&kionix_accel_pdata))))
+ {
+ printk(KERN_EMERG"Can't register gsensor i2c device!\n");
+ return -1;
+ }
+
+
+ if(iskionix())
+ {
+ printk(KERN_ERR "Can't find kionix!!\n");
+ sensor_i2c_unregister_device(this_client);
+ return -1;
+ }
+
+ //ret = get_axisset(NULL);
+
+ printk("kionix g-sensor driver init\n");
+
+ //spin_lock_init(&l_sensorconfig.spinlock);
+ l_dev_class = class_create(THIS_MODULE, KIONIX_ACCEL_NAME);
+ //for S40 module to judge whether insmod is ok
+ if (IS_ERR(l_dev_class)){
+ ret = PTR_ERR(l_dev_class);
+ printk(KERN_ERR "Can't class_create gsensor device !!\n");
+ return ret;
+ }
+ l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, KIONIX_ACCEL_NAME);
+ if (IS_ERR(l_clsdevice)){
+ ret = PTR_ERR(l_clsdevice);
+ printk(KERN_ERR "Failed to create device %s !!!",KIONIX_ACCEL_NAME);
+ return ret;
+ }
+
+ if((ret = platform_device_register(&kionix_pdevice)))
+ {
+ printk(KERN_ERR "%s Can't register kionix platform devcie!!!\n", __FUNCTION__);
+ return ret;
+ }
+ if ((ret = platform_driver_register(&kionix_driver)) != 0)
+ {
+ printk(KERN_ERR "%s Can't register kionix platform driver!!!\n", __FUNCTION__);
+ return ret;
+ }
+
+ return 0;
+
+}
+module_init(kionix_accel_init);
+
+static void __exit kionix_accel_exit(void)
+{
+ //i2c_del_driver(&kionix_accel_driver);
+ platform_driver_unregister(&kionix_driver);
+ platform_device_unregister(&kionix_pdevice);
+
+ device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0));
+ + class_destroy(l_dev_class);
+ sensor_i2c_unregister_device(this_client);
+}
+module_exit(kionix_accel_exit);
+
+MODULE_DESCRIPTION("Kionix accelerometer driver");
+MODULE_AUTHOR("Kuching Tan <kuchingtan@kionix.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("3.3.0");
diff --git a/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h new file mode 100755 index 00000000..b7be9b8f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kionix_gsensor/kionix_accel.h @@ -0,0 +1,85 @@ +/* include/linux/input/kionix_accel.h - Kionix accelerometer driver
+ *
+ * Copyright (C) 2012 Kionix, Inc.
+ * Written by Kuching Tan <kuchingtan@kionix.com>
+ *
+ * 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 __KIONIX_ACCEL_H__
+#define __KIONIX_ACCEL_H__
+
+#define KIONIX_ACCEL_I2C_ADDR 0x0E
+#define KIONIX_ACCEL_NAME "kionix_accel"
+#define KIONIX_ACCEL_IRQ "kionix-irq"
+
+struct kionix_accel_platform_data {
+ /* Although the accelerometer can perform at high ODR,
+ * there is a need to keep the maximum ODR to a lower
+ * value due to power consumption or other concern.
+ * Use this variable to set the minimum allowable
+ * interval for data to be reported from the
+ * accelerometer. Unit is measured in milli-
+ * seconds. Recommended value is 5ms. */
+ unsigned int min_interval;
+ /* Use this variable to set the default interval for
+ * data to be reported from the accelerometer. This
+ * value will be used during driver setup process,
+ * but can be changed by the system during runtime via
+ * sysfs control. Recommended value is 200ms.*/
+ unsigned int poll_interval;
+
+ /* This variable controls the corresponding direction
+ * of the accelerometer that is mounted on the board
+ * of the device. Refer to the porting guide for
+ * details. Valid value is 1 to 8. */
+ u8 accel_direction;
+
+ /* Use this variable to choose whether or not to use
+ * DRDY hardware interrupt mode to trigger a data
+ * report event instead of using software polling.
+ * Note that for those accelerometer model that does
+ * not support DRDY hardware interrupt, the driver
+ * will revert to software polling mode automatically.
+ * Valid value is 0 or 1.*/
+ bool accel_irq_use_drdy;
+
+ /* Use this variable to control the number of
+ * effective bits of the accelerometer output.
+ * Use the macro definition to select the desired
+ * number of effective bits. */
+ #define KIONIX_ACCEL_RES_12BIT 0
+ #define KIONIX_ACCEL_RES_8BIT 1
+ #define KIONIX_ACCEL_RES_6BIT 2
+ u8 accel_res;
+
+ /* Use this variable to control the G range of
+ * the accelerometer output. Use the macro definition
+ * to select the desired G range.*/
+ #define KIONIX_ACCEL_G_2G 0
+ #define KIONIX_ACCEL_G_4G 1
+ #define KIONIX_ACCEL_G_6G 2
+ #define KIONIX_ACCEL_G_8G 3
+ u8 accel_g_range;
+
+ /* Optional callback functions that can be implemented
+ * on per product basis. If these callbacks are defined,
+ * they will be called by the driver. */
+ int (*init)(void);
+ void (*exit)(void);
+ int (*power_on)(void);
+ int (*power_off)(void);
+};
+#endif /* __KIONIX_ACCEL_H__ */
diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile new file mode 100755 index 00000000..23eca917 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_kxte9
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := kxte9.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c new file mode 100755 index 00000000..2f25a4f8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.c @@ -0,0 +1,1798 @@ +/* drivers/i2c/chips/kxte9.c - KXTE9 accelerometer driver + * + * Copyright (C) 2010 Kionix, Inc. + * Written by Kuching Tan <kuchingtan@kionix.com> + * + * 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 3 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/module.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/uaccess.h> +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +//#include <linux/kxte9.h> +#include <linux/platform_device.h> +#include <linux/miscdevice.h> +#include <mach/hardware.h> +#include "kxte9.h" +//#include <linux/earlysuspend.h> +#include <mach/wmt-i2c-bus.h> + +#define NAME "kxte9" +#define G_MAX 2000 +/* OUTPUT REGISTERS */ +#define CT_RESP 0x0C +#define WHO_AM_I 0x0F +#define TILT_POS_CUR 0x10 +#define TILT_POS_PRE 0x11 +#define XOUT 0x12 +#define INT_STATUS_REG 0x16 +#define INT_SRC_REG2 0x17 +#define INT_REL 0x1A +/* CONTROL REGISTERS */ +#define CTRL_REG1 0x1B +#define CTRL_REG2 0x1C +#define CTRL_REG3 0x1D +#define INT_CTRL1 0x1E +#define INT_CTRL2 0x1F +#define TILT_TIMER 0x28 +#define WUF_TIMER 0x29 +#define B2S_TIMER 0x2A +#define WUF_THRESH 0x5A +#define B2S_THRESH 0x5B +/* CTRL_REG1 BITS */ +#define PC1_OFF 0x00 +#define PC1_ON 0x80 +/* INT_SRC_REG2 BITS */ +#define TPS 0x01 +#define WUFS 0x02 +#define B2SS 0x04 +/* Direction Mask */ +/* Used for TILT_POS_CUR, TILT_POS_PRE */ +/* INT_SRC_REG1, CTRL_REG2 */ +#define DIR_LE 0x20 +#define DIR_RI 0x10 +#define DIR_DO 0x08 +#define DIR_UP 0x04 +#define DIR_FD 0x02 +#define DIR_FU 0x01 +/* ODR MASKS */ +#define ODRM 0x18 // CTRL_REG1 +#define OWUFM 0x03 // CTRL_REG3 +#define OB2SM 0x0C // CTRL_REG3 +/* INPUT_ABS CONSTANTS */ +#define FUZZ 32 +#define FLAT 32 +/* RESUME STATE INDICES */ +#define RES_CTRL_REG1 0 +#define RES_CTRL_REG3 1 +#define RES_INT_CTRL1 2 +#define RES_TILT_TIMER 3 +#define RES_WUF_TIMER 4 +#define RES_B2S_TIMER 5 +#define RES_WUF_THRESH 6 +#define RES_B2S_THRESH 7 +#define RES_CURRENT_ODR 8 +#define RESUME_ENTRIES 9 +/* OFFSET and SENSITIVITY */ +//#define OFFSET 32 //6-bit +#define OFFSET 128 //8-bit +#define SENS 16 + +#define IOCTL_BUFFER_SIZE 64 + +//#define WM3445_A0 +//#define INT_MODE + +////////////////////////////////////////////////////////////////////////// +//#define DEBUG_WMT_GSENSOR +#ifdef DEBUG_WMT_GSENSOR +#define kxte9_dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__ , ## args) +//#define kxte9_dbg(fmt, args...) if (kpadall_isrundbg()) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) +#else +#define kxte9_dbg(fmt, args...) +#endif + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_DEBUG "[%s]: " fmt, __FUNCTION__, ## args) +////////////////////////////////////////////////////////////////////////// + +/* + * The following table lists the maximum appropriate poll interval for each + * available output data rate. + */ +struct { + unsigned int interval; + u8 mask; +} kxte9_odr_table[] = { + {1000, ODR1E}, + {334, ODR3E}, + {100, ODR10E}, + {25, ODR40E}, + {8, ODR125E}, +}; + +struct kxte9_data { + //struct i2c_client *client; + struct kxte9_platform_data *pdata; + struct mutex lock; + struct delayed_work input_work; + struct input_dev *input_dev; +#ifdef INT_MODE + struct work_struct irq_work; +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + int hw_initialized; + atomic_t enabled; + u8 resume[RESUME_ENTRIES]; + int i2c_xfer_complete; + int suspend; +}; + +struct gsensor_config +{ + int op; + int samp; + int xyz_axis[3][3]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + int sensorlevel; + unsigned int avg_count; + unsigned int kxte9_8bit; + int name; + int bmp; + unsigned int ctraddr; + unsigned int ocaddr; + unsigned int idaddr; + unsigned int peaddr; + unsigned int pcaddr; + unsigned int itbmp; + unsigned int itaddr; + unsigned int isbmp; + unsigned int isaddr; + int irq; +}; + +static struct gsensor_config gconf = { + .op = 0, + .samp = 40, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .avg_count = 4, + .kxte9_8bit = 1, + .name = 3, +#ifdef WM3445_A0 + .bmp = 0x100, /* GPIO 8 */ + .ctraddr = GPIO_BASE_ADDR + 0x40, + .ocaddr = GPIO_BASE_ADDR + 0x80, + .idaddr = GPIO_BASE_ADDR + 0x00, + .peaddr = GPIO_BASE_ADDR + 0x480, + .pcaddr = GPIO_BASE_ADDR + 0x4c0, + .itbmp = 0x30000, /* Rising Edge */ + .itaddr = GPIO_BASE_ADDR + 0x300, + .isbmp = 0x100, + .isaddr = GPIO_BASE_ADDR + 0x304, + .irq = IRQ_GPIO8, +#else + .bmp = 0x8, /* GPIO 3 */ + .ctraddr = GPIO_BASE_ADDR + 0x40, + .ocaddr = GPIO_BASE_ADDR + 0x80, + .idaddr = GPIO_BASE_ADDR + 0x00, + .peaddr = GPIO_BASE_ADDR + 0x480, + .pcaddr = GPIO_BASE_ADDR + 0x4c0, + .itbmp = 0x83000000, /* Rising Edge */ + .itaddr = GPIO_BASE_ADDR + 0x300, + .isbmp = 0x8, + .isaddr = GPIO_BASE_ADDR + 0x320, + .irq = 5, +#endif +}; + +static struct kxte9_platform_data kxte9_pdata = { + .min_interval = 1, + .poll_interval = 100, + .ctrl_reg1_init = ODR10E & ~B2SE & ~WUFE & ~TPE, + .engine_odr_init = OB2S1 | OWUF1, + .int_ctrl_init = KXTE9_IEA, + .tilt_timer_init = 0x00, + .wuf_timer_init = 0x00, + .wuf_thresh_init = 0x20, + .b2s_timer_init = 0x00, + .b2s_thresh_init = 0x60, +}; + +#ifdef WM3445_A0 +#define SET_GPIO_GSENSOR_INT() {\ + REG32_VAL(gconf.ctraddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.ocaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.peaddr) |= gconf.bmp; \ + REG32_VAL(gconf.pcaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.itaddr) |= gconf.itbmp; \ + REG32_VAL(GPIO_BASE_ADDR + 0x308) |= gconf.bmp; \ + REG32_VAL(gconf.isaddr) |= gconf.isbmp; \ +} +#define ENABLE_SENSOR_INT(enable) { \ + if (enable) \ + {\ + REG32_VAL(GPIO_BASE_ADDR + 0x308) &= ~gconf.bmp; \ + } else {\ + REG32_VAL(GPIO_BASE_ADDR + 0x308) |= gconf.bmp; \ + }\ +} + +#else +#define SET_GPIO_GSENSOR_INT() {\ + REG32_VAL(gconf.ctraddr) |= gconf.bmp; \ + REG32_VAL(gconf.ocaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.pcaddr) &= ~gconf.bmp; \ + REG32_VAL(gconf.itaddr) |= gconf.itbmp; \ + REG32_VAL(gconf.isaddr) |= gconf.isbmp; \ +} +#endif + +#define X_CONVERT(x) x*gconf.xyz_axis[ABS_X][1] +#define Y_CONVERT(y) y*gconf.xyz_axis[ABS_Y][1] +#define Z_CONVERT(z) z*gconf.xyz_axis[ABS_Z][1] + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void kxte9_early_suspend(struct early_suspend *h); +static void kxte9_late_resume(struct early_suspend *h); +#endif + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id); +extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size); +extern unsigned int wmt_read_oscr(void); + +static struct kxte9_data *te9 = NULL; +static atomic_t kxte9_dev_open_count; +static struct kobject *android_gsensor_kobj = NULL; +static void kxte9_read_callback(void *data); +struct i2c_msg *kxte9_msg; +unsigned char *i2c_read_buf; +unsigned char *i2c_write_buf; +static struct timer_list kxte9_timer; +static unsigned char *x_count; +static unsigned char *y_count; +static unsigned char *z_count; +static unsigned int x_total = 0, y_total = 0, z_total = 0; +static unsigned int xyz_index = 0; + +static int wait_i2c_xfer_complete(void) +{ + unsigned int now_time = 0; + unsigned int delay_time = 0; + + now_time = wmt_read_oscr(); + while (!te9->i2c_xfer_complete) { + delay_time = wmt_read_oscr() - now_time; + if (delay_time > 60000) {//20ms + printk(KERN_WARNING "[kxte9] transfer timeout!\n"); + return 0; + } + } + return 1; +} + +static void kxte9_read_callback(void *data) +{ + int xyz[3]; + + if (te9->suspend) { + te9->i2c_xfer_complete = 1; + return; + } + if (xyz_index >= gconf.avg_count) + xyz_index = 0; + x_total -= x_count[xyz_index]; + y_total -= y_count[xyz_index]; + z_total -= z_count[xyz_index]; + if (gconf.kxte9_8bit) { + x_count[xyz_index] = i2c_read_buf[0]; + y_count[xyz_index] = i2c_read_buf[1]; + z_count[xyz_index] = i2c_read_buf[2]; + } else { + x_count[xyz_index] = i2c_read_buf[0] & ~0x03; + y_count[xyz_index] = i2c_read_buf[1] & ~0x03; + z_count[xyz_index] = i2c_read_buf[2] & ~0x03; + } + x_total += x_count[xyz_index]; + y_total += y_count[xyz_index]; + z_total += z_count[xyz_index]; + xyz[ABS_X] = (x_total/gconf.avg_count - OFFSET) << 4; + xyz[ABS_Y] = (y_total/gconf.avg_count - OFFSET) << 4; + xyz[ABS_Z] = (z_total/gconf.avg_count - OFFSET) << 4; + //printk(KERN_DEBUG " [%d] x:%d y:%d z:%d\n", xyz_index, x_count[xyz_index], y_count[xyz_index], z_count[xyz_index]); + //printk(KERN_DEBUG " total x:%d y:%d z:%d\n", x_total, y_total, z_total); + //printk(KERN_DEBUG " avg x:%d y:%d z:%d\n", x_total/gconf.avg_count, y_total/gconf.avg_count, z_total/gconf.avg_count); + //printk(KERN_DEBUG "report x:%d y:%d z:%d\n", xyz[ABS_X], xyz[ABS_Y], xyz[ABS_Z]); + xyz_index++; + input_report_abs(te9->input_dev, ABS_X, X_CONVERT(xyz[gconf.xyz_axis[ABS_X][0]])); + input_report_abs(te9->input_dev, ABS_Y, Y_CONVERT(xyz[gconf.xyz_axis[ABS_Y][0]])); + input_report_abs(te9->input_dev, ABS_Z, Z_CONVERT(xyz[gconf.xyz_axis[ABS_Z][0]])); + input_sync(te9->input_dev); + te9->i2c_xfer_complete = 1; + mod_timer(&kxte9_timer, jiffies + msecs_to_jiffies(te9->pdata->poll_interval)); +} + +static void kxte9_read_data(u8 addr, int len) +{ + i2c_write_buf[0] = addr; + kxte9_msg[0].addr = KXTE9_I2C_ADDR; + kxte9_msg[0].flags = 0 ; + kxte9_msg[0].len = 1; + kxte9_msg[0].buf = i2c_write_buf; + kxte9_msg[1].addr = KXTE9_I2C_ADDR; + kxte9_msg[1].flags = I2C_M_RD; + kxte9_msg[1].len = len; + kxte9_msg[1].buf = i2c_read_buf; + wmt_i2c_transfer(kxte9_msg, 2, 0, kxte9_read_callback, 0); +} + +static int kxte9_i2c_read(u8 addr, u8 *data, int len) +{ +/* + int err; + + struct i2c_msg msgs[] = { + { + .addr = KXTE9_I2C_ADDR, + .flags = 0 & ~(I2C_M_RD), //te9->client->flags & I2C_M_TEN, + .len = 1, + .buf = &addr, + }, + { + .addr = KXTE9_I2C_ADDR, //te9->client->addr, + .flags = (I2C_M_RD), //(te9->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = data, + }, + }; + err = wmt_i2c_xfer_continue_if_4(msgs, 2, 0); + + if(err != 2) + errlog("read transfer error\n"); + else + err = 0; + + return err; +*/ + int ret; + ret = i2c_api_do_recv(0, KXTE9_I2C_ADDR, addr, data, len); + if (ret <= 0) { + errlog("i2c_api_do_recv error!\n"); + return -1; + } + return 0; +} + +static int kxte9_i2c_write(u8 addr, u8 *data, int len) +{ +/* + int err; + int i; + u8 buf[len + 1]; + + struct i2c_msg msgs[] = { + { + .addr = KXTE9_I2C_ADDR, //te9->client->addr, + .flags = 0 & ~(I2C_M_RD), //te9->client->flags & I2C_M_TEN, + .len = len + 1, + .buf = buf, + }, + }; + + buf[0] = addr; + for (i = 0; i < len; i++) + buf[i + 1] = data[i]; + + err = wmt_i2c_xfer_continue_if_4(msgs, 1, 0); + if(err != 1) + errlog("write transfer error\n"); + else + err = 0; + return err; +*/ + int ret; + ret = i2c_api_do_send(0, KXTE9_I2C_ADDR, addr, data, len); + if (ret <= 0) { + errlog("i2c_api_do_send error!\n"); + return -1; + } + return 0; + +} + +int kxte9_get_bits(u8 reg_addr, u8* bits_value, u8 bits_mask) +{ + int err; + u8 reg_data; + + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + return err; + + *bits_value = reg_data & bits_mask; + + return 1; +} + +int kxte9_get_byte(u8 reg_addr, u8* reg_value) +{ + int err; + u8 reg_data; + + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + return err; + + *reg_value = reg_data; + + return 1; +} + +int kxte9_set_bits(int res_index, u8 reg_addr, u8 bits_value, u8 bits_mask) +{ + int err=0, err1=0, retval=0; + u8 reg_data = 0x00, reg_bits = 0x00, bits_set = 0x00; + + // Turn off PC1 + reg_data = te9->resume[RES_CTRL_REG1] & ~PC1_ON; + + err = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err < 0) + goto exit0; + + // Read from device register + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + goto exit0; + + // Apply mask to device register; + reg_bits = reg_data & bits_mask; + + // Update resume state data + bits_set = bits_mask & bits_value; + te9->resume[res_index] &= ~bits_mask; + te9->resume[res_index] |= bits_set; + + // Return 0 if value in device register and value to be written is the same + if(reg_bits == bits_set) + retval = 0; + // Else, return 1 + else + retval = 1; + + // Write to device register + err = kxte9_i2c_write(reg_addr, &te9->resume[res_index], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", reg_addr, te9->resume[res_index], err); + if(err < 0) + goto exit0; + +exit0: + // Turn on PC1 + reg_data = te9->resume[RES_CTRL_REG1] | PC1_ON; + + err1 = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err1 < 0) + return err1; + + if(err < 0) + return err; + + return retval; +} + +int kxte9_set_byte(int res_index, u8 reg_addr, u8 reg_value) +{ + int err, err1, retval=0; + u8 reg_data; + + // Turn off PC1 + reg_data = te9->resume[RES_CTRL_REG1] & ~PC1_ON; + + err = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err < 0) + goto exit0; + + // Read from device register + err = kxte9_i2c_read(reg_addr, ®_data, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", reg_addr, reg_data, err); + if(err < 0) + goto exit0; + + // Update resume state data + te9->resume[res_index] = reg_value; + + // Return 0 if value in device register and value to be written is the same + if(reg_data == reg_value) + retval = 0; + // Else, return 1 + else + retval = 1; + + // Write to device register + err = kxte9_i2c_write(reg_addr, &te9->resume[res_index], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", reg_addr, te9->resume[res_index], err); + if(err < 0) + goto exit0; + +exit0: + // Turn on PC1 + reg_data = te9->resume[RES_CTRL_REG1] | PC1_ON; + err1 = kxte9_i2c_write(CTRL_REG1, ®_data, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, reg_data, err); + if(err1 < 0) + return err1; + + if(err < 0) + return err; + + return retval; +} + +int kxte9_set_pc1_off(void) +{ + u8 reg_data; + + reg_data = te9->resume[RES_CTRL_REG1] & ~PC1_ON; + + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, reg_data); + return kxte9_i2c_write(CTRL_REG1, ®_data, 1); +} + +int kxte9_set_pc1_on(void) +{ + u8 reg_data; + + reg_data = te9->resume[RES_CTRL_REG1] | PC1_ON; + + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, reg_data); + return kxte9_i2c_write(CTRL_REG1, ®_data, 1); +} + +static int kxte9_verify(void) +{ + int err; + u8 buf; + + err = kxte9_i2c_read(WHO_AM_I, &buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", WHO_AM_I, buf, err); + if(err < 0) + errlog( "read err int source\n"); + if(buf != 0) + err = -1; + return err; +} + +static int kxte9_hw_init(void) +{ + int err; + u8 buf = PC1_OFF; + + err = kxte9_i2c_write(CTRL_REG1, &buf, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, buf, err); + if(err < 0) + return err; + err = kxte9_i2c_write(CTRL_REG3, &te9->resume[RES_CTRL_REG3], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG3, te9->resume[RES_CTRL_REG3], err); + if(err < 0) + return err; + err = kxte9_i2c_write(INT_CTRL1, &te9->resume[RES_INT_CTRL1], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", INT_CTRL1, te9->resume[RES_INT_CTRL1], err); + if(err < 0) + return err; + err = kxte9_i2c_write(TILT_TIMER, &te9->resume[RES_TILT_TIMER], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", TILT_TIMER, te9->resume[RES_TILT_TIMER], err); + if(err < 0) + return err; + err = kxte9_i2c_write(WUF_TIMER, &te9->resume[RES_WUF_TIMER], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", WUF_TIMER, te9->resume[RES_WUF_TIMER], err); + if(err < 0) + return err; + err = kxte9_i2c_write(B2S_TIMER, &te9->resume[RES_B2S_TIMER], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", B2S_TIMER, te9->resume[RES_B2S_TIMER], err); + if(err < 0) + return err; + err = kxte9_i2c_write(WUF_THRESH, &te9->resume[RES_WUF_THRESH], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", WUF_THRESH, te9->resume[RES_WUF_THRESH], err); + if(err < 0) + return err; + err = kxte9_i2c_write(B2S_THRESH, &te9->resume[RES_B2S_THRESH], 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", B2S_THRESH, te9->resume[RES_B2S_THRESH], err); + if(err < 0) + return err; + buf = te9->resume[RES_CTRL_REG1] | PC1_ON; + err = kxte9_i2c_write(CTRL_REG1, &buf, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, buf, err); + if(err < 0) + return err; + + te9->resume[RES_CTRL_REG1] = buf; + te9->hw_initialized = 1; + + return 0; +} + +static void kxte9_device_power_off(void) +{ + int err; + u8 buf = PC1_OFF; + + err = kxte9_i2c_write(CTRL_REG1, &buf, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1), err=%d\n", CTRL_REG1, buf, err); + if(err < 0) + errlog("soft power off failed\n"); +#ifdef INT_MODE + ENABLE_SENSOR_INT(0); +// disable_irq(gconf.irq); +#endif + te9->hw_initialized = 0; +} + +static int kxte9_device_power_on(void) +{ + int err; + + if(!te9->hw_initialized) { + //mdelay(110); + err = kxte9_hw_init(); + if(err < 0) { + kxte9_device_power_off(); + return err; + } + } +#ifdef INT_MODE + ENABLE_SENSOR_INT(1); +// enable_irq(gconf.irq); +#endif + return 0; +} + +static u8 kxte9_resolve_dir(u8 dir) +{ + switch (dir) { + case 0x20: /* -X */ + if (gconf.xyz_axis[ABS_X][1] < 0) + dir = 0x10; + if (gconf.xyz_axis[ABS_Y][0] == 0) + dir >>= 2; + if (gconf.xyz_axis[ABS_Z][0] == 0) + dir >>= 4; + break; + case 0x10: /* +X */ + if (gconf.xyz_axis[ABS_X][1] < 0) + dir = 0x20; + if (gconf.xyz_axis[ABS_Y][0] == 0) + dir >>= 2; + if (gconf.xyz_axis[ABS_Z][0] == 0) + dir >>= 4; + break; + case 0x08: /* -Y */ + if (gconf.xyz_axis[ABS_Y][1] < 0) + dir = 0x04; + if (gconf.xyz_axis[ABS_X][0] == 1) + dir <<= 2; + if (gconf.xyz_axis[ABS_Z][0] == 1) + dir >>= 2; + break; + case 0x04: /* +Y */ + if (gconf.xyz_axis[ABS_Y][1] < 0) + dir = 0x08; + if (gconf.xyz_axis[ABS_X][0] == 1) + dir <<= 2; + if (gconf.xyz_axis[ABS_Z][0] == 1) + dir >>= 2; + break; + case 0x02: /* -Z */ + if (gconf.xyz_axis[ABS_Z][1] < 0) + dir = 0x01; + if (gconf.xyz_axis[ABS_X][0] == 2) + dir <<= 4; + if (gconf.xyz_axis[ABS_Y][0] == 2) + dir <<= 2; + break; + case 0x01: /* +Z */ + if (gconf.xyz_axis[ABS_Z][1] < 0) + dir = 0x02; + if (gconf.xyz_axis[ABS_X][0] == 2) + dir <<= 4; + if (gconf.xyz_axis[ABS_Y][0] == 2) + dir <<= 2; + break; + default: + return -EINVAL; + } + + return dir; +} + +#ifdef INT_MODE +static void kxte9_irq_work_func(struct work_struct *work) +{ +/* + * int_status output: + * [INT_SRC_REG1][INT_SRC_REG2][TILT_POS_PRE][TILT_POS_CUR] + * INT_SRC_REG2, TILT_POS_PRE, and TILT_POS_CUR directions are translated + * based on platform data variables. + */ + + int err; + int i; + int int_status = 0; + u8 status; + u8 b2s_comp; + u8 wuf_comp; + u8 buf[2]; + + err = kxte9_i2c_read(INT_STATUS_REG, &status, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_STATUS_REG, status, err); + if(err < 0) + errlog("read err int source\n"); + int_status = status << 24; + if((status & TPS) > 0) { + err = kxte9_i2c_read(TILT_POS_CUR, buf, 2); + kxte9_dbg("kxte9_i2c_read(%x, 2)=%x,%x, err=%d\n", TILT_POS_CUR, buf[0], buf[1], err); + if(err < 0) + errlog("read err tilt dir\n"); + int_status |= kxte9_resolve_dir(buf[0]); + int_status |= (kxte9_resolve_dir(buf[1])) << 8; + kxte9_dbg("IRQ TILT [%x]\n", kxte9_resolve_dir(buf[0])); + } + if((status & WUFS) > 0) { + kxte9_dbg("for WUFS\n"); + err = kxte9_i2c_read(INT_SRC_REG2, buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_SRC_REG2, buf[0], err); + if(err < 0) + kxte9_dbg("reading err wuf dir\n"); + int_status |= (kxte9_resolve_dir(buf[0])) << 16; + b2s_comp = (te9->resume[RES_CTRL_REG3] & 0x0C) >> 2; + wuf_comp = te9->resume[RES_CTRL_REG3] & 0x03; + if(!te9->resume[RES_CURRENT_ODR] && + !(te9->resume[RES_CTRL_REG1] & ODR125E) && + !(b2s_comp & wuf_comp)) { + /* set the new poll interval based on wuf odr */ + for (i = 0; i < ARRAY_SIZE(kxte9_odr_table); i++) { + if(kxte9_odr_table[i].mask == wuf_comp << 3) { + te9->pdata->poll_interval = kxte9_odr_table[i].interval; + break; + } + } + if(te9->input_dev) { + cancel_delayed_work_sync(&te9->input_work); + schedule_delayed_work(&te9->input_work, + msecs_to_jiffies(te9->pdata->poll_interval)); + } + } + } + if((status & B2SS) > 0) { + kxte9_dbg("fro B2SS\n"); + b2s_comp = (te9->resume[RES_CTRL_REG3] & 0x0C) >> 2; + wuf_comp = te9->resume[RES_CTRL_REG3] & 0x03; + if(!te9->resume[RES_CURRENT_ODR] && + !(te9->resume[RES_CTRL_REG1] & ODR125E) && + !(b2s_comp & wuf_comp)) { + /* set the new poll interval based on b2s odr */ + for (i = 1; i < ARRAY_SIZE(kxte9_odr_table); i++) { + if(kxte9_odr_table[i].mask == b2s_comp << 3) { + te9->pdata->poll_interval = kxte9_odr_table[i].interval; + break; + } + } + if(te9->input_dev) { + cancel_delayed_work_sync(&te9->input_work); + schedule_delayed_work(&te9->input_work, + msecs_to_jiffies(te9->pdata->poll_interval)); + } + } + } + input_report_abs(te9->input_dev, ABS_MISC, int_status); + input_sync(te9->input_dev); + err = kxte9_i2c_read(INT_REL, buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_REL, buf[0], err); + if(err < 0) + errlog("error clearing interrupt\n"); + //enable_irq(gconf.irq); +} + +static irqreturn_t kxte9_isr(int irq, void *dev) +{ + unsigned int status = REG32_VAL(gconf.isaddr); + + // clr int status ...?? + if ((status & gconf.isbmp) != 0) + { + kxte9_dbg("\n"); + REG32_VAL(gconf.isaddr) |= gconf.isbmp; + udelay(5); + // disable int and satrt irq work + disable_irq_nosync(irq); + schedule_work(&te9->irq_work); + return IRQ_HANDLED; + } + return IRQ_NONE; +} +#endif + +static int kxte9_update_odr(int poll_interval) +{ + int err = -1; + int i; + u8 config; + + /* Convert the poll interval into an output data rate configuration + * that is as low as possible. The ordering of these checks must be + * maintained due to the cascading cut off values - poll intervals are + * checked from shortest to longest. At each check, if the next lower + * ODR cannot support the current poll interval, we stop searching */ + for (i = 0; i < ARRAY_SIZE(kxte9_odr_table); i++) { + config = kxte9_odr_table[i].mask; + if(poll_interval >= kxte9_odr_table[i].interval) + break; + } + + config |= (te9->resume[RES_CTRL_REG1] & ~(ODR40E | ODR125E)); + te9->resume[RES_CTRL_REG1] = config; + if(atomic_read(&te9->enabled)) { + err = kxte9_set_byte(RES_CTRL_REG1, CTRL_REG1, config); + if(err < 0) + return err; + } + klog("Set new ODR to 0x%02X\n", config); + return 0; +} + +static void kxte9_input_work_func(unsigned long unused) +{ + //mutex_lock(&te9->lock); + if (te9->suspend) + return; + if (te9->i2c_xfer_complete) { + te9->i2c_xfer_complete = 0; + kxte9_read_data(XOUT, 3); + } + //mutex_unlock(&te9->lock); +} + +static int kxte9_enable(void) +{ + int err; + int int_status = 0; + u8 buf; + + if(!atomic_cmpxchg(&te9->enabled, 0, 1)) { + err = kxte9_device_power_on(); + err = kxte9_i2c_read(INT_REL, &buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", INT_REL, buf, err); + if(err < 0) { + errlog("error clearing interrupt: %d\n", err); + atomic_set(&te9->enabled, 0); + return err; + } + if((te9->resume[RES_CTRL_REG1] & TPS) > 0) { + err = kxte9_i2c_read(TILT_POS_CUR, &buf, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x, err=%d\n", TILT_POS_CUR, buf, err); + if(err < 0) + errlog("kxte9 error reading current tilt\n"); + int_status |= kxte9_resolve_dir(buf); + input_report_abs(te9->input_dev, ABS_MISC, int_status); + input_sync(te9->input_dev); + } + kxte9_msg = kzalloc(2*sizeof(struct i2c_msg), GFP_ATOMIC); + i2c_read_buf = kzalloc(3*sizeof(unsigned char), GFP_ATOMIC); + i2c_write_buf = kzalloc(sizeof(char), GFP_ATOMIC); + setup_timer(&kxte9_timer, kxte9_input_work_func, 0); + mod_timer(&kxte9_timer, jiffies + msecs_to_jiffies(te9->pdata->poll_interval)); + kxte9_dbg("Enabled\n"); + } + return 0; +} + +static int kxte9_disable(void) +{ + if(atomic_cmpxchg(&te9->enabled, 1, 0)) { + del_timer_sync(&kxte9_timer); + wait_i2c_xfer_complete(); + kfree(kxte9_msg); + kfree(i2c_read_buf); + kfree(i2c_write_buf); +#ifdef WM3445_A0 + ENABLE_SENSOR_INT(1); +#endif + kxte9_device_power_off(); + kxte9_dbg(" Disabled\n"); + //#endif + } + return 0; +} + +int kxte9_input_open(struct input_dev *input) +{ + kxte9_dbg("\n"); + return kxte9_enable(); +} + +void kxte9_input_close(struct input_dev *dev) +{ + kxte9_dbg("\n"); + kxte9_disable(); +} + +static int kxte9_input_init(void) +{ + int err; + + te9->input_dev = input_allocate_device(); + if(!te9->input_dev) { + err = -ENOMEM; + errlog("input device allocate failed\n"); + goto err0; + } + te9->input_dev->open = kxte9_input_open; + te9->input_dev->close = kxte9_input_close; + + input_set_drvdata(te9->input_dev, te9); + + set_bit(EV_ABS, te9->input_dev->evbit); + set_bit(ABS_MISC, te9->input_dev->absbit); + + input_set_abs_params(te9->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(te9->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(te9->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + te9->input_dev->name = INPUT_NAME_ACC; + + err = input_register_device(te9->input_dev); + if(err) { + errlog("unable to register input polled device %s: %d\n", + te9->input_dev->name, err); + goto err1; + } + + return 0; +err1: + input_free_device(te9->input_dev); +err0: + return err; +} + +static void kxte9_input_cleanup(void) +{ + input_unregister_device(te9->input_dev); +} + +/* sysfs */ +static ssize_t kxte9_delay_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", te9->pdata->poll_interval); +} + +static ssize_t kxte9_delay_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl; + + te9->pdata->poll_interval = max(val, te9->pdata->min_interval); + kxte9_update_odr(te9->pdata->poll_interval); + ctrl = te9->resume[RES_CTRL_REG1] & 0x18; + te9->resume[RES_CURRENT_ODR] = ctrl; + /* All ODRs are changed when this method is used. */ + ctrl = (ctrl >> 1) | (ctrl >> 3); + kxte9_i2c_write(CTRL_REG3, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG3, ctrl); + te9->resume[RES_CTRL_REG3] = ctrl; + return count; +} + +static ssize_t kxte9_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", atomic_read(&te9->enabled)); +} + +static ssize_t kxte9_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + if(val) + kxte9_enable(); + else + kxte9_disable(); + return count; +} + +static ssize_t kxte9_tilt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 tilt; + + if(te9->resume[RES_CTRL_REG1] & TPE) { + kxte9_i2c_read(TILT_POS_CUR, &tilt, 1); + kxte9_dbg("kxte9_i2c_read(%x, 1)=%x\n", TILT_POS_CUR, tilt); + return sprintf(buf, "%d\n", kxte9_resolve_dir(tilt)); + } else { + return sprintf(buf, "%d\n", 0); + } +} + +static ssize_t kxte9_tilt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl; + if(val) + te9->resume[RES_CTRL_REG1] |= TPE; + else + te9->resume[RES_CTRL_REG1] &= (~TPE); + ctrl = te9->resume[RES_CTRL_REG1]; + kxte9_i2c_write(CTRL_REG1, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, ctrl); + return count; +} + +static ssize_t kxte9_wake_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 val = te9->resume[RES_CTRL_REG1] & WUFE; + if(val) + return sprintf(buf, "%d\n", 1); + else + return sprintf(buf, "%d\n", 0); +} + +static ssize_t kxte9_wake_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl; + if(val) + te9->resume[RES_CTRL_REG1] |= (WUFE | B2SE); + else + te9->resume[RES_CTRL_REG1] &= (~WUFE & ~B2SE); + ctrl = te9->resume[RES_CTRL_REG1]; + kxte9_i2c_write(CTRL_REG1, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(%x, %x, 1)\n", CTRL_REG1, ctrl); + return count; +} + +static ssize_t kxte9_selftest_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int val = simple_strtoul(buf, NULL, 10); + u8 ctrl = 0x00; + if(val) + ctrl = 0xCA; + kxte9_i2c_write(0x3A, &ctrl, 1); + kxte9_dbg("kxte9_i2c_write(0x3A, %x, 1)\n", ctrl); + return count; +} + +static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR, kxte9_delay_show, kxte9_delay_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, kxte9_enable_show, + kxte9_enable_store); +static DEVICE_ATTR(tilt, S_IRUGO|S_IWUSR, kxte9_tilt_show, kxte9_tilt_store); +static DEVICE_ATTR(wake, S_IRUGO|S_IWUSR, kxte9_wake_show, kxte9_wake_store); +static DEVICE_ATTR(selftest, S_IWUSR, NULL, kxte9_selftest_store); + +static struct attribute *kxte9_attributes[] = { + &dev_attr_delay.attr, + &dev_attr_enable.attr, + &dev_attr_tilt.attr, + &dev_attr_wake.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group kxte9_attribute_group = { + .attrs = kxte9_attributes +}; +/* /sysfs */ + +static int kxte9_get_count(char *buf, int bufsize) +{ + const char ACC_REG_SIZE = 3; + int err; + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + u8 acc_data[ACC_REG_SIZE]; + /* x,y,z hardware values */ + int xyz[3]; + + if((!buf)||(bufsize<=(sizeof(xyz)*3))) + return -1; + + err = kxte9_i2c_read(XOUT, acc_data, ACC_REG_SIZE); + kxte9_dbg("kxte9_i2c_read(%x, %x)=%x,%x,%x, err=%d\n", XOUT, ACC_REG_SIZE, + acc_data[0], acc_data[1], acc_data[2], err); + if(err < 0) + return err; + + sprintf(buf, "%d %d %d", acc_data[0], acc_data[1], acc_data[2]); + + return err; +} + +static int kxte9_get_mg(char *buf, int bufsize) +{ + const char ACC_REG_SIZE = 3; + int err; + /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ + u8 acc_data[ACC_REG_SIZE]; + /* x,y,z hardware values */ + int xyz[3], mg[3]; + + if((!buf)||(bufsize<=(sizeof(mg)))) + return -1; + + err = kxte9_i2c_read(XOUT, acc_data, ACC_REG_SIZE); + kxte9_dbg("kxte9_i2c_read(%x, %x)=%x,%x,%x, err=%x\n", XOUT, ACC_REG_SIZE, + acc_data[0], acc_data[1], acc_data[2], err); + if(err < 0) + return err; + + xyz[0] = ((int)(acc_data[0]) - OFFSET) << 4; + xyz[1] = ((int)(acc_data[1]) - OFFSET) << 4; + xyz[2] = ((int)(acc_data[2]) - OFFSET) << 4; + + mg[0] = X_CONVERT(xyz[gconf.xyz_axis[ABS_X][0]]); + mg[1] = Y_CONVERT(xyz[gconf.xyz_axis[ABS_Y][0]]); + mg[2] = Z_CONVERT(xyz[gconf.xyz_axis[ABS_Z][0]]); + + sprintf(buf, "%d %d %d",mg[0], mg[1], mg[2]); + + kxte9_dbg(" [%5d] [%5d] [%5d]\n", mg[0], mg[1], mg[2]); + + return err; +} + +static void kxte9_dump_reg(void) +{ + u8 regval = 0; + + klog("**********************kxte9 reg val***************\n"); + // ct_resp + kxte9_i2c_read(CT_RESP, ®val, 1); + klog("ct_resp:0x%x\n", regval); + // who_am_i + kxte9_i2c_read(WHO_AM_I, ®val, 1); + klog("who_am_i:0x%x\n", regval); + // tilt_pos_cur + kxte9_i2c_read(TILT_POS_CUR, ®val, 1); + klog("tilt_pos_cur:0x%x\n", regval); + // int_src_reg1 + kxte9_i2c_read(INT_STATUS_REG, ®val, 1); + klog("int_src_reg1:0x%x\n", regval); + // int_src_reg2 + kxte9_i2c_read(INT_SRC_REG2, ®val, 1); + klog("int_src_reg2:0x%x\n", regval); + // status_reg + kxte9_i2c_read(0x18, ®val, 1); + klog("status_reg:0x%x\n", regval); + // int_rel + kxte9_i2c_read(INT_REL, ®val, 1); + klog("int_rel:0x%x\n", regval); + // ctrl_reg1 + kxte9_i2c_read(CTRL_REG1, ®val, 1); + klog("ctrl_reg1:0x%x\n", regval); + // ctrl_reg2 + kxte9_i2c_read(CTRL_REG2, ®val, 1); + klog("ctrl_reg2:0x%x\n", regval); + // ctrl_reg3 + kxte9_i2c_read(CTRL_REG3, ®val, 1); + klog("ctrl_reg3:0x%x\n", regval); + // int_ctrl_reg1 + kxte9_i2c_read(INT_CTRL1, ®val, 1); + klog("int_ctrl_reg1:0x%x\n", regval); + // int_ctrl_reg2 + kxte9_i2c_read(0x1F, ®val, 1); + klog("int_ctrl_reg2:0x%x\n", regval); + // tilt_timer + kxte9_i2c_read(TILT_TIMER, ®val, 1); + klog("tilt_timer:0x%x\n", regval); + // wuf_timer + kxte9_i2c_read(WUF_TIMER, ®val, 1); + klog("wuf_timer:0x%x\n", regval); + // b2s_timer + kxte9_i2c_read(B2S_TIMER, ®val, 1); + klog("b2s_timer:0x%x\n", regval); + // wuf_thresh + kxte9_i2c_read(WUF_THRESH, ®val, 1); + klog("wuf_thresh:0x%x\n", regval); + // b2s_thresh + kxte9_i2c_read(B2S_THRESH, ®val, 1); + klog("b2s_thresh:0x%x\n", regval); + // tilt_angle + kxte9_i2c_read(0x5c, ®val, 1); + klog("tilt_angle:0x%x\n", regval); + // hyst_set + kxte9_i2c_read(0x5f, ®val, 1); + klog("hyst_set:0x%x\n", regval); + klog("**********************************************************"); +} + +static int kxte9_open(struct inode *inode, struct file *file) +{ + int ret = -1; + + if(kxte9_enable() < 0) + return ret; + + atomic_inc(&kxte9_dev_open_count); + kxte9_dbg("opened %d times\n",\ + atomic_read(&kxte9_dev_open_count)); + kxte9_dump_reg(); + return 0; +} + +static int kxte9_release(struct inode *inode, struct file *file) +{ + int open_count; + + atomic_dec(&kxte9_dev_open_count); + open_count = (int)atomic_read(&kxte9_dev_open_count); + + if(open_count == 0) + kxte9_disable(); + + kxte9_dbg("opened %d times\n",\ + atomic_read(&kxte9_dev_open_count)); + return 0; +} + +static int kxte9_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + char buffer[IOCTL_BUFFER_SIZE]; + void __user *data; + u8 reg_buffer = 0x00; + const u8 set = 0xFF, unset = 0x00; + int retval=0, val_int=0; + short val_short=0; + + switch (cmd) { + case KXTE9_IOCTL_GET_COUNT: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_count(buffer, sizeof(buffer)); + if(retval < 0) + goto err_out; + + if(copy_to_user(data, buffer, sizeof(buffer))) { + retval = -EFAULT; + goto err_out; + } + break; + + case KXTE9_IOCTL_GET_MG: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_mg(buffer, sizeof(buffer)); + if(retval < 0) + goto err_out; + + if(copy_to_user(data, buffer, sizeof(buffer))) { + retval = -EFAULT; + goto err_out; + } + break; + + case KXTE9_IOCTL_ENABLE_OUTPUT: + retval = kxte9_set_pc1_on(); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_DISABLE_OUTPUT: + retval = kxte9_set_pc1_off(); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_GET_ENABLE: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_bits(CTRL_REG1, ®_buffer, PC1_ON); + if(retval < 0) + goto err_out; + + val_short = (short)reg_buffer; + + if(copy_to_user(data, &val_short, sizeof(val_short))) { + retval = -EFAULT; + goto err_out; + } + break; + + case KXTE9_IOCTL_RESET: + retval = kxte9_set_bits(RES_CTRL_REG3, CTRL_REG3, set, SRST); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_UPDATE_ODR: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + if(copy_from_user(&val_int, data, sizeof(val_int))) { + retval = -EFAULT; + goto err_out; + } + + mutex_lock(&te9->lock); + te9->pdata->poll_interval = max(val_int, te9->pdata->min_interval); + mutex_unlock(&te9->lock); + + retval = kxte9_update_odr(te9->pdata->poll_interval); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_ENABLE_CTC: + retval = kxte9_set_bits(RES_CTRL_REG3, CTRL_REG3, set, CTC); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_DISABLE_CTC: + retval = kxte9_set_bits(RES_CTRL_REG3, CTRL_REG3, unset, CTC); + if(retval < 0) + goto err_out; + break; + + case KXTE9_IOCTL_GET_CT_RESP: + data = (void __user *) arg; + if(data == NULL){ + retval = -EFAULT; + goto err_out; + } + retval = kxte9_get_byte(CT_RESP, ®_buffer); + if(retval < 0) + goto err_out; + + buffer[0] = (char)reg_buffer; + if(copy_to_user(data, buffer, sizeof(buffer))) { + retval = -EFAULT; + goto err_out; + } + break; + + default: + retval = -ENOIOCTLCMD; + break; + } + +err_out: + return retval; +} + +static struct file_operations kxte9_fops = { + .owner = THIS_MODULE, + .open = kxte9_open, + .release = kxte9_release, + //.ioctl = kxte9_ioctl, +}; + +static struct miscdevice kxte9_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = NAME_DEV, + .fops = &kxte9_fops, +}; + +static int kxte9_probe(void) +{ + int err = -1; + + te9 = kzalloc(sizeof(*te9), GFP_KERNEL); + if(te9 == NULL) { + errlog("failed to allocate memory for module data\n"); + err = -ENOMEM; + goto err0; + } + te9->pdata = &kxte9_pdata; + mutex_init(&te9->lock); + mutex_lock(&te9->lock); + + x_count = kzalloc(gconf.avg_count, GFP_KERNEL); + y_count = kzalloc(gconf.avg_count, GFP_KERNEL); + z_count = kzalloc(gconf.avg_count, GFP_KERNEL); + + if ((1000000/gconf.samp)%1000) + te9->pdata->poll_interval = 1000/gconf.samp + 1; + else + te9->pdata->poll_interval = 1000/gconf.samp; + printk(KERN_INFO "G-Sensor Time Interval: %d ms\n", te9->pdata->poll_interval); + + android_gsensor_kobj = kobject_create_and_add("kxte9_gsensor", NULL); + if (android_gsensor_kobj == NULL) { + errlog("gsensor_sysfs_init:subsystem_register failed\n"); + err = -ENOMEM; + goto err0; + } + + err = sysfs_create_group(android_gsensor_kobj, &kxte9_attribute_group); + if(err) + goto err1; + + if(te9->pdata->init) { + err = te9->pdata->init(); + if(err < 0) + goto err2; + } + + memset(te9->resume, 0, ARRAY_SIZE(te9->resume)); + te9->resume[RES_CTRL_REG1] = te9->pdata->ctrl_reg1_init; + te9->resume[RES_CTRL_REG3] = te9->pdata->engine_odr_init; + te9->resume[RES_INT_CTRL1] = te9->pdata->int_ctrl_init; + te9->resume[RES_TILT_TIMER] = te9->pdata->tilt_timer_init; + te9->resume[RES_WUF_TIMER] = te9->pdata->wuf_timer_init; + te9->resume[RES_B2S_TIMER] = te9->pdata->b2s_timer_init; + te9->resume[RES_WUF_THRESH] = te9->pdata->wuf_thresh_init; + te9->resume[RES_B2S_THRESH] = te9->pdata->b2s_thresh_init; + te9->hw_initialized = 0; + te9->i2c_xfer_complete = 1; + +#ifdef INT_MODE + // init gpio + SET_GPIO_GSENSOR_INT(); + INIT_WORK(&te9->irq_work, kxte9_irq_work_func); +#endif + + err = kxte9_device_power_on(); + if(err < 0) + goto err3; + atomic_set(&te9->enabled, 1); + + err = kxte9_verify(); + if(err < 0) { + errlog("kxte9_verify failed\n"); + goto err4; + } + + err = kxte9_update_odr(te9->pdata->poll_interval); + if(err < 0) { + errlog("update_odr failed\n"); + goto err4; + } + + err = kxte9_input_init(); + if(err < 0) + goto err4; + + err = misc_register(&kxte9_device); + if(err) { + errlog("misc. device failed to register.\n"); + goto err5; + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + te9->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + te9->earlysuspend.suspend = kxte9_early_suspend; + te9->earlysuspend.resume = kxte9_late_resume; + register_early_suspend(&te9->earlysuspend); +#endif + + atomic_set(&te9->enabled, 0); + +#ifdef INT_MODE + err = request_irq(gconf.irq, kxte9_isr, + IRQF_TRIGGER_RISING | IRQF_DISABLED, "kxte9_irq", te9); + if(err < 0) { + pr_err("%s: request irq failed: %d\n", __func__, err); + goto err6; + } + +#ifdef WM3445_A0 + // enable int + ENABLE_SENSOR_INT(1); +#endif + + // enable kxte9 + /*err = kxte9_enable(); + if (err < 0) { + errlog("kxte9_enable failed.\n"); + goto err6; + }*/ +#endif + + mutex_unlock(&te9->lock); + //kxte9_dump_reg(); + + return 0; + +#ifdef INT_MODE +err6: + misc_deregister(&kxte9_device); +#endif +err5: + kxte9_input_cleanup(); +err4: + kxte9_device_power_off(); +err3: + if(te9->pdata->exit) + te9->pdata->exit(); +err2: + //kfree(te9->pdata); + sysfs_remove_group(android_gsensor_kobj, &kxte9_attribute_group); +err1: + kobject_del(android_gsensor_kobj); + mutex_unlock(&te9->lock); + kfree(te9); +err0: + return err; +} + +static int kxte9_remove(void) +{ + cancel_delayed_work_sync(&te9->input_work); +#ifdef INT_MODE + free_irq(gconf.irq, te9); +#endif + kxte9_input_cleanup(); + misc_deregister(&kxte9_device); + kxte9_device_power_off(); + if(te9->pdata->exit) + te9->pdata->exit(); + kobject_del(android_gsensor_kobj); + sysfs_remove_group(android_gsensor_kobj, &kxte9_attribute_group); + kfree(te9); + + return 0; +} + +#ifdef CONFIG_PM +#if 0 +#ifdef CONFIG_HAS_EARLYSUSPEND +static void kxte9_early_suspend(struct early_suspend *h) +{ + kxte9_dbg("start\n"); + te9->suspend = 1; + kxte9_disable(); + kxte9_dbg("exit\n"); +} + +static void kxte9_late_resume(struct early_suspend *h) +{ + kxte9_dbg("start\n"); + te9->suspend = 0; + kxte9_enable(); + kxte9_dbg("exit\n"); +} +#endif +#endif +static int kxte9_resume(struct platform_device *pdev) +{ + te9->suspend = 0; + kxte9_enable(); + return 0; +} + +static int kxte9_suspend(struct platform_device *pdev, pm_message_t state) +{ + te9->suspend = 1; + kxte9_disable(); + return 0; +} +#endif + +static void kxte9_platform_release(struct device *device) +{ + kxte9_dbg("Do nothing!!!\n"); + return; +} + +static struct platform_device kxte9_plt_device = { + .name = "kxte9", + .id = 0, + .dev = { + .release = kxte9_platform_release, + }, +}; + +static struct platform_driver kxte9_plt_driver = { + .probe = NULL, //kxte9_probe, + .remove = NULL, //kxte9_remove, + .suspend = kxte9_suspend, + .resume = kxte9_resume, + .driver = { + .name = "kxte9", + }, +}; + +/* + * Get the configure of sensor from u-boot. + * Return: 1--success, 0--error. + */ +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.gsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "KXTE9: wmt.io.gsensor not defined!\n"); + return 0; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &gconf.op, + &gconf.samp, + &(gconf.xyz_axis[0][0]), + &(gconf.xyz_axis[0][1]), + &(gconf.xyz_axis[1][0]), + &(gconf.xyz_axis[1][1]), + &(gconf.xyz_axis[2][0]), + &(gconf.xyz_axis[2][1]), + &gconf.avg_count, + &gconf.kxte9_8bit); + + if (n != 10) { + kxte9_dbg(KERN_ERR "KXTE9: wmt.io.gsensor format is incorrect!\n"); + return 0; + } + } + if (gconf.op != 1) + return 0; + printk(KERN_INFO "KXTE9 G-Sensor driver init\n"); + kxte9_dbg("AVG Count: %d, KXTE9 8bit: %d\n", + gconf.avg_count, + gconf.kxte9_8bit); + if (gconf.samp > 100) { + printk(KERN_ERR "Sample Rate can't be greater than 100 !\n"); + gconf.samp = 100; + } + if (gconf.avg_count == 0) + gconf.avg_count = 1; + if (gconf.kxte9_8bit > 1) + gconf.kxte9_8bit = 1; + kxte9_dbg("wmt.io.gsensor = %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + gconf.op, + gconf.samp, + gconf.xyz_axis[0][0], + gconf.xyz_axis[0][1], + gconf.xyz_axis[1][0], + gconf.xyz_axis[1][1], + gconf.xyz_axis[2][0], + gconf.xyz_axis[2][1], + gconf.avg_count, + gconf.kxte9_8bit); + return 1; +} + +static int get_gpioset(void) +{ + char varbuf[96]; + int n; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.gpt.gsensor", varbuf, &varlen)) { + printk(KERN_DEBUG "Can't get gsensor's gpio config from u-boot! -> Use default config\n"); + return 0; + } else { + n = sscanf(varbuf, "%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x:%x", + &gconf.name, + &gconf.bmp, + &(gconf.ctraddr), + &(gconf.ocaddr), + &(gconf.idaddr), + &(gconf.peaddr), + &(gconf.pcaddr), + &(gconf.itbmp), + &(gconf.itaddr), + &(gconf.isbmp), + &(gconf.isaddr), + &(gconf.irq)); + if (n != 12) { + printk(KERN_ERR "wmt.gpt.gsensor format is incorrect in u-boot!!!\n"); + return 0; + } + + gconf.ctraddr += WMT_MMAP_OFFSET; + gconf.ocaddr += WMT_MMAP_OFFSET; + gconf.idaddr += WMT_MMAP_OFFSET; + gconf.peaddr += WMT_MMAP_OFFSET; + gconf.pcaddr += WMT_MMAP_OFFSET; + gconf.itaddr += WMT_MMAP_OFFSET; + gconf.isaddr += WMT_MMAP_OFFSET; + } + return 1; +} + +static int __init kxte9_init(void) +{ + int ret = 0; + + // parsing u-boot arg + ret = get_axisset(); // get gsensor config from u-boot + if (!ret) + return -EINVAL; + + get_gpioset(); + + // initail + if ((ret = kxte9_probe()) != 0) { + errlog(" Error for kxte9_probe !!!\n"); + return ret; + } + atomic_set(&kxte9_dev_open_count, 0); + + if ((ret = platform_device_register(&kxte9_plt_device)) != 0) { + errlog("Can't register kxte9_plt_device platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&kxte9_plt_driver)) != 0) { + errlog("Can't register kxte9_plt_driver platform driver!!!\n"); + return ret; + } + klog("gsensor_kxte9 driver is loaded successfully!\n"); + return ret; +} + +static void __exit kxte9_exit(void) +{ + platform_driver_unregister(&kxte9_plt_driver); + platform_device_unregister(&kxte9_plt_device); + atomic_set(&kxte9_dev_open_count, 0); + kxte9_remove(); +} + +module_init(kxte9_init); +module_exit(kxte9_exit); + +MODULE_DESCRIPTION("KXTE9 accelerometer driver"); +MODULE_AUTHOR("Kuching Tan <kuchingtan@kionix.com>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION_DEV); diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h new file mode 100755 index 00000000..6b5141e5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/kxte9.h @@ -0,0 +1,116 @@ +/* include/linux/kxte9.h - KXTE9 accelerometer driver + * + * Copyright (C) 2010 Kionix, Inc. + * Written by Kuching Tan <kuchingtan@kionix.com> + * + * 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 3 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 __KXTE9_H__ +#define __KXTE9_H__ + +#define KXTE9_I2C_ADDR 0x0F +/* CONTROL REGISTER 1 BITS */ +#define TPE 0x01 /* tilt position function enable bit */ +#define WUFE 0x02 /* wake-up function enable bit */ +#define B2SE 0x04 /* back-to-sleep function enable bit */ +#define ODR125E 0x20 /* 125Hz ODR mode */ +#define ODR40E 0x18 /* initial ODR masks */ +#define ODR10E 0x10 +#define ODR3E 0x08 +#define ODR1E 0x00 +/* CONTROL REGISTER 3 BITS */ +#define SRST 0x80 /* software reset */ +#define CTC 0x10 /* communication-test function */ +#define OB2S40 0x0C /* back-to-sleep ODR masks */ +#define OB2S10 0x08 +#define OB2S3 0x04 +#define OB2S1 0x00 +#define OWUF40 0x03 /* wake-up ODR masks */ +#define OWUF10 0x02 +#define OWUF3 0x01 +#define OWUF1 0x00 +/* INTERRUPT CONTROL REGISTER 1 BITS */ +#define KXTE9_IEN 0x10 /* interrupt enable */ +#define KXTE9_IEA 0x08 /* interrupt polarity */ +#define KXTE9_IEL 0x04 /* interrupt response */ + +/* Device Meta Data */ +#define DESC_DEV "KXTE9 3-axis Accelerometer" // Device Description +#define VERSION_DEV "1.1.7" +#define VER_MAJOR_DEV 1 +#define VER_MINOR_DEV 1 +#define VER_MAINT_DEV 7 +#define MAX_G_DEV (2.0f) // Maximum G Level +#define MAX_SENS_DEV (1024.0f) // Maximum Sensitivity +#define PWR_DEV (0.03f) // Typical Current + +/* Input Device Name */ +//#define INPUT_NAME_ACC "kxte9_accel" +#define INPUT_NAME_ACC "g-sensor" + +/* Device name for kxte9 misc. device */ +#define NAME_DEV "kxte9" +#define DIR_DEV "/dev/kxte9" + +/* IOCTLs for kxte9 misc. device library */ +#define KXTE9IO 0x92 +#define KXTE9_IOCTL_GET_COUNT _IOR(KXTE9IO, 0x01, int) +#define KXTE9_IOCTL_GET_MG _IOR(KXTE9IO, 0x02, int) +#define KXTE9_IOCTL_ENABLE_OUTPUT _IO(KXTE9IO, 0x03) +#define KXTE9_IOCTL_DISABLE_OUTPUT _IO(KXTE9IO, 0x04) +#define KXTE9_IOCTL_GET_ENABLE _IOR(KXTE9IO, 0x05, int) +#define KXTE9_IOCTL_RESET _IO(KXTE9IO, 0x06) +#define KXTE9_IOCTL_UPDATE_ODR _IOW(KXTE9IO, 0x07, int) +#define KXTE9_IOCTL_ENABLE_CTC _IO(KXTE9IO, 0x08) +#define KXTE9_IOCTL_DISABLE_CTC _IO(KXTE9IO, 0x09) +#define KXTE9_IOCTL_GET_CT_RESP _IOR(KXTE9IO, 0x0A, int) + + +#ifdef __KERNEL__ +struct kxte9_platform_data { + int poll_interval; + int min_interval; + /* the desired g-range, in milli-g (always 2000 for kxte9) */ + u8 g_range; + /* used to compensate for alternate device placement within the host */ +/* + u8 axis_map_x; + u8 axis_map_y; + u8 axis_map_z; + u8 negate_x; + u8 negate_y; + u8 negate_z; +*/ + /* initial configuration values, set during board configuration */ + u8 ctrl_reg1_init; + u8 engine_odr_init; + u8 int_ctrl_init; + u8 tilt_timer_init; + u8 wuf_timer_init; + u8 b2s_timer_init; + u8 wuf_thresh_init; + u8 b2s_thresh_init; + + int (*init)(void); + void (*exit)(void); +//NelsonTmp{ +// int gpio; +//} +}; +#endif /* __KERNEL__ */ + +#endif /* __KXTE9_H__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt new file mode 100755 index 00000000..e4653a08 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/kxte9_gsensor/readme.txt @@ -0,0 +1,47 @@ +The back of WM3445 MID
+ ______________
+| +z |
+| \ @ |
+| \ |
+| ---- +y |
+| | |
+| | |
+| +x |
+|______________|
+(KXTE9-2050 Accelerometer)
+
+wmt.io.gsensor
+Configure G-Sensor for Enable/Disable,X,Y,Z axis mapping and sampling rate. If driver not detect this variable, then G-sensor driver won¡¦t be loaded.
+<op>:<freq>:<axis-X>:<X-dir>:<axis-Y>:<Y-dir>:<axis-Z>:<Z-dir>:<avg-count>:<8bit>
+<op>:= Operation mode for the g-sensor
+0 : KXTE9-2050 G-Sensor is disabled.
+1 : KXTE9-2050 G-Sensor is enabled.
+<freq>:= G-Sensor sampling rate. The valid values are 1,3,10,and 40.
+<axis-X>:= G-Sensor axis-x will map to which axis of device.
+0 : X
+1 : Y
+2 : Z
+<X-dir>:= If G-Sensor axis-x direction is the same as device.
+1 : Positive direction
+-1 : Negative direction
+<axis-Y>:= G-Sensor axis-y will map to which axis of device.
+0 : X
+1 : Y
+2 : Z
+<Y-dir>:= If G-Sensor axis-y direction is the same as device.
+1 : Positive direction
+-1 : Negative direction
+<axis-Z>:= G-Sensor axis-z will map to which axis of device.
+0 : X
+1 : Y
+2 : Z
+<Z-dir>:= If G-Sensor axis-z direction is the same as device.
+1 : Positive direction
+-1 : Negative direction
+<avg-count>:= For every new/current axes values stored, add the newly stored axes with previously (avg-count-1) stored axes values and do an average
+<8bit>:= Using acceleration data as 8bit
+0 : 6bit
+1 : 8bit
+Ex:
+#KXTE9-2050 G-sensor enabled, using 40 sampling rate, X->-Y, Y->X, Z->-Z, 4 average count, using 8bit
+setenv wmt.io.gsensor 1:40:1:-1:0:-1:2:-1:4:1
diff --git a/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile new file mode 100755 index 00000000..2818c82f --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/Makefile @@ -0,0 +1,5 @@ +#
+# Makefile for the kernel device drivers.
+#
+obj-$(CONFIG_WMT_GYRO_L3G4200D) += s_wmt_gyro_l3g4200d.o
+s_wmt_gyro_l3g4200d-objs := l3g4200d_gyr.o
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h new file mode 100755 index 00000000..4cae2bc5 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d.h @@ -0,0 +1,108 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* +* File Name : l3g4200d.h +* Authors : MH - C&I BU - Application Team +* : Carmine Iascone (carmine.iascone@st.com) +* : Matteo Dameno (matteo.dameno@st.com) +* Version : V 1.1 sysfs +* Date : 2010/Aug/19 +* Description : L3G4200D digital output gyroscope sensor API +* +******************************************************************************** +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +******************************************************************************** +* REVISON HISTORY +* +* VERSION | DATE | AUTHORS | DESCRIPTION +* 1.0 | 2010/Aug/19 | Carmine Iascone | First Release +* 1.1 | 2011/02/28 | Matteo Dameno | Self Test Added +* 1.2 | 2013/04/29 | Howay Huo | Android Interface Added +*******************************************************************************/ + +#ifndef __L3G4200D_H__ +#define __L3G4200D_H__ + +#define L3G4200D_GYR_DEV_NAME "l3g4200d_gyr" +#define GYRO_INPUT_NAME "gyroscope" +#define GYRO_MISCDEV_NAME "gyro_ctrl" + +#define L3G4200D_DRVID 0 + +#define L3G4200D_GYR_FS_250DPS 0x00 +#define L3G4200D_GYR_FS_500DPS 0x10 +#define L3G4200D_GYR_FS_2000DPS 0x30 + +#define L3G4200D_GYR_ENABLED 1 +#define L3G4200D_GYR_DISABLED 0 + +#define WMTGSENSOR_IOCTL_MAGIC 0x09 +#define WMT_GYRO_IOCTL_MAGIC 0x11 +#define GYRO_IOCTL_SET_ENABLE _IOW(WMT_GYRO_IOCTL_MAGIC, 0, int) +#define GYRO_IOCTL_GET_ENABLE _IOW(WMT_GYRO_IOCTL_MAGIC, 1, int) +#define GYRO_IOCTL_SET_DELAY _IOW(WMT_GYRO_IOCTL_MAGIC, 2, int) +#define GYRO_IOCTL_GET_DELAY _IOW(WMT_GYRO_IOCTL_MAGIC, 3, int) +#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 4, unsigned int) + +#ifdef __KERNEL__ + +struct l3g4200d_triple { + short x, /* x-axis angular rate data. */ + y, /* y-axis angluar rate data. */ + z; /* z-axis angular rate data. */ +}; + + +struct reg_value_t { + u8 ctrl_reg1; + u8 ctrl_reg2; + u8 ctrl_reg3; + u8 ctrl_reg4; + u8 ctrl_reg5; + u8 ref_datacap; + u8 fifo_ctrl_reg; + u8 int1_cfg; + u8 int1_ths_xh; + u8 int1_ths_xl; + u8 int1_ths_yh; + u8 int1_ths_yl; + u8 int1_ths_zh; + u8 int1_ths_zl; + u8 int1_duration; +}; + +struct l3g4200d_gyr_platform_data { + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); + int poll_interval; + int min_interval; + + u8 fs_range; + + int axis_map_x; + int axis_map_y; + int axis_map_z; + + int direction_x; + int direction_y; + int direction_z; + + struct reg_value_t init_state; + +}; +#endif /* __KERNEL__ */ + +#endif /* __L3G4200D_H__ */ diff --git a/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c new file mode 100755 index 00000000..a30c00a6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/l3g4200d_gyro/l3g4200d_gyr.c @@ -0,0 +1,1681 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* +* File Name : l3g4200d_gyr_sysfs.c +* Authors : MH - C&I BU - Application Team +* : Carmine Iascone (carmine.iascone@st.com) +* : Matteo Dameno (matteo.dameno@st.com) +* : Both authors are willing to be considered the contact +* : and update points for the driver. +* Version : V 1.1 sysfs +* Date : 2011/02/28 +* Description : L3G4200D digital output gyroscope sensor API +* +******************************************************************************** +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +******************************************************************************** +* REVISON HISTORY +* +* VERSION | DATE | AUTHORS | DESCRIPTION +* 1.0 | 2010/11/19 | Carmine Iascone | First Release +* 1.1 | 2011/02/28 | Matteo Dameno | Self Test Added +* 1.2 | 2013/04/29 | Howay Huo | Android Interface Added +*******************************************************************************/ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/mutex.h> +#include <linux/input-polldev.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <mach/hardware.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + +#include "l3g4200d.h" + +#undef DEBUG +#define DEBUG 1 + +#define L3G4200D_I2C_ADDR 0x69 + +/* WM8880 interrupt pin connect to the DRDY Pin of LL3G4200D */ +#define L3G4200D_IRQ_PIN WMT_PIN_GP2_GPIO17 + +/** Maximum polled-device-reported rot speed value value in dps*/ +#define FS_MAX 32768 + +/* l3g4200d gyroscope registers */ +#define WHO_AM_I 0x0F + +#define CTRL_REG1 0x20 +#define CTRL_REG2 0x21 +#define CTRL_REG3 0x22 +#define CTRL_REG4 0x23 +#define CTRL_REG5 0x24 +#define REF_DATACAP 0x25 +#define OUT_TEMP 0x26 +#define STATUS_REG 0x27 +#define OUT_X_L 0x28 +#define OUT_X_H 0x29 +#define OUT_Y_L 0x2A +#define OUT_Y_H 0x2B +#define OUT_Z_L 0x2C +#define OUT_Z_H 0x2D +#define FIFO_CTRL_REG 0x2E +#define FIFO_SRC_REG 0x2F +#define INT1_CFG 0x30 +#define INT1_SRC 0x31 +#define INT1_THS_XH 0x32 +#define INT1_THS_XL 0x33 +#define INT1_THS_YH 0x34 +#define INT1_THS_YL 0x35 +#define INT1_THS_ZH 0x36 +#define INT1_THS_ZL 0x37 +#define INT1_DURATION 0x38 + +/* CTRL_REG1 */ +#define PM_MASK 0x08 +#define PM_NORMAL 0x08 +#define ENABLE_ALL_AXES 0x07 + +/* CTRL_REG3 */ +#define I2_DRDY 0x08 + +/* CTRL_REG4 bits */ +#define FS_MASK 0x30 + +#define SELFTEST_MASK 0x06 +#define L3G4200D_SELFTEST_DIS 0x00 +#define L3G4200D_SELFTEST_EN_POS 0x02 +#define L3G4200D_SELFTEST_EN_NEG 0x04 + +#define FUZZ 0 +#define FLAT 0 +#define AUTO_INCREMENT 0x80 + +/* STATUS_REG */ +#define ZYXDA 0x08 +#define ZDA 0x04 +#define YDA 0x02 +#define XDA 0x01 + +/** Registers Contents */ +#define WHOAMI_L3G4200D 0x00D3 /* Expected content for WAI register*/ + +#define ODR_MASK 0xF0 +#define ODR100_BW25 0x10 +#define ODR200_BW70 0x70 +#define ODR400_BW110 0xB0 +#define ODR800_BW110 0xF0 + +#define L3G4200D_PU_DELAY 320 //ms + +static struct i2c_client *l3g4200d_i2c_client = NULL; +static int enable_print_log; +static int interrupt_mode = 0; +static int flush_polling_data; + +/* + * L3G4200D gyroscope data + * brief structure containing gyroscope values for yaw, pitch and roll in + * signed short + */ + +struct output_rate{ + u8 odr_mask; + u32 delay_us; +}; + +static const struct output_rate gyro_odr_table[] = { + { ODR800_BW110, 1250 }, + { ODR400_BW110, 2500 }, + { ODR200_BW70, 5000 }, + { ODR100_BW25, 10000}, +}; + +struct l3g4200d_data { + struct i2c_client *client; + struct l3g4200d_gyr_platform_data *pdata; + + struct mutex lock; + + struct delayed_work enable_work; + struct delayed_work input_work; + struct input_dev *input_dev; + int hw_initialized; + int selftest_enabled; + atomic_t enabled; + + u8 reg_addr; + struct reg_value_t resume_state; +}; + +extern int wmt_getsyspara(char *varname, char *varval, int *varlen); + +static int l3g4200d_i2c_read(struct l3g4200d_data *gyro, + u8 *buf, int len) +{ + int err; + + struct i2c_msg msgs[] = { + { + .addr = gyro->client->addr, + .flags = gyro->client->flags & I2C_M_TEN, + .len = 1, + .buf = buf, + }, + { + .addr = gyro->client->addr, + .flags = (gyro->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = buf, + }, + }; + + err = i2c_transfer(gyro->client->adapter, msgs, 2); + + if (err != 2) { + dev_err(&gyro->client->dev, "read transfer error: %d\n",err); + return -EIO; + } + + return 0; +} + +static int l3g4200d_i2c_write(struct l3g4200d_data *gyro, + u8 *buf, + int len) +{ + int err; + + struct i2c_msg msgs[] = { + { + .addr = gyro->client->addr, + .flags = gyro->client->flags & I2C_M_TEN, + .len = len + 1, + .buf = buf, + }, + }; + + err = i2c_transfer(gyro->client->adapter, msgs, 1); + + if (err != 1) { + dev_err(&gyro->client->dev, "write transfer error\n"); + return -EIO; + } + + return 0; +} + +static int l3g4200d_register_write(struct l3g4200d_data *gyro, u8 *buf, + u8 reg_address, u8 new_value) +{ + int err = -1; + + /* Sets configuration register at reg_address + * NOTE: this is a straight overwrite */ + buf[0] = reg_address; + buf[1] = new_value; + err = l3g4200d_i2c_write(gyro, buf, 1); + if (err < 0) + return err; + + return err; +} + +static int l3g4200d_register_read(struct l3g4200d_data *gyro, u8 *buf, + u8 reg_address) +{ + + int err = -1; + buf[0] = (reg_address); + err = l3g4200d_i2c_read(gyro, buf, 1); + return err; +} + +static int l3g4200d_register_update(struct l3g4200d_data *gyro, u8 *buf, + u8 reg_address, u8 mask, u8 new_bit_values) +{ + int err = -1; + u8 init_val; + u8 updated_val; + err = l3g4200d_register_read(gyro, buf, reg_address); + if (!(err < 0)) { + init_val = buf[0]; + if((new_bit_values & mask) != (init_val & mask)) { + updated_val = ((mask & new_bit_values) | ((~mask) & init_val)); + err = l3g4200d_register_write(gyro, buf, reg_address, + updated_val); + } + else + return 0; + } + return err; +} + +static int l3g4200d_register_store(struct l3g4200d_data *gyro, u8 reg) +{ + int err = -1; + u8 buf[2]; + + err = l3g4200d_register_read(gyro, buf, reg); + if (err) + return err; + + switch (reg) { + case CTRL_REG1: + gyro->resume_state.ctrl_reg1 = buf[0]; + break; + case CTRL_REG2: + gyro->resume_state.ctrl_reg2 = buf[0]; + break; + case CTRL_REG3: + gyro->resume_state.ctrl_reg3 = buf[0]; + break; + case CTRL_REG4: + gyro->resume_state.ctrl_reg4 = buf[0]; + break; + case CTRL_REG5: + gyro->resume_state.ctrl_reg5 = buf[0]; + break; + case REF_DATACAP: + gyro->resume_state.ref_datacap = buf[0]; + break; + case FIFO_CTRL_REG: + gyro->resume_state.fifo_ctrl_reg = buf[0]; + break; + case INT1_CFG: + gyro->resume_state.int1_cfg = buf[0]; + break; + case INT1_THS_XH: + gyro->resume_state.int1_ths_xh = buf[0]; + break; + case INT1_THS_XL: + gyro->resume_state.int1_ths_xl = buf[0]; + break; + case INT1_THS_YH: + gyro->resume_state.int1_ths_yh = buf[0]; + break; + case INT1_THS_YL: + gyro->resume_state.int1_ths_yl = buf[0]; + break; + case INT1_THS_ZH: + gyro->resume_state.int1_ths_zh = buf[0]; + break; + case INT1_THS_ZL: + gyro->resume_state.int1_ths_zl = buf[0]; + break; + case INT1_DURATION: + gyro->resume_state.int1_duration = buf[0]; + break; + default: + pr_err("%s: can't support reg (0x%02X) store\n", L3G4200D_GYR_DEV_NAME, reg); + return -1; + } + + return 0; +} + +static int l3g4200d_update_fs_range(struct l3g4200d_data *gyro, + u8 new_fs) +{ + int res ; + u8 buf[2]; + + buf[0] = CTRL_REG4; + + res = l3g4200d_register_update(gyro, buf, CTRL_REG4, + FS_MASK, new_fs); + + if (res < 0) { + pr_err("%s : failed to update fs:0x%02x\n", + __func__, new_fs); + return res; + } + + l3g4200d_register_store(gyro, CTRL_REG4); + + return 0; +} + + +static int l3g4200d_selftest(struct l3g4200d_data *gyro, u8 enable) +{ + int err = -1; + u8 buf[2] = {0x00,0x00}; + char reg_address, mask, bit_values; + + reg_address = CTRL_REG4; + mask = SELFTEST_MASK; + if (enable > 0) + bit_values = L3G4200D_SELFTEST_EN_POS; + else + bit_values = L3G4200D_SELFTEST_DIS; + if (atomic_read(&gyro->enabled)) { + mutex_lock(&gyro->lock); + err = l3g4200d_register_update(gyro, buf, reg_address, + mask, bit_values); + gyro->selftest_enabled = enable; + mutex_unlock(&gyro->lock); + if (err < 0) + return err; + + l3g4200d_register_store(gyro, CTRL_REG4); + } + return err; +} + + +static int l3g4200d_update_odr(struct l3g4200d_data *gyro, + int poll_interval) +{ + int err = -1; + int i; + u8 config[2]; + + for (i = ARRAY_SIZE(gyro_odr_table) - 1; i >= 0; i--) { + if (gyro_odr_table[i].delay_us <= poll_interval){ + break; + } + } + + gyro->pdata->poll_interval = gyro_odr_table[i].delay_us; + + config[1] = gyro_odr_table[i].odr_mask; + config[1] |= (ENABLE_ALL_AXES + PM_NORMAL); + + /* If device is currently enabled, we need to write new + * configuration out to it */ + if (atomic_read(&gyro->enabled)) { + config[0] = CTRL_REG1; + err = l3g4200d_i2c_write(gyro, config, 1); + if (err < 0) + return err; + + l3g4200d_register_store(gyro, CTRL_REG1); + } + + return err; +} + +/* gyroscope data readout */ +static int l3g4200d_get_data(struct l3g4200d_data *gyro, + struct l3g4200d_triple *data) +{ + int err; + unsigned char gyro_out[6]; + /* y,p,r hardware data */ + s16 hw_d[3] = { 0 }; + + gyro_out[0] = (AUTO_INCREMENT | OUT_X_L); + + err = l3g4200d_i2c_read(gyro, gyro_out, 6); + + if (err < 0) + return err; + + hw_d[0] = (s16) (((gyro_out[1]) << 8) | gyro_out[0]); + hw_d[1] = (s16) (((gyro_out[3]) << 8) | gyro_out[2]); + hw_d[2] = (s16) (((gyro_out[5]) << 8) | gyro_out[4]); + + data->x = ((gyro->pdata->direction_x < 0) ? (-hw_d[gyro->pdata->axis_map_x]) + : (hw_d[gyro->pdata->axis_map_x])); + data->y = ((gyro->pdata->direction_y < 0) ? (-hw_d[gyro->pdata->axis_map_y]) + : (hw_d[gyro->pdata->axis_map_y])); + data->z = ((gyro->pdata->direction_z < 0) ? (-hw_d[gyro->pdata->axis_map_z]) + : (hw_d[gyro->pdata->axis_map_z])); + + if(enable_print_log) + printk("x = %d, y = %d, z = %d\n", data->x, data->y, data->z); + + return err; +} + +static void l3g4200d_report_values(struct l3g4200d_data *l3g, + struct l3g4200d_triple *data) +{ + struct input_dev *input = l3g->input_dev; + + input_report_abs(input, ABS_X, data->x); + input_report_abs(input, ABS_Y, data->y); + input_report_abs(input, ABS_Z, data->z); + input_sync(input); +} + +static int l3g4200d_hw_init(struct l3g4200d_data *gyro) +{ + int err = -1; + u8 buf[8]; + + printk(KERN_INFO "%s hw init\n", L3G4200D_GYR_DEV_NAME); + + buf[0] = (AUTO_INCREMENT | CTRL_REG1); + buf[1] = gyro->resume_state.ctrl_reg1; + buf[2] = gyro->resume_state.ctrl_reg2; + buf[3] = gyro->resume_state.ctrl_reg3; + buf[4] = gyro->resume_state.ctrl_reg4; + buf[5] = gyro->resume_state.ctrl_reg5; + buf[6] = gyro->resume_state.ref_datacap; + err = l3g4200d_i2c_write(gyro, buf, 6); + if(err) + return err; + + buf[0] = FIFO_CTRL_REG; + buf[1] = gyro->resume_state.fifo_ctrl_reg; + err = l3g4200d_i2c_write(gyro, buf, 1); + if(err) + return err; + + buf[0] = INT1_CFG; + buf[1] = gyro->resume_state.int1_cfg; + err = l3g4200d_i2c_write(gyro, buf, 1); + if(err) + return err; + + buf[0] = (AUTO_INCREMENT | INT1_THS_XH); + buf[1] = gyro->resume_state.int1_ths_xh; + buf[2] = gyro->resume_state.int1_ths_xl; + buf[3] = gyro->resume_state.int1_ths_yh; + buf[4] = gyro->resume_state.int1_ths_yl; + buf[5] = gyro->resume_state.int1_ths_zh; + buf[6] = gyro->resume_state.int1_ths_zl; + buf[7] = gyro->resume_state.int1_duration; + err = l3g4200d_i2c_write(gyro, buf, 7); + if(err) + return err; + + gyro->hw_initialized = 1; + + return 0; +} + +static void l3g4200d_gpio_irq_enable(void) +{ + wmt_gpio_unmask_irq(L3G4200D_IRQ_PIN); +} + +static void l3g4200d_gpio_irq_disable(void) +{ + wmt_gpio_mask_irq(L3G4200D_IRQ_PIN); +} + +static int l3g4200d_irq_hw_init(int resume) +{ + int ret; + + if(!resume) { + ret = gpio_request(L3G4200D_IRQ_PIN, "l3g4200d-gyro irq"); //enable gpio + if(ret < 0) { + pr_err("gpio(%d) request fail for l3g4200d-gyro irq\n", L3G4200D_IRQ_PIN); + return ret; + } + }else + gpio_re_enabled(L3G4200D_IRQ_PIN); //re-enable gpio + + gpio_direction_input(L3G4200D_IRQ_PIN); //gpio input + + wmt_gpio_setpull(L3G4200D_IRQ_PIN, WMT_GPIO_PULL_DOWN); //enable pull and pull-down + + wmt_gpio_mask_irq(L3G4200D_IRQ_PIN); //disable interrupt + + wmt_gpio_set_irq_type(L3G4200D_IRQ_PIN, IRQ_TYPE_EDGE_RISING); //rise edge and clear interrupt + + return 0; +} + +static void l3g4200d_irq_hw_free(void) +{ + l3g4200d_gpio_irq_disable(); + gpio_free(L3G4200D_IRQ_PIN); + +} + +static int l3g4200d_gpio_get_value(void) +{ + return (REG8_VAL(__GPIO_BASE + 0x0002) & BIT1); +} + +static int l3g4200d_flush_gyro_data(struct l3g4200d_data *gyro) +{ + struct l3g4200d_triple data; + int i; + + for (i = 0; i < 5; i++) { + if (l3g4200d_gpio_get_value()) { + l3g4200d_get_data(gyro, &data); + pr_info("%s: flush_gyro_data: %d\n", L3G4200D_GYR_DEV_NAME, i); + } + else { + return 0; + } + } + + return -EIO; +} + +static void l3g4200d_device_power_off(struct l3g4200d_data *gyro) +{ + int err; + u8 buf[2]; + + pr_info("%s power off\n", L3G4200D_GYR_DEV_NAME); + + buf[0] = CTRL_REG1; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err < 0) { + dev_err(&gyro->client->dev, "read ctrl_reg1 failed\n"); + buf[0] = (gyro->resume_state.ctrl_reg1 | PM_MASK); + } + + if(buf[0] & PM_MASK) { + buf[1] = buf[0] & ~PM_MASK; + buf[0] = CTRL_REG1; + + err = l3g4200d_i2c_write(gyro, buf, 1); + if (err) + dev_err(&gyro->client->dev, "soft power off failed\n"); + + l3g4200d_register_store(gyro, CTRL_REG1); + } + + if (gyro->pdata->power_off) { + gyro->pdata->power_off(); +// gyro->hw_initialized = 0; + } + +// if (gyro->hw_initialized) +// gyro->hw_initialized = 0; + +} + +static int l3g4200d_device_power_on(struct l3g4200d_data *gyro) +{ + int err; + u8 buf[2]; + + pr_info("%s power on\n", L3G4200D_GYR_DEV_NAME); + + if (gyro->pdata->power_on) { + err = gyro->pdata->power_on(); + if (err < 0) + return err; + } + + if (!gyro->hw_initialized) { + err = l3g4200d_hw_init(gyro); + if (err) { + l3g4200d_device_power_off(gyro); + return err; + } + } + + buf[0] = CTRL_REG1; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) { + dev_err(&gyro->client->dev, "read ctrl_reg1 failed\n"); + buf[0] = (gyro->resume_state.ctrl_reg1 & ~PM_MASK); + } + + if(!(buf[0] & PM_MASK)) { + buf[1] = buf[0] | PM_MASK; + buf[0] = CTRL_REG1; + err = l3g4200d_i2c_write(gyro, buf, 1); + if(err) { + dev_err(&gyro->client->dev, "soft power on failed\n"); + return err; + } + l3g4200d_register_store(gyro, CTRL_REG1); + } + + return 0; +} + +static int l3g4200d_enable(struct l3g4200d_data *gyro) +{ + int err; + + pr_info("%s enable\n", L3G4200D_GYR_DEV_NAME); + + if (!atomic_cmpxchg(&gyro->enabled, 0, 1)) { + err = l3g4200d_device_power_on(gyro); + if (err) { + atomic_set(&gyro->enabled, 0); + return err; + } + + //Android will call l3g4200d_set_delay() after l3g4200d_enable; + } + + return 0; +} + +static int l3g4200d_disable(struct l3g4200d_data *gyro) +{ + pr_info("%s disable\n", L3G4200D_GYR_DEV_NAME); + + if (atomic_cmpxchg(&gyro->enabled, 1, 0)){ + if(interrupt_mode) { + cancel_delayed_work_sync(&gyro->enable_work); + l3g4200d_gpio_irq_disable(); + }else + cancel_delayed_work_sync(&gyro->input_work); + + l3g4200d_device_power_off(gyro); + } + return 0; +} + +static int l3g4200d_set_delay(struct l3g4200d_data *gyro, u32 delay_us) +{ + int odr_value = ODR100_BW25; + int err = -1; + int i; + u8 buf[2] = {CTRL_REG1, 0}; + + pr_info("l3g4200d_set_delay: %d us\n", delay_us); + + /* do not report noise during ODR update */ + if(interrupt_mode) { + cancel_delayed_work_sync(&gyro->enable_work); + l3g4200d_gpio_irq_disable(); + }else + cancel_delayed_work_sync(&gyro->input_work); + + for(i=0; i < ARRAY_SIZE(gyro_odr_table); i++) + if(delay_us <= gyro_odr_table[i].delay_us) { + odr_value = gyro_odr_table[i].odr_mask; + delay_us = gyro_odr_table[i].delay_us; + break; + } + + if(delay_us >= gyro_odr_table[3].delay_us) { + odr_value = gyro_odr_table[3].odr_mask; + delay_us = gyro_odr_table[3].delay_us; + } + + err = l3g4200d_register_update(gyro, buf, CTRL_REG1, ODR_MASK, odr_value); + if(err) { + dev_err(&gyro->client->dev, "update odr failed 0x%x,0x%x: %d\n", + buf[0], odr_value, err); + return err; + } + + l3g4200d_register_store(gyro, CTRL_REG1); + + gyro->pdata->poll_interval = max((int)delay_us, gyro->pdata->min_interval); + + //do not report noise at IC power-up + // flush data before really read + if(interrupt_mode) + schedule_delayed_work(&gyro->enable_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + else { + flush_polling_data = 1; + schedule_delayed_work(&gyro->input_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + } + + return 0; +} + +static ssize_t attr_polling_rate_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int val; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + mutex_lock(&gyro->lock); + val = gyro->pdata->poll_interval; + mutex_unlock(&gyro->lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t attr_polling_rate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long interval_us; + + if (strict_strtoul(buf, 10, &interval_us)) + return -EINVAL; + if (!interval_us) + return -EINVAL; + mutex_lock(&gyro->lock); + gyro->pdata->poll_interval = interval_us; + l3g4200d_update_odr(gyro, interval_us); + mutex_unlock(&gyro->lock); + return size; +} + +static ssize_t attr_range_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + int range = 0; + char val; + mutex_lock(&gyro->lock); + val = gyro->pdata->fs_range; + switch (val) { + case L3G4200D_GYR_FS_250DPS: + range = 250; + break; + case L3G4200D_GYR_FS_500DPS: + range = 500; + break; + case L3G4200D_GYR_FS_2000DPS: + range = 2000; + break; + } + mutex_unlock(&gyro->lock); + return sprintf(buf, "%d\n", range); +} + +static ssize_t attr_range_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + mutex_lock(&gyro->lock); + gyro->pdata->fs_range = val; + l3g4200d_update_fs_range(gyro, val); + mutex_unlock(&gyro->lock); + return size; +} + +static ssize_t attr_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + int val = atomic_read(&gyro->enabled); + return sprintf(buf, "%d\n", val); +} + +static ssize_t attr_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + if (val) { + l3g4200d_enable(gyro); + l3g4200d_set_delay(gyro, gyro->pdata->poll_interval); + } + else + l3g4200d_disable(gyro); + + return size; +} + +static ssize_t attr_get_selftest(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int val; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + mutex_lock(&gyro->lock); + val = gyro->selftest_enabled; + mutex_unlock(&gyro->lock); + return sprintf(buf, "%d\n", val); +} + +static ssize_t attr_set_selftest(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + l3g4200d_selftest(gyro, val); + + return size; +} + +#ifdef DEBUG +static ssize_t attr_reg_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + int rc; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + u8 x[2]; + unsigned long val; + + if (strict_strtoul(buf, 16, &val)) + return -EINVAL; + mutex_lock(&gyro->lock); + x[0] = gyro->reg_addr; + mutex_unlock(&gyro->lock); + x[1] = val; + rc = l3g4200d_i2c_write(gyro, x, 1); + return size; +} + +static ssize_t attr_reg_get(struct device *dev, struct device_attribute *attr, + char *buf) +{ + ssize_t ret; + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + int rc; + u8 data; + + mutex_lock(&gyro->lock); + data = gyro->reg_addr; + mutex_unlock(&gyro->lock); + rc = l3g4200d_i2c_read(gyro, &data, 1); + ret = sprintf(buf, "0x%02x\n", data); + return ret; +} + +static ssize_t attr_addr_set(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + struct l3g4200d_data *gyro = dev_get_drvdata(dev); + unsigned long val; + + if (strict_strtoul(buf, 16, &val)) + return -EINVAL; + + mutex_lock(&gyro->lock); + + gyro->reg_addr = val; + + mutex_unlock(&gyro->lock); + + return size; +} + +static ssize_t attr_get_printlog(struct device * dev,struct device_attribute * attr, + char * buf) +{ + ssize_t ret; + + ret = sprintf(buf, "%d\n", enable_print_log); + + return ret; +} + +static ssize_t attr_set_printlog(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val)) + return -EINVAL; + + enable_print_log = val; + + return size; +} + +#endif /* DEBUG */ + +static struct device_attribute attributes[] = { + __ATTR(pollrate_ms, 0666, attr_polling_rate_show, + attr_polling_rate_store), + __ATTR(range, 0666, attr_range_show, attr_range_store), + __ATTR(enable_device, 0666, attr_enable_show, attr_enable_store), + __ATTR(enable_selftest, 0666, attr_get_selftest, attr_set_selftest), +#ifdef DEBUG + __ATTR(reg_value, 0600, attr_reg_get, attr_reg_set), + __ATTR(reg_addr, 0200, NULL, attr_addr_set), + __ATTR(printlog, 0600, attr_get_printlog, attr_set_printlog), +#endif +}; + +static int create_sysfs_interfaces(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(attributes); i++) + if (device_create_file(dev, attributes + i)) + goto error; + return 0; + +error: + for ( ; i >= 0; i--) + device_remove_file(dev, attributes + i); + dev_err(dev, "%s:Unable to create interface\n", __func__); + return -1; +} + +static int remove_sysfs_interfaces(struct device *dev) +{ + int i; + for (i = 0; i < ARRAY_SIZE(attributes); i++) + device_remove_file(dev, attributes + i); + return 0; +} + +static void l3g4200d_data_report(struct l3g4200d_data *gyro) +{ + struct l3g4200d_triple data_out; + int err; + + err = l3g4200d_get_data(gyro, &data_out); + if (err) + dev_err(&gyro->client->dev, "get_gyroscope_data failed\n"); + else + l3g4200d_report_values(gyro, &data_out); + +} + +static int l3g4200d_validate_pdata(struct l3g4200d_data *gyro) +{ + gyro->pdata->poll_interval = max(gyro->pdata->poll_interval, + gyro->pdata->min_interval); + + if (gyro->pdata->axis_map_x > 2 || + gyro->pdata->axis_map_y > 2 || + gyro->pdata->axis_map_z > 2) { + dev_err(&gyro->client->dev, + "invalid axis_map value x:%u y:%u z%u\n", + gyro->pdata->axis_map_x, + gyro->pdata->axis_map_y, + gyro->pdata->axis_map_z); + return -EINVAL; + } + + /* Only allow 1 and -1 for direction flag */ + if (abs(gyro->pdata->direction_x) != 1 || + abs(gyro->pdata->direction_y) != 1 || + abs(gyro->pdata->direction_z) != 1) { + dev_err(&gyro->client->dev, + "invalid direction value x:%d y:%d z:%d\n", + gyro->pdata->direction_x, + gyro->pdata->direction_y, + gyro->pdata->direction_z); + return -EINVAL; + } + + /* Enforce minimum polling interval */ + if (gyro->pdata->poll_interval < gyro->pdata->min_interval) { + dev_err(&gyro->client->dev, + "minimum poll interval violated\n"); + return -EINVAL; + } + return 0; +} + +static int l3g4200d_misc_open(struct inode *inode, struct file *file) +{ + int err; + + err = nonseekable_open(inode, file); + if(err < 0) + return err; + + file->private_data = i2c_get_clientdata(l3g4200d_i2c_client); + + return 0; +} + +static int l3g4200d_misc_close(struct inode *inode, struct file *filp) +{ + return 0; +} + + +static long l3g4200d_misc_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int interval, val; + int err = -1; + struct l3g4200d_data *gyro = file->private_data; + + switch(cmd){ + case GYRO_IOCTL_GET_DELAY: + interval = gyro->pdata->poll_interval; + if(copy_to_user(argp, &interval, sizeof(interval))) + return -EFAULT; + break; + + case GYRO_IOCTL_SET_DELAY: + if(copy_from_user(&interval, argp, sizeof(interval))) + return -EFAULT; + err = l3g4200d_set_delay(gyro, interval); + if(err < 0) + return err; + break; + + case GYRO_IOCTL_SET_ENABLE: + if(copy_from_user(&val, argp, sizeof(val))) + return -EFAULT; + if(val > 1) + return -EINVAL; + + if(val) + l3g4200d_enable(gyro); + else + l3g4200d_disable(gyro); + break; + + case GYRO_IOCTL_GET_ENABLE: + val = atomic_read(&gyro->enabled); + if(copy_to_user(argp, &val, sizeof(val))) + return -EINVAL; + break; + + case WMT_IOCTL_SENSOR_GET_DRVID: + val = L3G4200D_DRVID; + if (copy_to_user(argp, &val, sizeof(val))) + return -EFAULT; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct file_operations l3g4200d_misc_fops = { + .owner = THIS_MODULE, + .open = l3g4200d_misc_open, + .unlocked_ioctl = l3g4200d_misc_ioctl, + .release = l3g4200d_misc_close, +}; + +static struct miscdevice l3g4200d_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GYRO_MISCDEV_NAME, + .fops = &l3g4200d_misc_fops, +}; + +static int l3g4200d_input_init(struct l3g4200d_data *gyro) +{ + int err = -1; + struct input_dev *input; + + gyro->input_dev = input_allocate_device(); + if (!gyro->input_dev) { + err = -ENOMEM; + dev_err(&gyro->client->dev, + "input device allocate failed\n"); + goto err0; + } + + input = gyro->input_dev; + + input_set_drvdata(input, gyro); + + set_bit(EV_ABS, input->evbit); + + input_set_abs_params(input, ABS_X, -FS_MAX, FS_MAX, FUZZ, FLAT); + input_set_abs_params(input, ABS_Y, -FS_MAX, FS_MAX, FUZZ, FLAT); + input_set_abs_params(input, ABS_Z, -FS_MAX, FS_MAX, FUZZ, FLAT); + + input->name = GYRO_INPUT_NAME; + + err = input_register_device(input); + if (err) { + dev_err(&gyro->client->dev, + "unable to register input polled device %s\n", + input->name); + goto err1; + } + + return 0; + +err1: + input_free_device(input); +err0: + return err; +} + +static void l3g4200d_input_cleanup(struct l3g4200d_data *gyro) +{ + input_unregister_device(gyro->input_dev); + input_free_device(gyro->input_dev); +} + +static int l3g4300d_detect(struct i2c_client *client) +{ + int ret; + u8 buf[1]; + struct l3g4200d_data gyro; + + gyro.client = client; + + ret = l3g4200d_register_read(&gyro, buf, WHO_AM_I); + if(ret) + return 0; + + if(buf[0] != WHOAMI_L3G4200D){ + dev_err(&client->dev, "chipId = 0x%02X, error", buf[0]); + return 0; + } + + return 1; +} + +static irqreturn_t gyro_irq_handler(int irq, void *dev_id) +{ + if(!gpio_irqstatus(L3G4200D_IRQ_PIN)) + return IRQ_NONE; + + wmt_gpio_ack_irq(L3G4200D_IRQ_PIN); //clear interrupt + + //printk("got gyro interrupt\n"); + if(!is_gpio_irqenable(L3G4200D_IRQ_PIN)) { + //pr_err("l3g4200d irq is disabled\n"); + return IRQ_HANDLED; + }else + return IRQ_WAKE_THREAD; +} + +static irqreturn_t gyro_irq_thread(int irq, void *dev) +{ + struct l3g4200d_data *gyro = dev; + + l3g4200d_data_report(gyro); + + return IRQ_HANDLED; +} + +static void l3g4200d_enable_work_func(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct l3g4200d_data *gyro = + container_of(dwork, struct l3g4200d_data, enable_work); + + l3g4200d_flush_gyro_data(gyro); + l3g4200d_gpio_irq_enable(); +} + +static void l3g4200d_input_poll_func(struct work_struct *work) +{ + struct l3g4200d_triple data; + struct delayed_work *dwork = to_delayed_work(work); + struct l3g4200d_data *gyro = + container_of(dwork, struct l3g4200d_data, input_work); + + if(flush_polling_data == 0) + l3g4200d_data_report(gyro); + else { + l3g4200d_get_data(gyro, &data); //flush the first data + flush_polling_data = 0; + } + + schedule_delayed_work(&gyro->input_work, + usecs_to_jiffies(gyro->pdata->poll_interval)); +} + +static int l3g4200d_param_parse(int *p_int_mode, struct l3g4200d_gyr_platform_data *pdata) +{ + char varbuf[64] = {0}; + int n, ret, varlen; + int tmp[7]; + + varlen = sizeof(varbuf); + + ret = wmt_getsyspara("wmt.io.gyro.l3g4200d", varbuf, &varlen); + if(ret) + return 0; + + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d", + &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5], &tmp[6]); + + if(n != 7) { + pr_err("l3g4200d-gyro param format error\n"); + return -1; + } + + pdata->axis_map_x = tmp[0]; + pdata->direction_x = tmp[1]; + pdata->axis_map_y = tmp[2]; + pdata->direction_y = tmp[3]; + pdata->axis_map_z = tmp[4]; + pdata->direction_z = tmp[5]; + *p_int_mode = tmp[6]; + + return 0; +} + +static int l3g4200d_probe(struct i2c_client *client, + const struct i2c_device_id *devid) +{ + struct l3g4200d_data *gyro; + int err = -1; + u8 buf[2]; + + pr_info("%s: probe start.\n", L3G4200D_GYR_DEV_NAME); + + if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL. exiting.\n"); + err = -ENODEV; + goto err0; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "client not i2c capable:1\n"); + err = -ENODEV; + goto err0; + } + + if(l3g4300d_detect(client) == 0){ + dev_err(&client->dev, "not found the gyro\n"); + err = -ENODEV; + goto err0; + } + + gyro = kzalloc(sizeof(*gyro), GFP_KERNEL); + if (gyro == NULL) { + dev_err(&client->dev, + "failed to allocate memory for module data\n"); + err = -ENOMEM; + goto err0; + } + + l3g4200d_param_parse(&interrupt_mode, client->dev.platform_data); + if(interrupt_mode) { + pr_info("l3g4200d-gyro in interrupt mode\n"); + err = l3g4200d_irq_hw_init(0); + if(err) + goto err0; + } + else + pr_info("l3g4200d-gyro in polling mode\n"); + + mutex_init(&gyro->lock); + mutex_lock(&gyro->lock); + gyro->client = client; + + gyro->pdata = kmalloc(sizeof(*gyro->pdata), GFP_KERNEL); + if (gyro->pdata == NULL) { + dev_err(&client->dev, + "failed to allocate memory for pdata: %d\n", err); + goto err1; + } + memcpy(gyro->pdata, client->dev.platform_data, + sizeof(*gyro->pdata)); + + err = l3g4200d_validate_pdata(gyro); + if (err < 0) { + dev_err(&client->dev, "failed to validate platform data\n"); + goto err1_1; + } + + i2c_set_clientdata(client, gyro); + + if (gyro->pdata->init) { + err = gyro->pdata->init(); + if (err < 0) { + dev_err(&client->dev, "init failed: %d\n", err); + goto err1_1; + } + } + + if(interrupt_mode) + gyro->pdata->init_state.ctrl_reg3 |= I2_DRDY; + + //According to the introduction of L3G4200D's datasheet page 32, + //the bit7 and bit6 of CTRL_REG2's value is loaded at boot. This value must not be changed + buf[0] = CTRL_REG2; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) + goto err1_1; + + gyro->pdata->init_state.ctrl_reg2 = (gyro->pdata->init_state.ctrl_reg2 & 0x1F) + | (buf[0] & 0xC0); + + gyro->pdata->init_state.ctrl_reg1 &= ~PM_MASK; + + memcpy(&gyro->resume_state, &gyro->pdata->init_state, + sizeof(struct reg_value_t)); + + err = l3g4200d_hw_init(gyro); + if (err) { + dev_err(&client->dev, "hardware init failed: %d\n", err); + goto err2; + } + + err = l3g4200d_input_init(gyro); + if (err < 0) + goto err3; + + err = create_sysfs_interfaces(&client->dev); + if (err < 0) { + dev_err(&client->dev, + "%s device register failed\n", L3G4200D_GYR_DEV_NAME); + goto err4; + } + + /* As default, do not report information */ + atomic_set(&gyro->enabled, 0); + + if(interrupt_mode) + INIT_DELAYED_WORK(&gyro->enable_work, l3g4200d_enable_work_func); + else + INIT_DELAYED_WORK(&gyro->input_work, l3g4200d_input_poll_func); + + err = misc_register(&l3g4200d_misc_device); + if(err){ + dev_err(&client->dev, "l3g4200d_device register failed\n"); + goto err5; + } + + if(interrupt_mode) { + err = request_threaded_irq(gyro->client->irq, gyro_irq_handler, + gyro_irq_thread, IRQF_SHARED, L3G4200D_GYR_DEV_NAME, gyro); + + if(err) { + pr_err("%s: irq request failed: %d\n", __func__, err); + err = -ENODEV; + goto err6; + } + } + + mutex_unlock(&gyro->lock); + +#ifdef DEBUG + pr_info("%s probed: device created successfully\n", + L3G4200D_GYR_DEV_NAME); +#endif + + return 0; + +err6: + misc_deregister(&l3g4200d_misc_device); +err5: + remove_sysfs_interfaces(&client->dev); +err4: + l3g4200d_input_cleanup(gyro); +err3: + l3g4200d_device_power_off(gyro); +err2: + if (gyro->pdata->exit) + gyro->pdata->exit(); +err1_1: + mutex_unlock(&gyro->lock); + kfree(gyro->pdata); +err1: + kfree(gyro); + if(interrupt_mode) + l3g4200d_irq_hw_free(); +err0: + pr_err("%s: Driver Initialization failed\n", + L3G4200D_GYR_DEV_NAME); + return err; +} + +static int l3g4200d_remove(struct i2c_client *client) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(client); +#ifdef DEBUG + pr_info(KERN_INFO "L3G4200D driver removing\n"); +#endif + + l3g4200d_disable(gyro); + if(interrupt_mode) { + free_irq(gyro->client->irq, gyro); + l3g4200d_irq_hw_free(); + } + misc_deregister(&l3g4200d_misc_device); + l3g4200d_input_cleanup(gyro); + remove_sysfs_interfaces(&client->dev); + kfree(gyro->pdata); + kfree(gyro); + return 0; +} + +static void l3g4200d_shutdown(struct i2c_client *client) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(client); + + pr_info("l3g4200d_shutdown\n"); + + l3g4200d_disable(gyro); +} + + +static int l3g4200d_suspend(struct device *dev) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(l3g4200d_i2c_client); + int err; + u8 buf[8]; + + pr_info(KERN_INFO "l3g4200d_suspend\n"); + + if(atomic_read(&gyro->enabled)) { + if(interrupt_mode) { + cancel_delayed_work_sync(&gyro->enable_work); + l3g4200d_gpio_irq_disable(); + } + else + cancel_delayed_work_sync(&gyro->input_work); + + //store register value + buf[0] = (AUTO_INCREMENT | CTRL_REG1); + err = l3g4200d_i2c_read(gyro, buf, 6); + if(err) + goto err1; + gyro->resume_state.ctrl_reg1 = buf[0]; + gyro->resume_state.ctrl_reg2 = buf[1]; + gyro->resume_state.ctrl_reg3 = buf[2]; + gyro->resume_state.ctrl_reg4 = buf[3]; + gyro->resume_state.ctrl_reg5 = buf[4]; + gyro->resume_state.ref_datacap = buf[5]; + + buf[0] = FIFO_CTRL_REG; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) + goto err1; + gyro->resume_state.fifo_ctrl_reg = buf[0]; + + buf[0] = INT1_CFG; + err = l3g4200d_i2c_read(gyro, buf, 1); + if(err) + goto err1; + gyro->resume_state.int1_cfg = buf[0]; + + buf[0] = (AUTO_INCREMENT | INT1_THS_XH); + err = l3g4200d_i2c_read(gyro, buf, 7); + if(err) + goto err1; + + gyro->resume_state.int1_ths_xh = buf[0]; + gyro->resume_state.int1_ths_xl = buf[1]; + gyro->resume_state.int1_ths_yh = buf[2]; + gyro->resume_state.int1_ths_yl = buf[3]; + gyro->resume_state.int1_ths_zh = buf[4]; + gyro->resume_state.int1_ths_zl = buf[5]; + gyro->resume_state.int1_duration = buf[6]; + } + + goto exit1; + +err1: + dev_err(&gyro->client->dev, "save register value fail at suspend\n"); + memcpy(&gyro->resume_state, &gyro->pdata->init_state, + sizeof(struct reg_value_t)); +exit1: + l3g4200d_device_power_off(gyro); + + if (gyro->hw_initialized) + gyro->hw_initialized = 0; + + return 0; +} + +static int l3g4200d_resume(struct device *dev) +{ + struct l3g4200d_data *gyro = i2c_get_clientdata(l3g4200d_i2c_client); + int err; + + pr_info(KERN_INFO "l3g4200d_resume\n"); + + if(interrupt_mode) + l3g4200d_irq_hw_init(1); + + if(atomic_read(&gyro->enabled)) { + + err = l3g4200d_device_power_on(gyro); + if(err) + { + dev_err(&gyro->client->dev, "power_on failed at resume\n"); + atomic_set(&gyro->enabled, 0); + + return 0; + } + + //do not report noise at IC power-up + // flush data before really read + if(interrupt_mode) + schedule_delayed_work(&gyro->enable_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + else { + flush_polling_data = 1; + schedule_delayed_work(&gyro->input_work, msecs_to_jiffies( + L3G4200D_PU_DELAY)); + } + }else { + memcpy(&gyro->resume_state, &gyro->pdata->init_state, + sizeof(struct reg_value_t)); + + err = l3g4200d_hw_init(gyro); + if (err) + dev_err(&gyro->client->dev, "hardware init failed at resume\n"); + } + + return 0; +} + +static const struct i2c_device_id l3g4200d_id[] = { + { L3G4200D_GYR_DEV_NAME , 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, l3g4200d_id); + +static struct dev_pm_ops l3g4200d_pm = { + .suspend = l3g4200d_suspend, + .resume = l3g4200d_resume, +}; + +static struct i2c_driver l3g4200d_driver = { + .driver = { + .owner = THIS_MODULE, + .name = L3G4200D_GYR_DEV_NAME, + .pm = &l3g4200d_pm, + }, + .probe = l3g4200d_probe, + .remove = __devexit_p(l3g4200d_remove), + .shutdown = l3g4200d_shutdown, + .id_table = l3g4200d_id, +}; + +static struct l3g4200d_gyr_platform_data gyr_drvr_platform_data={ + .poll_interval = 10000, // us + .min_interval = 1250, // us + + .fs_range = L3G4200D_GYR_FS_2000DPS, + + .axis_map_x = 0, + .axis_map_y = 1, + .axis_map_z = 2, + + .direction_x = 1, + .direction_y = -1, + .direction_z = -1, + + .init_state.ctrl_reg1 = 0x17, //ODR100 + .init_state.ctrl_reg2 = 0x00, + .init_state.ctrl_reg3 = 0x00, //DRDY interrupt + .init_state.ctrl_reg4 = 0xA0, //BDU enable, 2000 dps + .init_state.ctrl_reg5 = 0x00, + .init_state.ref_datacap = 0x00, + .init_state.fifo_ctrl_reg = 0x00, + .init_state.int1_cfg = 0x00, + .init_state.int1_ths_xh = 0x00, + .init_state.int1_ths_xl = 0x00, + .init_state.int1_ths_yh = 0x00, + .init_state.int1_ths_yl = 0x00, + .init_state.int1_ths_zh = 0x00, + .init_state.int1_ths_zl = 0x00, + .init_state.int1_duration = 0x00 +}; + +static struct i2c_board_info __initdata l3g4200d_i2c_board[] = { + { + I2C_BOARD_INFO(L3G4200D_GYR_DEV_NAME, L3G4200D_I2C_ADDR), + .irq = IRQ_GPIO, + .platform_data = &gyr_drvr_platform_data, + }, +}; + +static int __init l3g4200d_init(void) +{ + int ret; + struct i2c_adapter *adapter; + +#ifdef DEBUG + pr_info("%s: gyroscope sysfs driver init\n", L3G4200D_GYR_DEV_NAME); +#endif + + adapter = i2c_get_adapter(0); + if (adapter == NULL) { + pr_err("%s: i2c_get_adapter() error\n", L3G4200D_GYR_DEV_NAME); + return -ENODEV; + } + + l3g4200d_i2c_client = i2c_new_device(adapter, l3g4200d_i2c_board); + if (l3g4200d_i2c_client == NULL) { + pr_err("%s: i2c_new_device() error\n", L3G4200D_GYR_DEV_NAME); + return -ENOMEM; + } + + i2c_put_adapter(adapter); + + ret = i2c_add_driver(&l3g4200d_driver); + if(ret){ + pr_err("%s: i2c_add_driver() failed\n", L3G4200D_GYR_DEV_NAME); + i2c_unregister_device(l3g4200d_i2c_client); + return ret; + } + + return ret; +} + +static void __exit l3g4200d_exit(void) +{ +#ifdef DEBUG + pr_info("L3G4200D exit\n"); +#endif + + i2c_del_driver(&l3g4200d_driver); + i2c_unregister_device(l3g4200d_i2c_client); + + return; +} + +module_init(l3g4200d_init); +module_exit(l3g4200d_exit); + +MODULE_DESCRIPTION("l3g4200d digital gyroscope sysfs driver"); +MODULE_AUTHOR("Matteo Dameno, Carmine Iascone, STMicroelectronics"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile new file mode 100755 index 00000000..8a419fc7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_mc3230
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := mc32x0.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c new file mode 100755 index 00000000..4330dbb6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0.c @@ -0,0 +1,2580 @@ +/* Date: 2011/4/8 11:00:00
+ * Revision: 2.5
+ */
+
+/*
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+
+ * (C) Copyright 2011 Bosch Sensortec GmbH
+ * All Rights Reserved
+ */
+
+
+/* file mc32x0.c
+ brief This file contains all function implementations for the mc32x0 in linux
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+//#include <linux/earlysuspend.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+
+//#include <linux/init-input.h>
+#include <mach/hardware.h>
+#include <linux/fs.h>
+
+#include "../sensor.h"
+#include "mc32x0_driver.h"
+
+
+#if 0
+#define mcprintkreg(x...) printk(x)
+#else
+#define mcprintkreg(x...)
+#endif
+
+#if 0
+#define mcprintkfunc(x...) printk(x)
+#else
+#define mcprintkfunc(x...)
+#endif
+
+#if 0
+#define GSE_ERR(x...) printk(x)
+#define GSE_LOG(x...) printk(x)
+#else
+#define GSE_ERR(x...)
+#define GSE_LOG(x...)
+#endif
+
+static int g_virtual_z = 0;
+#define G_2_REVERSE_VIRTUAL_Z 0 //!!!!! 1
+#define SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23
+#define LOW_RESOLUTION 1
+#define HIGH_RESOLUTION 2
+#define RBM_RESOLUTION 3
+#ifdef SUPPORT_VIRTUAL_Z_SENSOR
+#define Low_Pos_Max 127
+#define Low_Neg_Max -128
+#define High_Pos_Max 8191
+#define High_Neg_Max -8192
+#define VIRTUAL_Z 1
+static int Railed = 0;
+#else
+#define VIRTUAL_Z 0
+#endif
+
+
+static struct class* l_dev_class = NULL;
+
+
+
+
+#define GSENSOR_NAME "mc3230"
+#define SENSOR_DATA_SIZE 3
+#define AVG_NUM 16
+/* Addresses to scan */
+//static const unsigned short normal_i2c[2] = {0x00,I2C_CLIENT_END};
+
+
+//volatile unsigned char mc32x0_on_off=0;
+//static int mc32x0_pin_hd;
+static char mc32x0_on_off_str[32];
+#define G_0 ABS_X
+#define G_1 ABS_Y
+#define G_2 ABS_Z
+#define G_0_REVERSE 1
+#define G_1_REVERSE 1
+#define G_2_REVERSE -1
+
+#define GRAVITY_1G_VALUE 1000
+
+#define SENSOR_DMARD_IOCTL_BASE 234
+
+#define IOCTL_SENSOR_SET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 100)
+#define IOCTL_SENSOR_GET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 101)
+#define IOCTL_SENSOR_GET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 102)
+#define IOCTL_SENSOR_SET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 103)
+#define IOCTL_SENSOR_GET_DATA_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 104)
+
+#define IOCTL_MSENSOR_SET_DELAY_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 200)
+#define IOCTL_MSENSOR_GET_DATA_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 201)
+#define IOCTL_MSENSOR_GET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 202)
+#define IOCTL_MSENSOR_SET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 203)
+
+#define IOCTL_SENSOR_GET_NAME _IO(SENSOR_DMARD_IOCTL_BASE, 301)
+#define IOCTL_SENSOR_GET_VENDOR _IO(SENSOR_DMARD_IOCTL_BASE, 302)
+
+#define IOCTL_SENSOR_GET_CONVERT_PARA _IO(SENSOR_DMARD_IOCTL_BASE, 401)
+
+#define SENSOR_CALIBRATION _IOWR(SENSOR_DMARD_IOCTL_BASE, 402, int[SENSOR_DATA_SIZE])
+
+
+#define mc32x0_CONVERT_PARAMETER (1.5f * (9.80665f) / 256.0f)
+//#define mc32x0_DISPLAY_NAME "mc32x0"
+//#define mc32x0_DIPLAY_VENDOR "domintech"
+
+#define X_OUT 0x41
+#define CONTROL_REGISTER 0x44
+#define SW_RESET 0x53
+#define WHO_AM_I 0x0f
+#define WHO_AM_I_VALUE 0x06
+
+#define MC32X0_AXIS_X 0
+#define MC32X0_AXIS_Y 1
+#define MC32X0_AXIS_Z 2
+#define MC32X0_AXES_NUM 3
+#define MC32X0_DATA_LEN 6
+
+#define MC32X0_XOUT_REG 0x00
+#define MC32X0_YOUT_REG 0x01
+#define MC32X0_ZOUT_REG 0x02
+#define MC32X0_Tilt_Status_REG 0x03
+#define MC32X0_Sampling_Rate_Status_REG 0x04
+#define MC32X0_Sleep_Count_REG 0x05
+#define MC32X0_Interrupt_Enable_REG 0x06
+#define MC32X0_Mode_Feature_REG 0x07
+#define MC32X0_Sample_Rate_REG 0x08
+#define MC32X0_Tap_Detection_Enable_REG 0x09
+#define MC32X0_TAP_Dwell_Reject_REG 0x0a
+#define MC32X0_DROP_Control_Register_REG 0x0b
+#define MC32X0_SHAKE_Debounce_REG 0x0c
+#define MC32X0_XOUT_EX_L_REG 0x0d
+#define MC32X0_XOUT_EX_H_REG 0x0e
+#define MC32X0_YOUT_EX_L_REG 0x0f
+#define MC32X0_YOUT_EX_H_REG 0x10
+#define MC32X0_ZOUT_EX_L_REG 0x11
+#define MC32X0_ZOUT_EX_H_REG 0x12
+#define MC32X0_CHIP_ID_REG 0x18
+#define MC32X0_RANGE_Control_REG 0x20
+#define MC32X0_SHAKE_Threshold_REG 0x2B
+#define MC32X0_UD_Z_TH_REG 0x2C
+#define MC32X0_UD_X_TH_REG 0x2D
+#define MC32X0_RL_Z_TH_REG 0x2E
+#define MC32X0_RL_Y_TH_REG 0x2F
+#define MC32X0_FB_Z_TH_REG 0x30
+#define MC32X0_DROP_Threshold_REG 0x31
+#define MC32X0_TAP_Threshold_REG 0x32
+#define MC32X0_HIGH_END 0x01
+/*******MC3210/20 define this**********/
+
+
+#define MCUBE_8G_14BIT 0x10
+
+#define DOT_CALI
+
+#define MC32X0_LOW_END 0x02
+/*******mc32x0 define this**********/
+
+#define MCUBE_1_5G_8BIT 0x20
+//#define MCUBE_1_5G_8BIT_TAP
+//#define MCUBE_1_5G_6BIT
+#define MC32X0_MODE_DEF 0x43
+
+#define MC32X0ADDRESS 0x4c
+
+#define mc32x0_I2C_NAME "mc32x0"
+#define GSENSOR_DEV_COUNT 1
+#define GSENSOR_DURATION_MAX 200
+#define GSENSOR_DURATION_MIN 10
+#define GSENSOR_DURATION_DEFAULT 20
+
+#define MAX_RETRY 20
+#define INPUT_FUZZ 0
+#define INPUT_FLAT 0
+
+#define AUTO_CALIBRATION 0
+
+static unsigned char is_new_mc34x0 = 0;
+static unsigned char is_mc3250 = 0;
+
+static unsigned char McubeID=0;
+#ifdef DOT_CALI
+#define CALIB_PATH "/data/data/com.mcube.acc/files/mcube-calib.txt"
+//MCUBE_BACKUP_FILE
+#define BACKUP_CALIB_PATH "/data/misc/sensors/mcube-calib.txt"
+//static char backup_buf[64];
+//MCUBE_BACKUP_FILE
+#define DATA_PATH "/sdcard/mcube-register-map.txt"
+
+typedef struct {
+ unsigned short x; /**< X axis */
+ unsigned short y; /**< Y axis */
+ unsigned short z; /**< Z axis */
+} GSENSOR_VECTOR3D;
+
+static GSENSOR_VECTOR3D gsensor_gain;
+static struct miscdevice mc32x0_device;
+
+//static struct file * fd_file = NULL;
+
+static mm_segment_t oldfs;
+//add by Liang for storage offset data
+static unsigned char offset_buf[9];
+static signed int offset_data[3];
+s16 G_RAW_DATA[3];
+static signed int gain_data[3];
+static signed int enable_RBM_calibration = 0;
+#endif
+
+#ifdef DOT_CALI
+
+#if 1
+#define GSENSOR 0xA1//0x95
+
+#define GSENSOR_IOCTL_INIT _IO(GSENSOR, 0x01)
+#define GSENSOR_IOCTL_READ_CHIPINFO _IOR(GSENSOR, 0x02, int)
+#define GSENSOR_IOCTL_READ_SENSORDATA _IOR(GSENSOR, 0x17, int)
+#define GSENSOR_IOCTL_READ_OFFSET _IOR(GSENSOR, 0x04, GSENSOR_VECTOR3D)
+#define GSENSOR_IOCTL_READ_GAIN _IOR(GSENSOR, 0x05, GSENSOR_VECTOR3D)
+#define GSENSOR_IOCTL_READ_RAW_DATA _IOR(GSENSOR, 0x30, int)
+//#define GSENSOR_IOCTL_SET_CALI _IOW(GSENSOR, 0x06, SENSOR_DATA)
+#define GSENSOR_IOCTL_GET_CALI _IOW(GSENSOR, 0x22, SENSOR_DATA)
+#define GSENSOR_IOCTL_CLR_CALI _IO(GSENSOR, 0x23)
+#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA _IOR(GSENSOR, 0x24, SENSOR_DATA)
+#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE _IO(GSENSOR, 0x25)
+#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE _IO(GSENSOR, 0x26)
+#define GSENSOR_MCUBE_IOCTL_SET_CALI _IOW(GSENSOR, 0x27, SENSOR_DATA)
+#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP _IO(GSENSOR, 0x28)
+#define GSENSOR_IOCTL_SET_CALI_MODE _IOW(GSENSOR, 0x29,int)
+#else
+
+#define GSENSOR_IOCTL_INIT 0xa1
+#define GSENSOR_IOCTL_READ_CHIPINFO 0xa2
+#define GSENSOR_IOCTL_READ_SENSORDATA 0xa3
+#define GSENSOR_IOCTL_READ_OFFSET 0xa4
+#define GSENSOR_IOCTL_READ_GAIN 0xa5
+#define GSENSOR_IOCTL_READ_RAW_DATA 0xa6
+#define GSENSOR_IOCTL_SET_CALI 0xa7
+#define GSENSOR_IOCTL_GET_CALI 0xa8
+#define GSENSOR_IOCTL_CLR_CALI 0xa9
+
+#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA 0xaa
+#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE 0xab
+#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE 0xac
+#define GSENSOR_MCUBE_IOCTL_SET_CALI 0xad
+#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP 0xae
+#define GSENSOR_IOCTL_SET_CALI_MODE 0xaf
+#endif
+
+typedef struct{
+ int x;
+ int y;
+ int z;
+}SENSOR_DATA;
+
+static int load_cali_flg = 0;
+//MCUBE_BACKUP_FILE
+//static bool READ_FROM_BACKUP = false;
+//MCUBE_BACKUP_FILE
+
+#endif
+
+#define MC32X0_WAKE 1
+#define MC32X0_SNIFF 2
+#define MC32X0_STANDBY 3
+
+struct dev_data {
+ struct i2c_client *client;
+};
+static struct dev_data dev;
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[2] = {MC32X0ADDRESS, I2C_CLIENT_END};
+
+/*
+typedef union {
+ struct {
+ s16 x;
+ s16 y;
+ s16 z;
+ } u;
+ s16 v[SENSOR_DATA_SIZE];
+} raw_data;
+static raw_data offset;
+*/
+
+struct acceleration {
+ int x;
+ int y;
+ int z;
+};
+
+//void gsensor_write_offset_to_file(void);
+//void gsensor_read_offset_from_file(void);
+//char OffsetFileName[] = "/data/misc/dmt/offset.txt";
+/*static struct sensor_config_info gsensor_info = {
+ .input_type = GSENSOR_TYPE,
+};*/
+
+static u32 debug_mask = 0;
+#define dprintk(level_mask, fmt, arg...) if (unlikely(debug_mask & level_mask)) \
+ printk(KERN_DEBUG fmt , ## arg)
+
+module_param_named(debug_mask, debug_mask, int, 0644);
+
+
+enum {
+ DEBUG_INIT = 1U << 0,
+ DEBUG_CONTROL_INFO = 1U << 1,
+ DEBUG_DATA_INFO = 1U << 2,
+ DEBUG_SUSPEND = 1U << 3,
+};
+
+struct mc32x0_data {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct delayed_work work;
+ struct workqueue_struct *mc32x0_wq;
+ struct hrtimer timer;
+ struct device *device;
+ struct input_dev *input_dev;
+ int use_count;
+ int enabled;
+ volatile unsigned int duration;
+ int use_irq;
+ int irq;
+ unsigned long irqflags;
+ int gpio;
+ unsigned int map[3];
+ int inv[3];
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
+ // for control
+ int int_gpio; //0-3 + int op; + int samp; + //int xyz_axis[3][3]; // (axis,direction)
+ struct proc_dir_entry* sensor_proc;
+ int isdbg;
+ int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass;
+ int offset[MC32X0_AXES_NUM+1]; /*+1: for 4-byte alignment*/
+ s16 data[MC32X0_AXES_NUM+1];
+};
+
+static struct mc32x0_data l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .samp = 16,
+ /*.xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },*/
+ .sensor_proc = NULL,
+ .isdbg = 1,
+ .sensor_samp = 1, // 1 sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ //.offset={0,0,0},
+};
+
+
+//=============================================================================
+enum mc3xx0_orientation
+{
+ MC3XX0_TOP_LEFT_DOWN = 0,
+ MC3XX0_TOP_RIGHT_DOWN,
+ MC3XX0_TOP_RIGHT_UP,
+ MC3XX0_TOP_LEFT_UP,
+ MC3XX0_BOTTOM_LEFT_DOWN,
+ MC3XX0_BOTTOM_RIGHT_DOWN,
+ MC3XX0_BOTTOM_RIGHT_UP,
+ MC3XX0_BOTTOM_LEFT_UP
+};
+
+enum mc3xx0_axis
+{
+ MC3XX0_AXIS_X = 0,
+ MC3XX0_AXIS_Y,
+ MC3XX0_AXIS_Z,
+ MC3XX0_AXIS_NUM
+};
+
+struct mc3xx0_hwmsen_convert
+{
+ signed int sign[3];
+ unsigned int map[3];
+};
+
+// Transformation matrix for chip mounting position
+static const struct mc3xx0_hwmsen_convert mc3xx0_cvt[] =
+{
+ {{ 1, 1, 1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 0: top , left-down
+ {{-1, 1, 1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 1: top , right-down
+ {{-1, -1, 1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 2: top , right-up
+ {{ 1, -1, 1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 3: top , left-up
+ {{-1, 1, -1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 4: bottom, left-down
+ {{ 1, 1, -1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 5: bottom, right-down
+ {{ 1, -1, -1}, {MC3XX0_AXIS_X, MC3XX0_AXIS_Y, MC3XX0_AXIS_Z}}, // 6: bottom, right-up
+ {{-1, -1, -1}, {MC3XX0_AXIS_Y, MC3XX0_AXIS_X, MC3XX0_AXIS_Z}}, // 7: bottom, left-up
+};
+
+//static unsigned char mc3xx0_current_placement = MC3XX0_BOTTOM_LEFT_DOWN; // current soldered placement
+static struct mc3xx0_hwmsen_convert *pCvt;
+
+//volatile static short sensor_duration = SENSOR_DURATION_DEFAULT;//delay
+//volatile static short sensor_state_flag = 1;
+
+#ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23
+int Verify_Z_Railed(int AccData, int resolution)
+{
+ int status = 0;
+ GSE_LOG("%s: AccData = %d",__func__, AccData);
+ if(resolution == 1) // Low resolution
+ {
+ if((AccData >= Low_Pos_Max && AccData >=0)|| (AccData <= Low_Neg_Max && AccData < 0))
+ {
+ status = 1;
+ GSE_LOG("%s: Railed at Low Resolution",__func__);
+ }
+ }
+ else if (resolution == 2) //High resolution
+ {
+ if((AccData >= High_Pos_Max && AccData >=0) || (AccData <= High_Neg_Max && AccData < 0))
+ {
+ status = 1;
+ GSE_LOG("%s: Railed at High Resolution",__func__);
+ }
+ }
+ else if (resolution == 3) //High resolution
+ {
+ if((AccData >= Low_Pos_Max*3 && AccData >=0) || (AccData <= Low_Neg_Max*3 && AccData < 0))
+ {
+ status = 1;
+ GSE_LOG("%s: Railed at High Resolution",__func__);
+ }
+ }
+ else
+ GSE_LOG("%s, Wrong resolution",__func__);
+
+ return status;
+}
+
+int SquareRoot(int x)
+{
+ int lowerbound;
+ int upperbound;
+ int root;
+
+ if(x < 0) return -1;
+ if(x == 0 || x == 1) return x;
+ lowerbound = 1;
+ upperbound = x;
+ root = lowerbound + (upperbound - lowerbound)/2;
+
+ while(root > x/root || root+1 <= x/(root+1))
+ {
+ if(root > x/root)
+ {
+ upperbound = root;
+ }
+ else
+ {
+ lowerbound = root;
+ }
+ root = lowerbound + (upperbound - lowerbound)/2;
+ }
+ GSE_LOG("%s: Sqrt root is %d",__func__, root);
+ return root;
+}
+#endif
+
+
+unsigned int sample_rate_2_memsec(unsigned int rate)
+{
+ return (1000/rate);
+}
+
+static ssize_t mc32x0_map_show(struct device *dev, struct device_attribute *attr,char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mc32x0_data *data;
+ int i;
+ data = i2c_get_clientdata(client);
+ for (i = 0; i< 3; i++)
+ {
+ if(data->inv[i] == 1)
+ {
+ switch(data->map[i])
+ {
+ case ABS_X:
+ buf[i] = 'x';
+ break;
+ case ABS_Y:
+ buf[i] = 'y';
+ break;
+ case ABS_Z:
+ buf[i] = 'z';
+ break;
+ default:
+ buf[i] = '_';
+ break;
+ }
+ }
+ else
+ {
+ switch(data->map[i])
+ {
+ case ABS_X:
+ buf[i] = 'X';
+ break;
+ case ABS_Y:
+ buf[i] = 'Y';
+ break;
+ case ABS_Z:
+ buf[i] = 'Z';
+ break;
+ default:
+ buf[i] = '-';
+ break;
+ }
+ }
+ }
+ sprintf(buf+3,"\r\n");
+ return 5;
+}
+/*
+//Function as i2c_master_send, and return 1 if operation is successful.
+static int i2c_write_bytes(struct i2c_client *client, uint8_t *data, uint16_t len)
+{
+ struct i2c_msg msg;
+ int ret=-1;
+
+ msg.flags = !I2C_M_RD;
+ msg.addr = client->addr;
+ msg.len = len;
+ msg.buf = data;
+
+ ret=i2c_transfer(client->adapter, &msg,1);
+ return ret;
+}
+
+static bool gsensor_i2c_test(struct i2c_client * client)
+{
+ int ret, retry;
+ uint8_t test_data[1] = { 0 }; //only write a data address.
+
+ for(retry=0; retry < 2; retry++)
+ {
+ ret =i2c_write_bytes(client, test_data, 1); //Test i2c.
+ if (ret == 1)
+ break;
+ msleep(5);
+ }
+
+ return ret==1 ? true : false;
+}
+*/
+/**
+ * gsensor_detect - Device detection callback for automatic device creation
+ * return value:
+ * = 0; success;
+ * < 0; err
+ */
+ /*
+static int gsensor_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int ret;
+
+ dprintk(DEBUG_INIT, "%s enter \n", __func__);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ if(twi_id == adapter->nr){
+ pr_info("%s: addr= %x\n",__func__,client->addr);
+
+ ret = gsensor_i2c_test(client);
+ if(!ret){
+ pr_info("%s:I2C connection might be something wrong or maybe the other gsensor equipment! \n",__func__);
+ return -ENODEV;
+ }else{
+ pr_info("I2C connection sucess!\n");
+ strlcpy(info->type, SENSOR_NAME, I2C_NAME_SIZE);
+ return 0;
+ }
+
+ }else{
+ return -ENODEV;
+ }
+}
+*/
+int mc32x0_set_image (struct i2c_client *client)
+{
+ int comres = 0;
+ unsigned char data;
+
+
+ data = i2c_smbus_read_byte_data(client, 0x3B);
+ //comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x3B, &data, 1 );
+ if((data == 0x19)||(data == 0x29))
+ {
+ McubeID = 0x22;
+ }
+ else if((data == 0x90)||(data == 0xA8))
+ {
+ McubeID = 0x11;
+ }
+ else
+ {
+ McubeID = 0;
+ }
+
+ if (0x88 == data)
+ {
+ McubeID = 0x11;
+ is_mc3250 = 1;
+ }
+
+ if (0x39 == data)
+ {
+ McubeID = 0x22;
+ is_new_mc34x0 = 1;
+ }
+ else if (0xB8 == data)
+ {
+ McubeID = 0x11;
+ is_new_mc34x0 = 1;
+ }
+
+
+ if(McubeID &MCUBE_8G_14BIT)
+ {
+ //#ifdef MCUBE_8G_14BIT
+ data = MC32X0_MODE_DEF;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Sleep_Count_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Sample_Rate_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Tap_Detection_Enable_REG,data);
+ data = 0x3F;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_RANGE_Control_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Interrupt_Enable_REG,data);
+#ifdef DOT_CALI
+ gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024;
+#endif
+ //#endif
+ }
+ else if(McubeID &MCUBE_1_5G_8BIT)
+ {
+ #ifdef MCUBE_1_5G_8BIT
+ data = MC32X0_MODE_DEF;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Sleep_Count_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Sample_Rate_REG,data);
+ data = 0x02;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_RANGE_Control_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Tap_Detection_Enable_REG,data);
+ data = 0x00;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Interrupt_Enable_REG,data);
+#ifdef DOT_CALI
+ gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 86;
+#endif
+ #endif
+ }
+
+ data = 0x41;
+ //comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+ i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data);
+ //MC32X0_rbm(0,0);
+ return comres;
+}
+
+static ssize_t mc32x0_map_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mc32x0_data *data;
+ int i;
+ data = i2c_get_clientdata(client);
+
+ if(count < 3) return -EINVAL;
+
+ for(i = 0; i< 3; i++)
+ {
+ switch(buf[i])
+ {
+ case 'x':
+ data->map[i] = ABS_X;
+ data->inv[i] = 1;
+ break;
+ case 'y':
+ data->map[i] = ABS_Y;
+ data->inv[i] = 1;
+ break;
+ case 'z':
+ data->map[i] = ABS_Z;
+ data->inv[i] = 1;
+ break;
+ case 'X':
+ data->map[i] = ABS_X;
+ data->inv[i] = -1;
+ break;
+ case 'Y':
+ data->map[i] = ABS_Y;
+ data->inv[i] = -1;
+ break;
+ case 'Z':
+ data->map[i] = ABS_Z;
+ data->inv[i] = -1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return count;
+}
+
+static int mc32x0_enable(struct mc32x0_data *data, int enable);
+
+static ssize_t mc32x0_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = container_of(mc32x0_device.parent, struct i2c_client, dev);
+
+ struct mc32x0_data *mc32x0 = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", mc32x0->enabled);
+}
+
+static ssize_t mc32x0_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ bool new_enable;
+
+ struct i2c_client *client = container_of(mc32x0_device.parent, struct i2c_client, dev);
+
+ struct mc32x0_data *mc32x0 = i2c_get_clientdata(client);
+
+ if (sysfs_streq(buf, "1"))
+ new_enable = true;
+ else if (sysfs_streq(buf, "0"))
+ new_enable = false;
+ else {
+ pr_debug("%s: invalid value %d\n", __func__, *buf);
+ return -EINVAL;
+ }
+
+ mc32x0_enable(mc32x0, new_enable);
+
+ return count;
+}
+
+static ssize_t mc32x0_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", 1000/l_sensorconfig.sensor_samp);
+}
+
+static ssize_t mc32x0_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+
+ error = strict_strtoul(buf, 10, &data);
+ if (error)
+ return error;
+ if (data > GSENSOR_DURATION_MAX)
+ data = GSENSOR_DURATION_MAX;
+ if (data < GSENSOR_DURATION_MIN)
+ data = GSENSOR_DURATION_MIN;
+ l_sensorconfig.sensor_samp = 1000/data;
+
+ return count;
+}
+
+static DEVICE_ATTR(map, 0660, mc32x0_map_show, mc32x0_map_store);
+static DEVICE_ATTR(enable, 0660, mc32x0_enable_show, mc32x0_enable_store);
+static DEVICE_ATTR(delay, 0660, mc32x0_delay_show, mc32x0_delay_store);
+
+static struct attribute* mc32x0_attrs[] =
+{
+ &dev_attr_map.attr,
+ &dev_attr_enable.attr,
+ &dev_attr_delay.attr,
+ NULL
+};
+
+static const struct attribute_group mc32x0_group =
+{
+ .attrs = mc32x0_attrs,
+};
+
+static int mc32x0_chip_init(struct i2c_client *client)
+{
+
+ mc32x0_set_image(client);
+
+ return McubeID?0:-1;
+}
+
+int mc32x0_set_mode(struct i2c_client *client, unsigned char mode)
+{
+
+ int comres=0;
+ unsigned char data;
+
+
+ if (mode<4) {
+ data = 0x40|mode;
+ i2c_smbus_write_byte_data(client, MC32X0_Mode_Feature_REG,data);
+ }
+ return comres;
+
+}
+
+
+
+#ifdef DOT_CALI
+struct file *openFile(const char *path,int flag,int mode)
+{
+ struct file *fp;
+
+ fp=filp_open(path, flag, mode);
+ if (IS_ERR(fp) || !fp->f_op)
+ {
+ GSE_LOG("Calibration File filp_open return NULL\n");
+ return NULL;
+ }
+ else
+ {
+
+ return fp;
+ }
+}
+
+int readFile(struct file *fp,char *buf,int readlen)
+{
+ if (fp->f_op && fp->f_op->read)
+ return fp->f_op->read(fp,buf,readlen, &fp->f_pos);
+ else
+ return -1;
+}
+
+int writeFile(struct file *fp,char *buf,int writelen)
+{
+ if (fp->f_op && fp->f_op->write)
+ return fp->f_op->write(fp,buf,writelen, &fp->f_pos);
+ else
+ return -1;
+}
+
+int closeFile(struct file *fp)
+{
+ filp_close(fp,NULL);
+ return 0;
+}
+
+void initKernelEnv(void)
+{
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ printk(KERN_INFO "initKernelEnv\n");
+}
+
+ int MC32X0_WriteCalibration(struct i2c_client *client, int dat[MC32X0_AXES_NUM])
+{
+ int err;
+ u8 buf[9];
+ s16 tmp, x_gain, y_gain, z_gain ;
+ s32 x_off, y_off, z_off;
+ int temp_cali_dat[MC32X0_AXES_NUM] = { 0 };
+ //const struct mc3xx0_hwmsen_convert *pCvt = NULL;
+
+ //pCvt = &mc3xx0_cvt[mc3xx0_current_placement];
+
+ temp_cali_dat[pCvt->map[MC3XX0_AXIS_X]] = pCvt->sign[MC3XX0_AXIS_X] * dat[MC3XX0_AXIS_X];
+ temp_cali_dat[pCvt->map[MC3XX0_AXIS_Y]] = pCvt->sign[MC3XX0_AXIS_Y] * dat[MC3XX0_AXIS_Y];
+ temp_cali_dat[pCvt->map[MC3XX0_AXIS_Z]] = pCvt->sign[MC3XX0_AXIS_Z] * dat[MC3XX0_AXIS_Z];
+/*
+ temp_cali_dat[MC3XX0_AXIS_X] = ((temp_cali_dat[MC3XX0_AXIS_X] * gsensor_gain.x) / GRAVITY_1G_VALUE);
+ temp_cali_dat[MC3XX0_AXIS_Y] = ((temp_cali_dat[MC3XX0_AXIS_Y] * gsensor_gain.y) / GRAVITY_1G_VALUE);
+ temp_cali_dat[MC3XX0_AXIS_Z] = ((temp_cali_dat[MC3XX0_AXIS_Z] * gsensor_gain.z) / GRAVITY_1G_VALUE);
+*/
+ if (is_new_mc34x0)
+ {
+ temp_cali_dat[MC3XX0_AXIS_X] = -temp_cali_dat[MC3XX0_AXIS_X];
+ temp_cali_dat[MC3XX0_AXIS_Y] = -temp_cali_dat[MC3XX0_AXIS_Y];
+ }
+ else if (is_mc3250)
+ {
+ s16 temp = 0;
+
+ temp = temp_cali_dat[MC3XX0_AXIS_X];
+
+ temp_cali_dat[MC3XX0_AXIS_X] = -temp_cali_dat[MC3XX0_AXIS_Y];
+ temp_cali_dat[MC3XX0_AXIS_Y] = temp;
+ }
+
+ dat[MC3XX0_AXIS_X] = temp_cali_dat[MC3XX0_AXIS_X];
+ dat[MC3XX0_AXIS_Y] = temp_cali_dat[MC3XX0_AXIS_Y];
+ dat[MC3XX0_AXIS_Z] = temp_cali_dat[MC3XX0_AXIS_Z];
+
+#if 0 //modify by zwx
+
+ GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n",
+ dat[MC32X0_AXIS_X], dat[MC32X0_AXIS_Y], dat[MC32X0_AXIS_Z]);
+
+ /*calculate the real offset expected by caller*/
+ //cali_temp[MC32X0_AXIS_X] = dat[MC32X0_AXIS_X];
+ //cali_temp[MC32X0_AXIS_Y] = dat[MC32X0_AXIS_Y];
+ //cali_temp[MC32X0_AXIS_Z] = dat[MC32X0_AXIS_Z];
+ //cali[MC32X0_AXIS_Z]= cali[MC32X0_AXIS_Z]-gsensor_gain.z;
+
+
+#endif
+// read register 0x21~0x28
+#if 1 //zwx
+ //if ((err = mc32x0_read_block(client, 0x21, buf, 3)))
+ //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x21, &buf[0],3)))
+ err = i2c_smbus_read_i2c_block_data(client , 0x21 , 3 , &buf[0]);
+
+ //if ((err = mc32x0_read_block(client, 0x24, &buf[3], 3)))
+ //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x24, &buf[3],3)))
+ err = i2c_smbus_read_i2c_block_data(client , 0x24 , 3 , &buf[3]);
+
+ //if ((err = mc32x0_read_block(client, 0x27, &buf[6], 3)))
+ //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x27, &buf[6],3)))
+ err = i2c_smbus_read_i2c_block_data(client , 0x27 , 3 , &buf[6]);
+
+#else
+ buf[0] = 0x21;
+ err = mc32x0_rx_data(client, &buf[0], 3);
+ buf[3] = 0x24;
+ err = mc32x0_rx_data(client, &buf[3], 3);
+ buf[6] = 0x27;
+ err = mc32x0_rx_data(client, &buf[6], 3);
+#endif
+#if 1
+ // get x,y,z offset
+ tmp = ((buf[1] & 0x3f) << 8) + buf[0];
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ x_off = tmp;
+
+ tmp = ((buf[3] & 0x3f) << 8) + buf[2];
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ y_off = tmp;
+
+ tmp = ((buf[5] & 0x3f) << 8) + buf[4];
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ z_off = tmp;
+
+ // get x,y,z gain
+ x_gain = ((buf[1] >> 7) << 8) + buf[6];
+ y_gain = ((buf[3] >> 7) << 8) + buf[7];
+ z_gain = ((buf[5] >> 7) << 8) + buf[8];
+
+ // prepare new offset
+ x_off = x_off + 16 * dat[MC32X0_AXIS_X] * 256 * 128 / 3 / gsensor_gain.x / (40 + x_gain);
+ y_off = y_off + 16 * dat[MC32X0_AXIS_Y] * 256 * 128 / 3 / gsensor_gain.y / (40 + y_gain);
+ z_off = z_off + 16 * dat[MC32X0_AXIS_Z] * 256 * 128 / 3 / gsensor_gain.z / (40 + z_gain);
+
+ //storege the cerrunt offset data with DOT format
+ offset_data[0] = x_off;
+ offset_data[1] = y_off;
+ offset_data[2] = z_off;
+
+ //storege the cerrunt Gain data with GOT format
+ gain_data[0] = 256*8*128/3/(40+x_gain);
+ gain_data[1] = 256*8*128/3/(40+y_gain);
+ gain_data[2] = 256*8*128/3/(40+z_gain);
+ printk("%d %d ======================\n\n ",gain_data[0],x_gain);
+#endif
+ buf[0]=0x43;
+ //mc32x0_write_block(client, 0x07, buf, 1);
+ //mc32x0_write_reg(client,0x07,0x43);
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf[0]);
+ buf[0] = x_off & 0xff;
+ buf[1] = ((x_off >> 8) & 0x3f) | (x_gain & 0x0100 ? 0x80 : 0);
+ buf[2] = y_off & 0xff;
+ buf[3] = ((y_off >> 8) & 0x3f) | (y_gain & 0x0100 ? 0x80 : 0);
+ buf[4] = z_off & 0xff;
+ buf[5] = ((z_off >> 8) & 0x3f) | (z_gain & 0x0100 ? 0x80 : 0);
+
+
+ //mc32x0_write_block(client, 0x21, buf, 6);
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x21, &buf[0], 6 );
+ i2c_smbus_write_i2c_block_data(client, 0x21, 2,&buf[0]);
+ i2c_smbus_write_i2c_block_data(client, 0x21+2, 2,&buf[2]);
+ i2c_smbus_write_i2c_block_data(client, 0x21+4, 2,&buf[4]);
+
+
+ buf[0]=0x41;
+ //mc32x0_write_block(client, 0x07, buf, 1);
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf[0]);
+ //mc32x0_write_reg(client,0x07,0x41);
+
+ return err;
+
+}
+/*
+int mcube_read_cali_file(struct i2c_client *client)
+{
+ int cali_data[3];
+ int err =0;
+
+ printk("%s %d\n",__func__,__LINE__);
+ //MCUBE_BACKUP_FILE
+ READ_FROM_BACKUP = false;
+ //MCUBE_BACKUP_FILE
+ initKernelEnv();
+ fd_file = openFile(CALIB_PATH,O_RDONLY,0);
+ //MCUBE_BACKUP_FILE
+ if (fd_file == NULL)
+ {
+ fd_file = openFile(BACKUP_CALIB_PATH, O_RDONLY, 0);
+ if(fd_file != NULL)
+ {
+ READ_FROM_BACKUP = true;
+ }
+ }
+ //MCUBE_BACKUP_FILE
+ if (fd_file == NULL)
+ {
+ GSE_LOG("fail to open\n");
+ cali_data[0] = 0;
+ cali_data[1] = 0;
+ cali_data[2] = 0;
+ return 1;
+ }
+ else
+ {
+ printk("%s %d\n",__func__,__LINE__);
+ memset(backup_buf,0,64);
+ if ((err = readFile(fd_file,backup_buf,128))>0)
+ GSE_LOG("buf:%s\n",backup_buf);
+ else
+ GSE_LOG("read file error %d\n",err);
+ printk("%s %d\n",__func__,__LINE__);
+
+ set_fs(oldfs);
+ closeFile(fd_file);
+
+ sscanf(backup_buf, "%d %d %d",&cali_data[MC32X0_AXIS_X], &cali_data[MC32X0_AXIS_Y], &cali_data[MC32X0_AXIS_Z]);
+ GSE_LOG("cali_data: %d %d %d\n", cali_data[MC32X0_AXIS_X], cali_data[MC32X0_AXIS_Y], cali_data[MC32X0_AXIS_Z]);
+
+ //cali_data1[MC32X0_AXIS_X] = cali_data[MC32X0_AXIS_X] * gsensor_gain.x / GRAVITY_EARTH_1000;
+ //cali_data1[MC32X0_AXIS_Y] = cali_data[MC32X0_AXIS_Y] * gsensor_gain.y / GRAVITY_EARTH_1000;
+ //cali_data1[MC32X0_AXIS_Z] = cali_data[MC32X0_AXIS_Z] * gsensor_gain.z / GRAVITY_EARTH_1000;
+ //cali_data[MC32X0_AXIS_X]=-cali_data[MC32X0_AXIS_X];
+ //cali_data[MC32X0_AXIS_Y]=-cali_data[MC32X0_AXIS_Y];
+ //cali_data[MC32X0_AXIS_Z]=-cali_data[MC32X0_AXIS_Z];
+
+ //GSE_LOG("cali_data1: %d %d %d\n", cali_data1[MC32X0_AXIS_X], cali_data1[MC32X0_AXIS_Y], cali_data1[MC32X0_AXIS_Z]);
+ printk("%s %d\n",__func__,__LINE__);
+ MC32X0_WriteCalibration(client,cali_data);
+ }
+
+ return 0;
+}
+*/
+
+void MC32X0_rbm(struct i2c_client *client, int enable)
+{
+ //int err;
+ char buf1[3];
+ if(enable == 1 )
+ {
+#if 1
+ buf1[0] = 0x43;
+ //err = mc32x0_write_block(client, 0x07, buf1, 0x01);
+ //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf1[0]);
+ buf1[0] = 0x02;
+ //err = mc32x0_write_block(client, 0x14, buf1, 0x01);
+ //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x14, &buf1[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x14,buf1[0]);
+ buf1[0] = 0x41;
+ //err = mc32x0_write_block(client, 0x07, buf1, 0x01);
+ //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf1[0]);
+#else
+ err = mc32x0_write_reg(client,0x07,0x43);
+ err = mc32x0_write_reg(client,0x14,0x02);
+ err = mc32x0_write_reg(client,0x07,0x41);
+#endif
+ enable_RBM_calibration =1;
+
+ GSE_LOG("set rbm!!\n");
+
+ msleep(10);
+ }
+ else if(enable == 0 )
+ {
+#if 1
+ buf1[0] = 0x43;
+ //err = mc32x0_write_block(client, 0x07, buf1, 0x01);
+ //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf1[0]);
+
+ buf1[0] = 0x00;
+ //err = mc32x0_write_block(client, 0x14, buf1, 0x01);
+ //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x14, &buf1[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x14,buf1[0]);
+ buf1[0] = 0x41;
+ //err = mc32x0_write_block(client, 0x07, buf1, 0x01);
+ //err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf1[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf1[0]);
+#else
+ err = mc32x0_write_reg(client,0x07,0x43);
+ err = mc32x0_write_reg(client,0x14,0x00);
+ err = mc32x0_write_reg(client,0x07,0x41);
+#endif
+ enable_RBM_calibration =0;
+
+ GSE_LOG("clear rbm!!\n");
+
+ msleep(10);
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+ int MC32X0_ReadData_RBM(struct i2c_client *client,int data[MC32X0_AXES_NUM])
+{
+ //u8 uData;
+ u8 addr = 0x0d;
+ u8 rbm_buf[MC32X0_DATA_LEN] = {0};
+ int err = 0;
+
+
+ //err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, addr, &rbm_buf[0],6);
+ err = i2c_smbus_read_i2c_block_data(client , addr , 6 , rbm_buf);
+ //err = mc32x0_read_block(client, addr, rbm_buf, 0x06);
+
+ data[MC32X0_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8));
+ data[MC32X0_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8));
+ data[MC32X0_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8));
+
+ GSE_LOG("rbm_buf<<<<<[%02x %02x %02x %02x %02x %02x]\n",rbm_buf[0], rbm_buf[2], rbm_buf[2], rbm_buf[3], rbm_buf[4], rbm_buf[5]);
+ GSE_LOG("RBM<<<<<[%04x %04x %04x]\n", data[MC32X0_AXIS_X], data[MC32X0_AXIS_Y], data[MC32X0_AXIS_Z]);
+ GSE_LOG("RBM<<<<<[%04d %04d %04d]\n", data[MC32X0_AXIS_X], data[MC32X0_AXIS_Y], data[MC32X0_AXIS_Z]);
+ return err;
+}
+
+
+ int MC32X0_ReadRBMData(struct i2c_client *client, char *buf)
+{
+ //struct mc32x0_data *mc32x0 = i2c_get_clientdata(client);
+ int res = 0;
+ int data[3];
+
+ if (!buf)
+ {
+ return EINVAL;
+ }
+
+ mc32x0_set_mode(client,MC32X0_WAKE);
+/*
+ if(mc32x0->status == mc32x0_CLOSE)
+ {
+ res = mc32x0_start(client, 0);
+ if(res)
+ {
+ GSE_ERR("Power on mc32x0 error %d!\n", res);
+ }
+ }
+*/
+ if((res = MC32X0_ReadData_RBM(client,data)))
+ {
+ GSE_ERR("%s I2C error: ret value=%d",__func__, res);
+ return EIO;
+ }
+ else
+ {
+ sprintf(buf, "%04x %04x %04x", data[MC32X0_AXIS_X],
+ data[MC32X0_AXIS_Y], data[MC32X0_AXIS_Z]);
+
+ }
+
+ return 0;
+}
+ int MC32X0_ReadOffset(struct i2c_client *client,s16 ofs[MC32X0_AXES_NUM])
+{
+ int err;
+ u8 off_data[6];
+
+
+ if(McubeID &MCUBE_8G_14BIT)
+ {
+
+ //if ((err = mc32x0_read_block(client, MC32X0_XOUT_EX_L_REG, off_data, MC32X0_DATA_LEN)))
+ //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &off_data[0],MC32X0_DATA_LEN)))
+ err = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_EX_L_REG , MC32X0_DATA_LEN , off_data);
+
+ ofs[MC32X0_AXIS_X] = ((s16)(off_data[0]))|((s16)(off_data[1])<<8);
+ ofs[MC32X0_AXIS_Y] = ((s16)(off_data[2]))|((s16)(off_data[3])<<8);
+ ofs[MC32X0_AXIS_Z] = ((s16)(off_data[4]))|((s16)(off_data[5])<<8);
+ }
+ else if(McubeID &MCUBE_1_5G_8BIT)
+ {
+ //if ((err = mc32x0_read_block(client, 0, off_data, 3)))
+ //if ((err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0, &off_data[0],3)))
+ err = i2c_smbus_read_i2c_block_data(client , 0 , 3 , off_data);
+
+ ofs[MC32X0_AXIS_X] = (s8)off_data[0];
+ ofs[MC32X0_AXIS_Y] = (s8)off_data[1];
+ ofs[MC32X0_AXIS_Z] = (s8)off_data[2];
+ }
+
+ GSE_LOG("MC32X0_ReadOffset %d %d %d \n",ofs[MC32X0_AXIS_X] ,ofs[MC32X0_AXIS_Y],ofs[MC32X0_AXIS_Z]);
+
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+ int MC32X0_ResetCalibration(struct i2c_client *client)
+{
+
+ u8 buf[6];
+ s16 tmp;
+ int err;
+#if 1 //zwx
+ buf[0] = 0x43;
+ //if(err = mc32x0_write_block(client, 0x07, buf, 1))
+ //if(err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 ))
+ if((err = i2c_smbus_write_byte_data(client, 0x07,buf[0])))
+ {
+ GSE_ERR("error 0x07: %d\n", err);
+ }
+
+
+ //if(err = mc32x0_write_block(client, 0x21, offset_buf, 6)) // add by liang for writing offset register as OTP value
+ //if(err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x21, &offset_buf[0], 6 ))
+ if((err = i2c_smbus_write_i2c_block_data(client, 0x21, 6,offset_buf)))
+ {
+ GSE_ERR("error: %d\n", err);
+ }
+
+ buf[0] = 0x41;
+ //if(err = mc32x0_write_block(client, 0x07, buf, 1))
+ //if(err = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 ))
+ if((err = i2c_smbus_write_byte_data(client, 0x07,buf[0])))
+ {
+ GSE_ERR("error: %d\n", err);
+ }
+#else
+ mc32x0_write_reg(client,0x07,0x43);
+
+ mc32x0_write_block(client, 0x21, offset_buf, 6);
+
+ mc32x0_write_reg(client,0x07,0x41);
+#endif
+ msleep(20);
+
+ tmp = ((offset_buf[1] & 0x3f) << 8) + offset_buf[0]; // add by Liang for set offset_buf as OTP value
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ offset_data[0] = tmp;
+
+ tmp = ((offset_buf[3] & 0x3f) << 8) + offset_buf[2]; // add by Liang for set offset_buf as OTP value
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ offset_data[1] = tmp;
+
+ tmp = ((offset_buf[5] & 0x3f) << 8) + offset_buf[4]; // add by Liang for set offset_buf as OTP value
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ offset_data[2] = tmp;
+
+ //memset(mc32x0->cali_sw, 0x00, sizeof(mc32x0->cali_sw));
+ return 0;
+
+}
+/*----------------------------------------------------------------------------*/
+ int MC32X0_ReadCalibration(struct i2c_client *client,int dat[MC32X0_AXES_NUM])
+{
+
+ signed short MC_offset[MC32X0_AXES_NUM+1]; /*+1: for 4-byte alignment*/
+ int err;
+ memset(MC_offset, 0, sizeof(MC_offset));
+ if ((err = MC32X0_ReadOffset(client, MC_offset))) {
+ GSE_ERR("read offset fail, %d\n", err);
+ return err;
+ }
+
+ dat[MC32X0_AXIS_X] = MC_offset[MC32X0_AXIS_X];
+ dat[MC32X0_AXIS_Y] = MC_offset[MC32X0_AXIS_Y];
+ dat[MC32X0_AXIS_Z] = MC_offset[MC32X0_AXIS_Z];
+ //modify by zwx
+ //GSE_LOG("MC32X0_ReadCalibration %d %d %d \n",dat[mc32x0->cvt.map[MC32X0_AXIS_X]] ,dat[mc32x0->cvt.map[MC32X0_AXIS_Y]],dat[mc32x0->cvt.map[MC32X0_AXIS_Z]]);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+ int MC32X0_ReadData(struct i2c_client *client, s16 buffer[MC32X0_AXES_NUM])
+{
+ unsigned char buf[6];
+ signed char buf1[6];
+ char rbm_buf[6];
+ int ret;
+ //int err = 0;
+
+ #ifdef SUPPORT_VIRTUAL_Z_SENSOR
+ int tempX=0; + int tempY=0; + int tempZ=0; + #endif
+
+ if ( enable_RBM_calibration == 0)
+ {
+ //err = hwmsen_read_block(client, addr, buf, 0x06);
+ }
+ else if (enable_RBM_calibration == 1)
+ {
+ memset(rbm_buf, 0, 6);
+ //rbm_buf[0] = mc32x0_REG_RBM_DATA;
+ //ret = mc32x0_rx_data(client, &rbm_buf[0], 6);
+ //ret = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x0d, &rbm_buf[0],6);
+ i2c_smbus_read_i2c_block_data(client , 0x0d , 2 , &rbm_buf[0]);
+ i2c_smbus_read_i2c_block_data(client , 0x0d+2 , 2 , &rbm_buf[2]);
+ i2c_smbus_read_i2c_block_data(client , 0x0d+4 , 2 , &rbm_buf[4]);
+ }
+
+ if ( enable_RBM_calibration == 0)
+ {
+
+ if(McubeID &MC32X0_HIGH_END)
+ {
+ #ifdef MC32X0_HIGH_END
+ ret = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_EX_L_REG , 6 , buf);
+ //ret = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &buf[0],6);
+
+ buffer[0] = (signed short)((buf[0])|(buf[1]<<8));
+ buffer[1] = (signed short)((buf[2])|(buf[3]<<8));
+ buffer[2] = (signed short)((buf[4])|(buf[5]<<8));
+ #endif
+ }
+ else if(McubeID &MC32X0_LOW_END)
+ {
+ #ifdef MC32X0_LOW_END
+ ret = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_REG , 3 , buf1);
+ //ret = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_REG, &buf[0],3);
+
+ buffer[0] = (signed short)buf1[0];
+ buffer[1] = (signed short)buf1[1];
+ buffer[2] = (signed short)buf1[2];
+ #endif
+ }
+ #ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23
+ if (g_virtual_z) + { + //printk("%s 1\n", __FUNCTION__); + + tempX = buffer[MC32X0_AXIS_X]; + tempY = buffer[MC32X0_AXIS_Y]; + tempZ = buffer[MC32X0_AXIS_Z]; + //printk(" %d:Verify_Z_Railed() %d\n", (int)buffer[MC32X0_AXIS_Z], Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], LOW_RESOLUTION)); + if(1 == Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], LOW_RESOLUTION)) // z-railed + { + Railed = 1; + + GSE_LOG("%s: Z railed", __func__); + //printk("%s: Z railed \n", __func__); + if (G_2_REVERSE_VIRTUAL_Z == 1)
+ buffer[MC32X0_AXIS_Z] = (s8) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC32X0_AXIS_Z] = (s8) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + else + { + Railed = 0; + } + } + #endif
+ mcprintkreg("MC32X0_ReadData : %d %d %d \n",buffer[0],buffer[1],buffer[2]);
+ }
+ else if (enable_RBM_calibration == 1)
+ {
+ buffer[MC32X0_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8));
+ buffer[MC32X0_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8));
+ buffer[MC32X0_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8));
+
+ GSE_LOG("%s RBM<<<<<[%08d %08d %08d]\n", __func__,buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]);
+ if(gain_data[0] == 0)
+ {
+ buffer[MC32X0_AXIS_X] = 0;
+ buffer[MC32X0_AXIS_Y] = 0;
+ buffer[MC32X0_AXIS_Z] = 0;
+ return 0;
+ }
+ buffer[MC32X0_AXIS_X] = (buffer[MC32X0_AXIS_X] + offset_data[0]/2)*gsensor_gain.x/gain_data[0];
+ buffer[MC32X0_AXIS_Y] = (buffer[MC32X0_AXIS_Y] + offset_data[1]/2)*gsensor_gain.y/gain_data[1];
+ buffer[MC32X0_AXIS_Z] = (buffer[MC32X0_AXIS_Z] + offset_data[2]/2)*gsensor_gain.z/gain_data[2];
+
+ #ifdef SUPPORT_VIRTUAL_Z_SENSOR // add 2013-10-23
+ if (g_virtual_z) + { + tempX = buffer[MC32X0_AXIS_X]; + tempY = buffer[MC32X0_AXIS_Y]; + tempZ = buffer[MC32X0_AXIS_Z]; + //printk("%s 2\n", __FUNCTION__); + GSE_LOG("Original RBM<<<<<[%08d %08d %08d]\n", buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]); + printk("Verify_Z_Railed() %d\n", Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], RBM_RESOLUTION)); + if(1 == Verify_Z_Railed(buffer[MC32X0_AXIS_Z], RBM_RESOLUTION)) // z-railed + { + GSE_LOG("%s: Z Railed in RBM mode",__FUNCTION__); + //printk("%s: Z Railed in RBM mode\n",__FUNCTION__); + if (G_2_REVERSE_VIRTUAL_Z == 1)
+ buffer[MC32X0_AXIS_Z] = (s16) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC32X0_AXIS_Z] = (s16) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + GSE_LOG("RBM<<<<<[%08d %08d %08d]\n", buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]); + } + #endif
+
+ GSE_LOG("%s offset_data <<<<<[%d %d %d]\n", __func__,offset_data[0], offset_data[1], offset_data[2]);
+
+ GSE_LOG("%s gsensor_gain <<<<<[%d %d %d]\n", __func__,gsensor_gain.x, gsensor_gain.y, gsensor_gain.z);
+
+ GSE_LOG("%s gain_data <<<<<[%d %d %d]\n", __func__,gain_data[0], gain_data[1], gain_data[2]);
+
+ GSE_LOG("%s RBM->RAW <<<<<[%d %d %d]\n", __func__,buffer[MC32X0_AXIS_X], buffer[MC32X0_AXIS_Y], buffer[MC32X0_AXIS_Z]);
+ }
+
+ return 0;
+}
+
+int MC32X0_ReadRawData(struct i2c_client *client, char * buf)
+{
+
+
+ int res = 0;
+ s16 raw_buf[3];
+
+ if (!buf)
+ {
+ return EINVAL;
+ }
+
+ //mc32x0_power_up(mc32x0);
+ mc32x0_set_mode(client, MC32X0_WAKE);
+ if((res = MC32X0_ReadData(client,&raw_buf[0])))
+ {
+ printk("%s %d\n",__FUNCTION__, __LINE__);
+ GSE_ERR("I2C error: ret value=%d", res);
+ return EIO;
+ }
+ else
+ {
+ //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement];
+ GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n",
+ raw_buf[MC32X0_AXIS_X], raw_buf[MC32X0_AXIS_Y], raw_buf[MC32X0_AXIS_Z]);
+
+ //G_RAW_DATA[MC32X0_AXIS_X] = raw_buf[0];
+ //G_RAW_DATA[MC32X0_AXIS_Y] = raw_buf[1];
+ //G_RAW_DATA[MC32X0_AXIS_Z] = raw_buf[2];
+ //G_RAW_DATA[MC32X0_AXIS_Z] = G_RAW_DATA[MC32X0_AXIS_Z] + gsensor_gain.z;
+/*
+ raw_buf[MC3XX0_AXIS_X] = ((raw_buf[MC3XX0_AXIS_X] * GRAVITY_1G_VALUE) / gsensor_gain.x);
+ raw_buf[MC3XX0_AXIS_Y] = ((raw_buf[MC3XX0_AXIS_Y] * GRAVITY_1G_VALUE) / gsensor_gain.y);
+ raw_buf[MC3XX0_AXIS_Z] = ((raw_buf[MC3XX0_AXIS_Z] * GRAVITY_1G_VALUE) / gsensor_gain.z);
+*/
+ if (is_new_mc34x0)
+ {
+ raw_buf[MC3XX0_AXIS_X] = -raw_buf[MC3XX0_AXIS_X];
+ raw_buf[MC3XX0_AXIS_Y] = -raw_buf[MC3XX0_AXIS_Y];
+ }
+ else if (is_mc3250)
+ {
+ s16 temp = 0;
+
+ temp = raw_buf[MC3XX0_AXIS_X];
+
+ raw_buf[MC3XX0_AXIS_X] = raw_buf[MC3XX0_AXIS_Y];
+ raw_buf[MC3XX0_AXIS_Y] = -temp;
+ }
+
+ G_RAW_DATA[MC3XX0_AXIS_X] = pCvt->sign[MC3XX0_AXIS_X] * raw_buf[pCvt->map[MC3XX0_AXIS_X]];
+ G_RAW_DATA[MC3XX0_AXIS_Y] = pCvt->sign[MC3XX0_AXIS_Y] * raw_buf[pCvt->map[MC3XX0_AXIS_Y]];
+ G_RAW_DATA[MC3XX0_AXIS_Z] = pCvt->sign[MC3XX0_AXIS_Z] * raw_buf[pCvt->map[MC3XX0_AXIS_Z]];
+
+ G_RAW_DATA[MC32X0_AXIS_Z] += gsensor_gain.z*(pCvt->sign[MC3XX0_AXIS_Z])*(1);//-=GRAVITY_1G_VALUE;
+
+ //printk("%s %d\n",__FUNCTION__, __LINE__);
+ sprintf(buf, "%04x %04x %04x", G_RAW_DATA[MC32X0_AXIS_X],
+ G_RAW_DATA[MC32X0_AXIS_Y], G_RAW_DATA[MC32X0_AXIS_Z]);
+ GSE_LOG("G_RAW_DATA: (%+3d %+3d %+3d)\n",
+ G_RAW_DATA[MC32X0_AXIS_X], G_RAW_DATA[MC32X0_AXIS_Y], G_RAW_DATA[MC32X0_AXIS_Z]);
+ }
+ return 0;
+}
+
+int mc32x0_reset (struct i2c_client *client)
+{
+
+ s16 tmp, x_gain, y_gain, z_gain ;
+ s32 x_off, y_off, z_off;
+ u8 buf[3];
+ int err;
+ //mc32x0_write_reg(client,0x1b,0x6d);
+ buf[0]=0x6d;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x1b,buf[0]);
+
+ //mc32x0_write_reg(client,0x1b,0x43);
+ buf[0]=0x43;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x1b,buf[0]);
+ msleep(5);
+
+ //mc32x0_write_reg(client,0x07,0x43);
+ buf[0]=0x43;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x07,buf[0]);
+ //mc32x0_write_reg(client,0x1C,0x80);
+ buf[0]=0x80;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1C, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x1c,buf[0]);
+ //mc32x0_write_reg(client,0x17,0x80);
+ buf[0]=0x80;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x17,buf[0]);
+ msleep(5);
+ //mc32x0_write_reg(client,0x1C,0x00);
+ buf[0]=0x00;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1C, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x1c,buf[0]);
+ //mc32x0_write_reg(client,0x17,0x00);
+ buf[0]=0x00;
+ //p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &buf[0], 1 );
+ i2c_smbus_write_byte_data(client, 0x17,buf[0]);
+ msleep(5);
+
+
+/*
+ if ((err = mc32x0_read_block(new_client, 0x21, offset_buf, 6))) //add by Liang for storeage OTP offsef register value
+ {
+ GSE_ERR("error: %d\n", err);
+ return err;
+ }
+*/
+ memset(offset_buf, 0, 9);
+ //offset_buf[0] = 0x21;
+ //err = mc32x0_rx_data(client, offset_buf, 9);
+ //err = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, 0x21, &offset_buf[0],9);
+ err = i2c_smbus_read_i2c_block_data(client , 0x21 , 9 , offset_buf);
+
+
+ tmp = ((offset_buf[1] & 0x3f) << 8) + offset_buf[0];
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ x_off = tmp;
+
+ tmp = ((offset_buf[3] & 0x3f) << 8) + offset_buf[2];
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ y_off = tmp;
+
+ tmp = ((offset_buf[5] & 0x3f) << 8) + offset_buf[4];
+ if (tmp & 0x2000)
+ tmp |= 0xc000;
+ z_off = tmp;
+
+ // get x,y,z gain
+ x_gain = ((offset_buf[1] >> 7) << 8) + offset_buf[6];
+ y_gain = ((offset_buf[3] >> 7) << 8) + offset_buf[7];
+ z_gain = ((offset_buf[5] >> 7) << 8) + offset_buf[8];
+
+
+ //storege the cerrunt offset data with DOT format
+ offset_data[0] = x_off;
+ offset_data[1] = y_off;
+ offset_data[2] = z_off;
+
+ //storege the cerrunt Gain data with GOT format
+ gain_data[0] = 256*8*128/3/(40+x_gain);
+ gain_data[1] = 256*8*128/3/(40+y_gain);
+ gain_data[2] = 256*8*128/3/(40+z_gain);
+ printk("offser gain = %d %d %d %d %d %d======================\n\n ",
+ gain_data[0],gain_data[1],gain_data[2],offset_data[0],offset_data[1],offset_data[2]);
+
+ return 0;
+}
+#endif
+
+int mc32x0_read_accel_xyz(struct i2c_client *client, s16 * acc)
+{
+ int comres;
+ s16 raw_data[MC3XX0_AXIS_NUM] = { 0 };
+ //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement];
+#ifdef DOT_CALI
+ s16 raw_buf[6];
+
+
+ comres = MC32X0_ReadData(client,&raw_buf[0]);
+
+ acc[0] = raw_buf[0];
+ acc[1] = raw_buf[1];
+ acc[2] = raw_buf[2];
+#else
+ unsigned char raw_buf[6];
+ signed char raw_buf1[3];
+ if(McubeID &MC32X0_HIGH_END)
+ {
+ #ifdef MC32X0_HIGH_END
+ comres = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_EX_L_REG , 6 , raw_buf);
+ //comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &data[0],6);
+
+ acc[0] = (signed short)((raw_buf[0])|(raw_buf[1]<<8));
+ acc[1] = (signed short)((raw_buf[2])|(raw_buf[3]<<8));
+ acc[2] = (signed short)((raw_buf[4])|(raw_buf[5]<<8));
+ #endif
+ }
+ else if(McubeID &MC32X0_LOW_END)
+ {
+ #ifdef MC32X0_LOW_END
+ comres = i2c_smbus_read_i2c_block_data(client , MC32X0_XOUT_REG , 3 , raw_buf1);
+ //comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_REG, &data[0],3);
+
+ acc[0] = (signed short)raw_buf1[0];
+ acc[1] = (signed short)raw_buf1[1];
+ acc[2] = (signed short)raw_buf1[2];
+ #endif
+ }
+#endif
+
+ raw_data[MC3XX0_AXIS_X] = acc[MC3XX0_AXIS_X];
+ raw_data[MC3XX0_AXIS_Y] = acc[MC3XX0_AXIS_Y];
+ raw_data[MC3XX0_AXIS_Z] = acc[MC3XX0_AXIS_Z];
+/*
+ raw_data[MC3XX0_AXIS_X] = ((raw_data[MC3XX0_AXIS_X] * GRAVITY_1G_VALUE) / gsensor_gain.x);
+ raw_data[MC3XX0_AXIS_Y] = ((raw_data[MC3XX0_AXIS_Y] * GRAVITY_1G_VALUE) / gsensor_gain.y);
+ raw_data[MC3XX0_AXIS_Z] = ((raw_data[MC3XX0_AXIS_Z] * GRAVITY_1G_VALUE) / gsensor_gain.z);
+*/
+ if (is_new_mc34x0)
+ {
+ raw_data[MC3XX0_AXIS_X] = -raw_data[MC3XX0_AXIS_X];
+ raw_data[MC3XX0_AXIS_Y] = -raw_data[MC3XX0_AXIS_Y];
+ }
+ else if (is_mc3250)
+ {
+ s16 temp = 0;
+
+ temp = raw_data[MC3XX0_AXIS_X];
+
+ raw_data[MC3XX0_AXIS_X] = raw_data[MC3XX0_AXIS_Y];
+ raw_data[MC3XX0_AXIS_Y] = -temp;
+ }
+
+ acc[MC3XX0_AXIS_X] = pCvt->sign[MC3XX0_AXIS_X] * raw_data[pCvt->map[MC3XX0_AXIS_X]];
+ acc[MC3XX0_AXIS_Y] = pCvt->sign[MC3XX0_AXIS_Y] * raw_data[pCvt->map[MC3XX0_AXIS_Y]];
+ acc[MC3XX0_AXIS_Z] = pCvt->sign[MC3XX0_AXIS_Z] * raw_data[pCvt->map[MC3XX0_AXIS_Z]];
+
+ return comres;
+
+}
+
+static int mc32x0_measure(struct i2c_client *client, struct acceleration *accel)
+{
+
+ s16 raw[3];
+
+#ifdef DOT_CALI
+ //int ret;
+#endif
+
+
+#ifdef DOT_CALI
+ if( load_cali_flg > 0)
+ {
+ /*ret =mcube_read_cali_file(client);
+ if(ret == 0)
+ load_cali_flg = ret;
+ else
+ load_cali_flg --;
+ GSE_LOG("load_cali %d\n",ret); */
+ MC32X0_WriteCalibration(client,l_sensorconfig.offset);
+ load_cali_flg = 0;
+ }
+#endif
+ /* read acceleration data */
+ mc32x0_read_accel_xyz(client,&raw[0]);
+
+ accel->x = raw[0] ;
+ accel->y = raw[1] ;
+ accel->z = raw[2] ;
+ return 0;
+}
+
+static void mc32x0_work_func(struct work_struct *work)
+{
+ struct mc32x0_data *data = container_of(work, struct mc32x0_data, work);
+ struct acceleration accel = {0};
+
+ mc32x0_measure(data->client, &accel);
+
+ //printk(KERN_ERR"mc32x0_measure: acc.x=%d, acc.y=%d, acc.z=%d\n", data->inv[0]*accel.x,data->inv[1]*accel.y, data->inv[2]*accel.z);
+
+ //input_report_abs(data->input_dev, data->map[0], data->inv[0]*accel.x);
+ //input_report_abs(data->input_dev, data->map[1], data->inv[1]*accel.y);
+ //input_report_abs(data->input_dev, data->map[2], data->inv[2]*accel.z);
+
+ //accel.x = (accel.x&0x00FF) | ((accel.y&0xFF)<<8) | ((accel.z&0xFF)<<16);
+
+ input_report_abs(data->input_dev, ABS_X, accel.x);
+ input_report_abs(data->input_dev, ABS_Y, accel.y);
+ input_report_abs(data->input_dev, ABS_Z, accel.z);
+ input_sync(data->input_dev);
+
+ queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));
+}
+/*
+static enum hrtimer_restart mc32x0_timer_func(struct hrtimer *timer)
+{
+ struct mc32x0_data *data = container_of(timer, struct mc32x0_data, timer);
+
+ queue_work(data->mc32x0_wq, &data->work);
+ hrtimer_start(&data->timer, ktime_set(0, sensor_duration*1000000), HRTIMER_MODE_REL);
+
+ return HRTIMER_NORESTART;
+}
+*/
+static int mc32x0_enable(struct mc32x0_data *data, int enable)
+{
+ if(enable){
+ msleep(10);
+ mc32x0_chip_init(data->client);
+ queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));//hrtimer_start(&data->timer, ktime_set(0, asensor_duration*1000000), HRTIMER_MODE_REL);
+ data->enabled = true;
+ }else{
+ cancel_delayed_work_sync(&l_sensorconfig.work);//hrtimer_cancel(&data->timer);
+ data->enabled = false;
+ }
+ return 0;
+}
+/*
+//MCUBE_BACKUP_FILE
+static void mcube_copy_file(const char *dstFilePath)
+{
+
+ int err =0;
+ initKernelEnv();
+
+ fd_file = openFile(dstFilePath,O_RDWR,0);
+ if (fd_file == NULL)
+ {
+ GSE_LOG("open %s fail\n",dstFilePath);
+ return;
+ }
+
+ if ((err = writeFile(fd_file,backup_buf,64))>0)
+ GSE_LOG("buf:%s\n",backup_buf);
+ else
+ GSE_LOG("write file error %d\n",err);
+
+ set_fs(oldfs); ;
+ closeFile(fd_file);
+
+}
+//MCUBE_BACKUP_FILE
+*/
+
+extern int wmt_setsyspara(char *varname, char *varval);
+static void update_var(void)
+{
+ char varbuf[64];
+ int varlen;
+
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+
+ sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ l_sensorconfig.op,
+ l_sensorconfig.int_gpio,
+ l_sensorconfig.samp,
+ (pCvt->map[MC3XX0_AXIS_X]),
+ (pCvt->sign[MC3XX0_AXIS_X]),
+ (pCvt->map[MC3XX0_AXIS_Y]),
+ (pCvt->sign[MC3XX0_AXIS_Y]),
+ (pCvt->map[MC3XX0_AXIS_Z]),
+ (pCvt->sign[MC3XX0_AXIS_Z]),
+ l_sensorconfig.offset[0],
+ l_sensorconfig.offset[1],
+ l_sensorconfig.offset[2]
+ );
+
+ wmt_setsyspara("wmt.io.mc3230sensor",varbuf);
+}
+
+static long mc32x0_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ //int intBuf[SENSOR_DATA_SIZE];
+ int ret = 0;
+ //float convert_para=0.0f;
+ short enable = 0;
+ short delay = 0;
+ //short val=1000/l_sensorconfig.sensor_samp;
+ unsigned int uval ;
+#ifdef DOT_CALI
+ void __user *data1;
+ char strbuf[256];
+ //int cali[3];
+ SENSOR_DATA sensor_data;
+ struct i2c_client *client = container_of(mc32x0_device.parent, struct i2c_client, dev);
+ //struct mc32x0_data* this = (struct mc32x0_data *)i2c_get_clientdata(client); /* ?õô????????????. */
+#endif
+
+ switch (cmd) {
+ case ECS_IOCTL_APP_SET_AFLAG:
+ // enable/disable sensor
+
+ if (copy_from_user(&enable, (short*)arg, sizeof(short)))
+ {
+ errlog("Can't get enable flag!!!\n");
+ ret = -EFAULT;
+ goto errioctl;
+ }
+ if ((enable >=0) && (enable <=1))
+ {
+ dbg("driver: disable/enable(%d) gsensor. l_sensorconfig.sensor_samp=%d\n", enable, l_sensorconfig.sensor_samp);
+ + if (enable != l_sensorconfig.sensor_enable)
+ {
+
+ l_sensorconfig.sensor_enable = enable;
+ + }
+ } else {
+ errlog("Wrong enable argument!!!\n");
+ ret = -EFAULT;
+ goto errioctl;
+ }
+ break;
+ case ECS_IOCTL_APP_SET_DELAY://IOCTL_SENSOR_SET_DELAY_ACCEL:
+ /*if(copy_from_user((void *)&sensor_duration, (void __user *) arg, sizeof(short))!=0){
+ printk("copy from error in %s.\n",__func__);
+ }*/
+
+ // set the rate of g-sensor
+ if (copy_from_user(&delay,(short*)arg, sizeof(short)))
+ {
+ errlog("Can't get set delay!!!\n");
+ ret = -EFAULT;
+ goto errioctl;
+ }
+ dbg("Get delay=%d \n", delay);
+
+ if ((delay >=0) && (delay < 20))
+ {
+ delay = 20;
+ } else if (delay > 200)
+ {
+ delay = 200;
+ }
+ if (delay > 0)
+ {
+ l_sensorconfig.sensor_samp = 1000/delay;
+ } else {
+ errlog("error delay argument(delay=%d)!!!\n",delay);
+ ret = -EFAULT;
+ goto errioctl;
+ }
+
+ break;
+/*
+ case IOCTL_SENSOR_GET_DELAY_ACCEL:
+
+ if(copy_to_user((void __user *) arg, (const void *)&val, sizeof(short))!=0){
+ printk("copy to error in %s.\n",__func__);
+ }
+
+ break;*/
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = MC3230_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ dbg("mc32x0_driver_id:%d\n",uval);
+ break;
+ case WMT_IOCTL_SENOR_GET_RESOLUTION:
+ if(McubeID &MCUBE_1_5G_8BIT)
+ uval = (8<<8) | 3; //mc3230:8 bit ,+/-1.5g
+ if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<<resolution:0x%x\n",uval);
+ break;
+ /*case IOCTL_SENSOR_GET_STATE_ACCEL:
+ if(copy_to_user((void __user *) arg, (const void *)&sensor_state_flag, sizeof(short))!=0){
+ printk("copy to error in %s.\n",__func__);
+ }
+
+ break;
+
+ case IOCTL_SENSOR_SET_STATE_ACCEL:
+ if(copy_from_user((void *)&sensor_state_flag, (void __user *) arg, sizeof(short))!=0){
+ printk("copy from error in %s.\n",__func__);
+ }
+
+ break;
+ case IOCTL_SENSOR_GET_NAME:
+ if(copy_to_user((void __user *) arg,(const void *)mc32x0_DISPLAY_NAME, sizeof(mc32x0_DISPLAY_NAME))!=0){
+ printk("copy to error in %s.\n",__func__);
+ }
+ break;
+
+ case IOCTL_SENSOR_GET_VENDOR:
+ if(copy_to_user((void __user *) arg,(const void *)mc32x0_DIPLAY_VENDOR, sizeof(mc32x0_DIPLAY_VENDOR))!=0){
+ printk("copy to error in %s.\n",__func__);
+ }
+ break;
+
+ case IOCTL_SENSOR_GET_CONVERT_PARA:
+ convert_para = mc32x0_CONVERT_PARAMETER;
+ if(copy_to_user((void __user *) arg,(const void *)&convert_para,sizeof(float))!=0){
+ printk("copy to error in %s.\n",__func__);
+ }
+ break;
+ */
+
+ #ifdef DOT_CALI
+ case GSENSOR_IOCTL_READ_SENSORDATA:
+ case GSENSOR_IOCTL_READ_RAW_DATA:
+ GSE_LOG("fwq GSENSOR_IOCTL_READ_RAW_DATA\n");
+ MC32X0_ReadRawData(client,strbuf);
+ if (copy_to_user((void __user *) arg, &strbuf, strlen(strbuf)+1)) {
+ printk("failed to copy sense data to user space.");
+ return -EFAULT;
+ }
+
+
+ break;
+
+
+ case GSENSOR_MCUBE_IOCTL_SET_CALI:
+ GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_CALI!!\n");
+ data1 = (void __user *)arg;
+
+
+ //data = (unsigned char*)arg;
+
+
+ if(data1 == NULL)
+ {
+ ret = -EINVAL;
+ break;
+ }
+ if(copy_from_user(&sensor_data, data1, sizeof(sensor_data)))
+ {
+ ret = -EFAULT;
+ break;
+ }
+ //if(atomic_read(&this->suspend))
+ //{
+ // GSE_ERR("Perform calibration in suspend state!!\n");
+ // err = -EINVAL;
+ //}
+ else
+ {
+ //this->cali_sw[MC32X0_AXIS_X] += sensor_data.x;
+ //this->cali_sw[MC32X0_AXIS_Y] += sensor_data.y;
+ //this->cali_sw[MC32X0_AXIS_Z] += sensor_data.z;
+
+ l_sensorconfig.offset[MC32X0_AXIS_X] = sensor_data.x;
+ l_sensorconfig.offset[MC32X0_AXIS_Y] = sensor_data.y;
+ l_sensorconfig.offset[MC32X0_AXIS_Z] = sensor_data.z;
+
+ GSE_LOG("GSENSOR_MCUBE_IOCTL_SET_CALI %d %d %d %d %d %d!!\n", l_sensorconfig.offset[MC32X0_AXIS_X], l_sensorconfig.offset[MC32X0_AXIS_Y],l_sensorconfig.offset[MC32X0_AXIS_Z] ,sensor_data.x, sensor_data.y ,sensor_data.z);
+
+ update_var();
+ ret = MC32X0_WriteCalibration(client, l_sensorconfig.offset);
+ }
+
+ break;
+
+ case GSENSOR_IOCTL_CLR_CALI:
+ GSE_LOG("fwq GSENSOR_IOCTL_CLR_CALI!!\n");
+ l_sensorconfig.offset[0] = 0;
+ l_sensorconfig.offset[1] = 0; + l_sensorconfig.offset[2] = 0; + + update_var();
+ ret = MC32X0_ResetCalibration(client);
+ break;
+
+ case GSENSOR_IOCTL_GET_CALI:
+ GSE_LOG("fwq mc32x0 GSENSOR_IOCTL_GET_CALI\n");
+
+ data1 = (unsigned char*)arg;
+
+ if(data1 == NULL)
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ if((ret = MC32X0_ReadCalibration(client,l_sensorconfig.offset)))
+ {
+ GSE_LOG("fwq mc32x0 MC32X0_ReadCalibration error!!!!\n");
+ break;
+ }
+
+ sensor_data.x = l_sensorconfig.offset[0];//this->cali_sw[MC32X0_AXIS_X];
+ sensor_data.y = l_sensorconfig.offset[1];//this->cali_sw[MC32X0_AXIS_Y];
+ sensor_data.z = l_sensorconfig.offset[2];//this->cali_sw[MC32X0_AXIS_Z];
+ // if(copy_to_user(data, &sensor_data, sizeof(sensor_data)))
+
+ if(copy_to_user(data1, &sensor_data, sizeof(sensor_data)))
+ {
+ ret = -EFAULT;
+ break;
+ }
+ break;
+ // add by liang ****
+ //add in Sensors_io.h
+ //#define GSENSOR_IOCTL_SET_CALI_MODE _IOW(GSENSOR, 0x0e, int)
+ case GSENSOR_IOCTL_SET_CALI_MODE:
+ GSE_LOG("fwq mc32x0 GSENSOR_IOCTL_SET_CALI_MODE\n");
+ break;
+
+ case GSENSOR_MCUBE_IOCTL_READ_RBM_DATA:
+ GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_READ_RBM_DATA\n");
+ data1 = (void __user *) arg;
+ if(data1 == NULL)
+ {
+ ret = -EINVAL;
+ break;
+ }
+ MC32X0_ReadRBMData(client,(char *)&strbuf);
+ if(copy_to_user(data1, &strbuf, strlen(strbuf)+1))
+ {
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ case GSENSOR_MCUBE_IOCTL_SET_RBM_MODE:
+ GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_RBM_MODE\n");
+ //MCUBE_BACKUP_FILE
+ /*if(READ_FROM_BACKUP==true)
+ {
+
+ mcube_copy_file(CALIB_PATH);
+
+ READ_FROM_BACKUP = false;
+ }*/
+ //MCUBE_BACKUP_FILE
+ MC32X0_rbm(client, 1);
+
+ break;
+
+ case GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE:
+ GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE\n");
+
+ MC32X0_rbm(client, 0);
+
+ break;
+
+ case GSENSOR_MCUBE_IOCTL_REGISTER_MAP:
+ GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_REGISTER_MAP\n");
+
+ //MC32X0_Read_Reg_Map(client);
+
+ break;
+#endif
+
+
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+errioctl:
+
+ return ret;
+}
+
+
+static int mc32x0_open(struct inode *inode, struct file *filp)
+{
+ /*int ret;
+ ret = nonseekable_open(inode, filp);*/
+ return 0;
+}
+
+static int mc32x0_release(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static struct file_operations sensor_fops =
+{
+ .owner = THIS_MODULE,
+ .open = mc32x0_open,
+ .release = mc32x0_release,
+ .unlocked_ioctl = mc32x0_ioctl,
+};
+
+//#ifdef CONFIG_HAS_EARLYSUSPEND
+static int mc32x0_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ /*struct mc32x0_data *data;
+ char mc32x0_address;
+ char mc32x0_data;
+
+ //printk("mc32x0_early_suspend 2 \n");
+
+ data = container_of(handler, struct mc32x0_data, early_suspend);
+
+ hrtimer_cancel(&data->timer);
+ */
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+ mc32x0_set_mode(l_sensorconfig.client,MC32X0_STANDBY);
+ return 0;
+}
+
+static int mc32x0_i2c_resume(struct platform_device *pdev)
+{
+ struct mc32x0_data *data = &l_sensorconfig;
+ //char mc32x0_address;
+ //char mc32x0_data;
+
+ //printk("mc32x0_early_resume 2\n");
+
+ //data = container_of(handler, struct mc32x0_data, early_suspend);
+
+ //Add 20130722
+ mc32x0_chip_init(data->client);
+ MC32X0_ResetCalibration(data->client);
+ MC32X0_WriteCalibration(data->client,l_sensorconfig.offset);//mcube_read_cali_file(data->client);
+ //before
+
+ mc32x0_set_mode(data->client,MC32X0_WAKE);
+
+ queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));
+ //hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ return 0;
+}
+//#endif
+
+static struct miscdevice mc32x0_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sensor_ctrl",
+ .fops = &sensor_fops,
+};
+
+static int sensor_writeproc( struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data )
+{
+
+ //int inputval = -1;
+ int enable, sample = -1;
+ char tembuf[8];
+ //unsigned int amsr = 0;
+ int test = 0;
+
+ mutex_lock(&l_sensorconfig.lock);
+ memset(tembuf, 0, sizeof(tembuf));
+ // get sensor level and set sensor level
+ if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg))
+ {
+ // only set the dbg flag
+ } else if (sscanf(buffer, "samp=%d\n", &sample))
+ {
+ if (sample > 0)
+ {
+ if (sample != l_sensorconfig.sensor_samp)
+ {
+ // should do sth
+ }
+ //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr);
+ } else {
+ klog("Wrong sample argumnet of sensor.\n");
+ }
+ } else if (sscanf(buffer, "enable=%d\n", &enable))
+ {
+ if ((enable < 0) || (enable > 1))
+ {
+ dbg("The argument to enable/disable g-sensor should be 0 or 1 !!!\n");
+ } else if (enable != l_sensorconfig.sensor_enable)
+ {
+ //mma_enable_disable(enable);
+ l_sensorconfig.sensor_enable = enable;
+ }
+ } else if (sscanf(buffer, "sensor_test=%d\n", &test))
+ { // for test begin
+ l_sensorconfig.test_pass = 0;
+ } else if (sscanf(buffer, "sensor_testend=%d\n", &test))
+ { // Don nothing only to be compatible the before testing program
+ }
+ mutex_unlock(&l_sensorconfig.lock);
+ return count;
+}
+
+static int sensor_readproc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len = sprintf(page,
+ "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n",
+ l_sensorconfig.test_pass,
+ l_sensorconfig.isdbg,
+ l_sensorconfig.sensor_samp,
+ l_sensorconfig.sensor_enable
+ );
+ return len;
+}
+
+static int mc32x0_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mc32x0_data *data = &l_sensorconfig;
+ struct i2c_client *client = data->client;
+
+#ifdef DOT_CALI
+ load_cali_flg = 30;
+#endif
+ data->sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/);
+ if (data->sensor_proc != NULL)
+ { + data->sensor_proc->write_proc = sensor_writeproc;
+ data->sensor_proc->read_proc = sensor_readproc;
+ }
+
+ data->mc32x0_wq = create_singlethread_workqueue("mc32x0_wq");
+ if (!data->mc32x0_wq )
+ {
+ ret = -ENOMEM;
+ goto err_create_workqueue_failed;
+ }
+
+ INIT_DELAYED_WORK(&data->work, mc32x0_work_func);
+ //INIT_WORK(&data->work, mc32x0_work_func);
+ mutex_init(&data->lock);
+
+
+ data->input_dev = input_allocate_device();
+ if (!data->input_dev) {
+ ret = -ENOMEM;
+ goto exit_input_dev_alloc_failed;
+ }
+
+
+ dev.client=client;
+
+ i2c_set_clientdata(client, data);
+ #ifdef DOT_CALI
+ mc32x0_reset(client);
+ #endif
+
+ set_bit(EV_ABS, data->input_dev->evbit);
+ data->map[0] = G_0;
+ data->map[1] = G_1;
+ data->map[2] = G_2;
+ data->inv[0] = G_0_REVERSE;
+ data->inv[1] = G_1_REVERSE;
+ data->inv[2] = G_2_REVERSE;
+
+ input_set_abs_params(data->input_dev, ABS_X, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(data->input_dev, ABS_Y, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT);
+ input_set_abs_params(data->input_dev, ABS_Z, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT);
+
+ data->input_dev->name = "g-sensor";
+
+
+ ret = input_register_device(data->input_dev);
+ if (ret) {
+ goto exit_input_register_device_failed;
+ }
+ mc32x0_device.parent = &client->dev;
+ ret = misc_register(&mc32x0_device);
+ if (ret) {
+ goto exit_misc_device_register_failed;
+ }
+
+ ret = sysfs_create_group(&client->dev.kobj, &mc32x0_group);
+/*
+ if (!data->use_irq){
+ hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ data->timer.function = mc32x0_timer_func;
+ hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ }
+*/
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ data->early_suspend.suspend = mc32x0_early_suspend;
+ data->early_suspend.resume = mc32x0_early_resume;
+ register_early_suspend(&data->early_suspend);
+#endif
+ data->enabled = true;
+ queue_delayed_work(data->mc32x0_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));
+ strcpy(mc32x0_on_off_str,"gsensor_int2");
+ dprintk(DEBUG_INIT,"mc32x0 probe ok \n");
+
+ return 0;
+exit_misc_device_register_failed:
+exit_input_register_device_failed:
+ input_free_device(data->input_dev);
+exit_input_dev_alloc_failed:
+ destroy_workqueue(data->mc32x0_wq);
+err_create_workqueue_failed:
+ kfree(data);
+ printk("mc32x0 probe failed \n");
+ return ret;
+
+}
+
+static int mc32x0_remove(struct platform_device *pdev)
+{
+ /*struct mc32x0_data *data = i2c_get_clientdata(client);
+
+ hrtimer_cancel(&data->timer);
+ input_unregister_device(data->input_dev);
+ //gpio_release(mc32x0_pin_hd, 2);
+ misc_deregister(&mc32x0_device);
+ sysfs_remove_group(&client->dev.kobj, &mc32x0_group);
+ kfree(data);*/
+
+ if (NULL != l_sensorconfig.mc32x0_wq)
+ { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.mc32x0_wq);
+ destroy_workqueue(l_sensorconfig.mc32x0_wq);
+ l_sensorconfig.mc32x0_wq = NULL;
+ } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&mc32x0_device);
+ input_unregister_device(l_sensorconfig.input_dev);
+ sysfs_remove_group(&l_sensorconfig.client->dev.kobj, &mc32x0_group);
+ return 0;
+}
+
+static void mc32x0_shutdown(struct platform_device *pdev)
+{
+ struct mc32x0_data *data = &l_sensorconfig;//i2c_get_clientdata(client);
+ if(data->enabled)
+ mc32x0_enable(data,0);
+}
+/*
+static const struct i2c_device_id mc32x0_id[] = {
+ { SENSOR_NAME, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, mc32x0_id);
+
+static struct i2c_driver mc32x0_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = SENSOR_NAME,
+ },
+ .id_table = mc32x0_id,
+ .probe = mc32x0_probe,
+ .remove = mc32x0_remove,
+ .shutdown = mc32x0_shutdown,
+ .detect = gsensor_detect,
+ .address_list = normal_i2c,
+};
+*/
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static int get_axisset(void)
+{
+ char varbuf[64];
+ int n;
+ int varlen;
+ //int tmpoff[3] = {0};
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+
+ pCvt = (struct mc3xx0_hwmsen_convert *)kzalloc(sizeof(struct mc3xx0_hwmsen_convert), GFP_KERNEL);
+
+ if (wmt_getsyspara("wmt.io.mc3230.virtualz", varbuf, &varlen)) {
+ errlog("Can't get gsensor config in u-boot!!!!\n");
+ //return -1;
+ } else {
+ sscanf(varbuf, "%d", &g_virtual_z);
+
+ }
+ printk("%s g_virtual_z %d\n", __FUNCTION__, g_virtual_z);
+ memset(varbuf, 0, sizeof(varbuf));
+ if (wmt_getsyspara("wmt.io.mc3230sensor", varbuf, &varlen)) {
+ errlog("Can't get gsensor config in u-boot!!!!\n");
+ return -1; //open it for no env just,not insmod such module 2014-6-30
+ } else {
+ n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &l_sensorconfig.op,
+ &l_sensorconfig.int_gpio,
+ &l_sensorconfig.samp,
+ &(pCvt->map[MC3XX0_AXIS_X]),
+ &(pCvt->sign[MC3XX0_AXIS_X]),
+ &(pCvt->map[MC3XX0_AXIS_Y]),
+ &(pCvt->sign[MC3XX0_AXIS_Y]),
+ &(pCvt->map[MC3XX0_AXIS_Z]),
+ &(pCvt->sign[MC3XX0_AXIS_Z]),
+ &(l_sensorconfig.offset[0]),
+ &(l_sensorconfig.offset[1]),
+ &(l_sensorconfig.offset[2])
+ );
+ if (n != 12) {
+ printk(KERN_ERR "gsensor format is error in u-boot!!!\n");
+ return -1;
+ }
+ l_sensorconfig.sensor_samp = l_sensorconfig.samp;
+
+
+ dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ l_sensorconfig.op,
+ l_sensorconfig.int_gpio,
+ l_sensorconfig.samp,
+ pCvt->map[MC3XX0_AXIS_X],
+ pCvt->sign[MC3XX0_AXIS_X],
+ pCvt->map[MC3XX0_AXIS_Y],
+ pCvt->sign[MC3XX0_AXIS_Y],
+ pCvt->map[MC3XX0_AXIS_Z],
+ pCvt->sign[MC3XX0_AXIS_Z],
+ l_sensorconfig.offset[0],
+ l_sensorconfig.offset[1],
+ l_sensorconfig.offset[2]
+ );
+ }
+ return 0;
+}
+
+static void mc32x0_platform_release(struct device *device)
+{
+ return;
+}
+
+static struct platform_device mc32x0_pdevice = {
+ .name = GSENSOR_NAME,
+ .id = 0,
+ .dev = {
+ .release = mc32x0_platform_release,
+ },
+};
+
+static struct platform_driver mc32x0_pdriver = {
+ .probe = mc32x0_probe,
+ .remove = mc32x0_remove,
+ .suspend = mc32x0_i2c_suspend,
+ .resume = mc32x0_i2c_resume,
+ .shutdown = mc32x0_shutdown,
+ .driver = {
+ .name = GSENSOR_NAME,
+ },
+};
+
+
+static int __init mc32x0_init(void)
+{
+ struct i2c_client *this_client;
+ int ret = 0;
+
+ dprintk(DEBUG_INIT, "======%s=========. \n", __func__);
+ // parse g-sensor u-boot arg + ret = get_axisset();
+ if (ret < 0)
+ {
+ printk("<<<<<%s user choose to no sensor chip!\n", __func__);
+ return ret;
+ }
+ if (!(this_client = sensor_i2c_register_device(0, MC32X0_I2C_ADDR, GSENSOR_NAME)))
+ { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (mc32x0_chip_init(this_client))
+ { + printk(KERN_ERR"Failed to init MC32X0!\n");
+ sensor_i2c_unregister_device(this_client); + return -1; + }
+
+ //printk(KERN_ERR"McubeID:%d\n",McubeID);
+ l_sensorconfig.client = this_client;
+
+ l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME);
+ if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&mc32x0_pdevice)))
+ { + klog("Can't register mc3230 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&mc32x0_pdriver)) != 0)
+ { + errlog("Can't register mc3230 platform driver!!!\n"); + return ret; + }
+ return ret;
+}
+
+static void __exit mc32x0_exit(void)
+{
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ unregister_early_suspend(&l_sensorconfig.earlysuspend); +#endif + platform_driver_unregister(&mc32x0_pdriver);
+ platform_device_unregister(&mc32x0_pdevice);
+ sensor_i2c_unregister_device(l_sensorconfig.client);
+ class_destroy(l_dev_class);
+}
+
+//*********************************************************************************************************
+MODULE_AUTHOR("Long Chen <lchen@mcube-inc.com>");
+MODULE_DESCRIPTION("mc32x0 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.1");
+
+module_init(mc32x0_init);
+module_exit(mc32x0_exit);
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c new file mode 100755 index 00000000..19c81b97 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.c @@ -0,0 +1,505 @@ +/*
+ * Copyright (C) 2011 MCUBE, Inc.
+ *
+ * Initial Code:
+ * Tan Liang
+ */
+
+
+
+
+
+#include <linux/delay.h> +
+#include "mc32x0_driver.h"
+
+
+mc32x0_t *p_mc32x0; /**< pointer to MC32X0 device structure */
+
+
+/** API Initialization routine
+ \param *mc32x0 pointer to MC32X0 structured type
+ \return result of communication routines
+ */
+
+int mcube_mc32x0_init(mc32x0_t *mc32x0)
+{
+ int comres=0;
+ unsigned char data;
+
+ p_mc32x0 = mc32x0; /* assign mc32x0 ptr */
+ p_mc32x0->dev_addr = MC32X0_I2C_ADDR; /* preset I2C_addr */
+ comres += p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_CHIP_ID, &data, 1); /* read Chip Id */
+
+ p_mc32x0->chip_id = data;
+
+ // init other reg
+ data = 0x63;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &data, 1);
+ data = 0x43;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1b, &data, 1);
+ msleep(5);
+
+ data = 0x43;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x07, &data, 1);
+ data = 0x80;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1c, &data, 1);
+ data = 0x80;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &data, 1);
+ msleep(5);
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x1c, &data, 1);
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, 0x17, &data, 1);
+
+ return comres;
+}
+
+int mc32x0_set_image (void)
+{
+ int comres;
+ unsigned char data;
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+#ifdef MCUBE_2G_10BIT_TAP
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x80;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x05;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Dwell_Reject_REG, &data, 1 );
+
+ data = 0x33;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x07;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Threshold_REG, &data, 1 );
+
+ data = 0x04;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+#endif
+
+#ifdef MCUBE_2G_10BIT
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x33;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+#endif
+
+#ifdef MCUBE_8G_14BIT_TAP
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x80;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x05;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Dwell_Reject_REG, &data, 1 );
+
+ data = 0x3F;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x07;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Threshold_REG, &data, 1 );
+
+ data = 0x04;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+#endif
+
+#ifdef MCUBE_8G_14BIT
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x3F;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+#endif
+
+
+
+#ifdef MCUBE_1_5G_8BIT
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x02;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+#endif
+
+
+#ifdef MCUBE_1_5G_8BIT_TAP
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x80;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x02;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x03;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Dwell_Reject_REG, &data, 1 );
+
+ data = 0x07;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_TAP_Threshold_REG, &data, 1 );
+
+ data = 0x04;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+#endif
+
+
+#ifdef MCUBE_1_5G_6BIT
+
+ data = MC32X0_MODE_DEF;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Mode_Feature_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sleep_Count_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Sample_Rate_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE_Control_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Tap_Detection_Enable_REG, &data, 1 );
+
+ data = 0x00;
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_Interrupt_Enable_REG, &data, 1 );
+
+
+#endif
+
+
+
+ return comres;
+}
+
+
+int mc32x0_get_offset(unsigned char *offset)
+{
+ return 0;
+}
+
+
+int mc32x0_set_offset(unsigned char offset)
+{
+ return 0;
+}
+
+
+
+
+/** set mc32x0s range
+ \param range
+
+ \see MC32X0_RANGE_2G
+ \see MC32X0_RANGE_4G
+ \see MC32X0_RANGE_8G
+*/
+int mc32x0_set_range(char range)
+{
+ int comres = 0;
+ unsigned char data;
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ if (range<3) {
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE__REG, &data, 1);
+ data = MC32X0_SET_BITSLICE(data, MC32X0_RANGE, range);
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE__REG, &data, 1);
+
+ }
+ return comres;
+
+}
+
+
+/* readout select range from MC32X0
+ \param *range pointer to range setting
+ \return result of bus communication function
+ \see MC32X0_RANGE_2G, MC32X0_RANGE_4G, MC32X0_RANGE_8G
+ \see mc32x0_set_range()
+*/
+int mc32x0_get_range(unsigned char *range)
+{
+
+ int comres = 0;
+ unsigned char data;
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_RANGE__REG, &data, 1);
+ data = MC32X0_GET_BITSLICE(data, MC32X0_RANGE);
+
+ *range = data;
+
+
+ return comres;
+
+}
+
+
+
+int mc32x0_set_mode(unsigned char mode) {
+
+ int comres=0;
+ unsigned char data;
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ if (mode<4) {
+ data = MC32X0_MODE_DEF;
+ data = MC32X0_SET_BITSLICE(data, MC32X0_MODE, mode);
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_MODE__REG, &data, 1 );
+
+ p_mc32x0->mode = mode;
+ }
+ return comres;
+
+}
+
+
+
+int mc32x0_get_mode(unsigned char *mode)
+{
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+ *mode = p_mc32x0->mode;
+ return 0;
+}
+
+
+int mc32x0_set_bandwidth(char bw)
+{
+ int comres = 0;
+ unsigned char data;
+
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ if (bw<7) {
+
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_BANDWIDTH__REG, &data, 1 );
+ data = MC32X0_SET_BITSLICE(data, MC32X0_BANDWIDTH, bw);
+ comres += p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, MC32X0_BANDWIDTH__REG, &data, 1 );
+
+ }
+
+ return comres;
+
+
+}
+
+int mc32x0_get_bandwidth(unsigned char *bw) {
+ int comres = 1;
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_BANDWIDTH__REG, bw, 1 );
+
+ *bw = MC32X0_GET_BITSLICE(*bw, MC32X0_BANDWIDTH);
+
+ return comres;
+
+}
+
+
+int mc32x0_read_accel_x(short *a_x)
+{
+ int comres;
+ unsigned char data[2];
+
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &data[0],2);
+
+ *a_x = ((short)data[0])|(((short)data[1])<<8);
+
+ return comres;
+
+}
+
+
+
+int mc32x0_read_accel_y(short *a_y)
+{
+ int comres;
+ unsigned char data[2];
+
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_YOUT_EX_L_REG, &data[0],2);
+
+ *a_y = ((short)data[0])|(((short)data[1])<<8);
+
+ return comres;
+}
+
+
+int mc32x0_read_accel_z(short *a_z)
+{
+ int comres;
+ unsigned char data[2];
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_ZOUT_EX_L_REG, &data[0],2);
+
+ *a_z = ((short)data[0])|(((short)data[1])<<8);
+
+ return comres;
+}
+
+
+int mc32x0_read_accel_xyz(mc32x0acc_t * acc)
+{
+ int comres;
+ unsigned char data[6];
+
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+#ifdef MC32X0_HIGH_END
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_EX_L_REG, &data[0],6);
+
+ acc->x = ((signed short)data[0])|(((signed short)data[1])<<8);
+ acc->y = ((signed short)data[2])|(((signed short)data[3])<<8);
+ acc->z = ((signed short)data[4])|(((signed short)data[5])<<8);
+#endif
+
+#ifdef MC32X0_LOW_END
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_XOUT_REG, &data[0],3);
+
+#ifndef MCUBE_1_5G_6BIT
+ acc->x = (signed char)data[0];
+ acc->y = (signed char)data[1];
+ acc->z = (signed char)data[2];
+#else
+ acc->x = (signed short)GET_REAL_VALUE(data[0],6);
+ acc->y = (signed short)GET_REAL_VALUE(data[1],6);
+ acc->z = (signed short)GET_REAL_VALUE(data[2],6);
+#endif
+
+#endif
+
+
+
+
+ return comres;
+
+}
+
+
+
+int mc32x0_get_interrupt_status(unsigned char * ist)
+{
+
+ int comres=0;
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, MC32X0_Tilt_Status_REG, ist, 1);
+ return comres;
+}
+
+
+
+int mc32x0_read_reg(unsigned char addr, unsigned char *data, unsigned char len)
+{
+
+ int comres;
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ comres = p_mc32x0->MC32X0_BUS_READ_FUNC(p_mc32x0->dev_addr, addr, data, len);
+ return comres;
+
+}
+
+
+int mc32x0_write_reg(unsigned char addr, unsigned char *data, unsigned char len)
+{
+
+ int comres;
+
+ if (p_mc32x0==0)
+ return E_NULL_PTR;
+
+ comres = p_mc32x0->MC32X0_BUS_WRITE_FUNC(p_mc32x0->dev_addr, addr, data, len);
+
+ return comres;
+
+}
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h new file mode 100755 index 00000000..0aca80e8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3230_gsensor/mc32x0_driver.h @@ -0,0 +1,219 @@ +/*
+ * Copyright (C) 2011 MCUBE, Inc.
+ *
+ * Initial Code:
+ * Tan Liang
+ */
+
+
+
+#ifndef __MC32X0_H__
+#define __MC32X0_H__
+
+
+
+#define MC32X0_WR_FUNC_PTR char (* bus_write)(unsigned char, unsigned char *, unsigned char)
+
+#define MC32X0_BUS_WRITE_FUNC(dev_addr, reg_addr, reg_data, wr_len)\
+ bus_write(reg_addr, reg_data, wr_len)
+
+#define MC32X0_RD_FUNC_PTR char (* bus_read)( unsigned char, unsigned char *, unsigned char)
+
+#define MC32X0_BUS_READ_FUNC(dev_addr, reg_addr, reg_data, r_len)\
+ bus_read(reg_addr, reg_data, r_len)
+
+#define GET_REAL_VALUE(rv, bn) \
+ ((rv & (0x01 << (bn - 1))) ? (- (rv & ~(0xffff << (bn - 1)))) : (rv & ~(0xffff << (bn - 1))))
+
+
+
+//#define MC32X0_HIGH_END
+/*******MC3210/20 define this**********/
+
+//#define MCUBE_2G_10BIT_TAP
+//#define MCUBE_2G_10BIT
+//#define MCUBE_8G_14BIT_TAP
+//#define MCUBE_8G_14BIT
+
+
+
+//#define MC32X0_LOW_END
+/*******MC3230 define this**********/
+
+//#define MCUBE_1_5G_8BIT
+//#define MCUBE_1_5G_8BIT_TAP
+
+
+
+
+
+/** MC32X0 I2C Address
+*/
+
+#define MC32X0_I2C_ADDR 0x4c // 0x98 >> 1
+
+
+
+/*
+ MC32X0 API error codes
+*/
+
+#define E_NULL_PTR (char)-127
+
+/*
+ *
+ * register definitions
+ *
+ */
+
+#define MC32X0_XOUT_REG 0x00
+#define MC32X0_YOUT_REG 0x01
+#define MC32X0_ZOUT_REG 0x02
+#define MC32X0_Tilt_Status_REG 0x03
+#define MC32X0_Sampling_Rate_Status_REG 0x04
+#define MC32X0_Sleep_Count_REG 0x05
+#define MC32X0_Interrupt_Enable_REG 0x06
+#define MC32X0_Mode_Feature_REG 0x07
+#define MC32X0_Sample_Rate_REG 0x08
+#define MC32X0_Tap_Detection_Enable_REG 0x09
+#define MC32X0_TAP_Dwell_Reject_REG 0x0a
+#define MC32X0_DROP_Control_Register_REG 0x0b
+#define MC32X0_SHAKE_Debounce_REG 0x0c
+#define MC32X0_XOUT_EX_L_REG 0x0d
+#define MC32X0_XOUT_EX_H_REG 0x0e
+#define MC32X0_YOUT_EX_L_REG 0x0f
+#define MC32X0_YOUT_EX_H_REG 0x10
+#define MC32X0_ZOUT_EX_L_REG 0x11
+#define MC32X0_ZOUT_EX_H_REG 0x12
+#define MC32X0_CHIP_ID 0x18
+#define MC32X0_RANGE_Control_REG 0x20
+#define MC32X0_SHAKE_Threshold_REG 0x2B
+#define MC32X0_UD_Z_TH_REG 0x2C
+#define MC32X0_UD_X_TH_REG 0x2D
+#define MC32X0_RL_Z_TH_REG 0x2E
+#define MC32X0_RL_Y_TH_REG 0x2F
+#define MC32X0_FB_Z_TH_REG 0x30
+#define MC32X0_DROP_Threshold_REG 0x31
+#define MC32X0_TAP_Threshold_REG 0x32
+
+
+
+
+/** MC32X0 acceleration data
+ \brief Structure containing acceleration values for x,y and z-axis in signed short
+
+*/
+
+typedef struct {
+ short x, /**< holds x-axis acceleration data sign extended. Range -512 to 511. */
+ y, /**< holds y-axis acceleration data sign extended. Range -512 to 511. */
+ z; /**< holds z-axis acceleration data sign extended. Range -512 to 511. */
+} mc32x0acc_t;
+
+/* RANGE */
+
+#define MC32X0_RANGE__POS 2
+#define MC32X0_RANGE__LEN 2
+#define MC32X0_RANGE__MSK 0x0c
+#define MC32X0_RANGE__REG MC32X0_RANGE_Control_REG
+
+/* MODE */
+
+#define MC32X0_MODE__POS 0
+#define MC32X0_MODE__LEN 2
+#define MC32X0_MODE__MSK 0x03
+#define MC32X0_MODE__REG MC32X0_Mode_Feature_REG
+
+#define MC32X0_MODE_DEF 0x43
+
+
+/* BANDWIDTH */
+
+#define MC32X0_BANDWIDTH__POS 4
+#define MC32X0_BANDWIDTH__LEN 3
+#define MC32X0_BANDWIDTH__MSK 0x70
+#define MC32X0_BANDWIDTH__REG MC32X0_RANGE_Control_REG
+
+
+#define MC32X0_GET_BITSLICE(regvar, bitname)\
+ (regvar & bitname##__MSK) >> bitname##__POS
+
+
+#define MC32X0_SET_BITSLICE(regvar, bitname, val)\
+ (regvar & ~bitname##__MSK) | ((val<<bitname##__POS)&bitname##__MSK)
+
+
+
+
+
+
+#define MC32X0_RANGE_2G 0
+#define MC32X0_RANGE_4G 1
+#define MC32X0_RANGE_8G 2
+
+
+#define MC32X0_WAKE 1
+#define MC32X0_SNIFF 2
+#define MC32X0_STANDBY 3
+
+
+#define MC32X0_LOW_PASS_512HZ 0
+#define MC32X0_LOW_PASS_256HZ 1
+#define MC32X0_LOW_PASS_128HZ 2
+#define MC32X0_LOW_PASS_64HZ 3
+#define MC32X0_LOW_PASS_32HZ 4
+#define MC32X0_LOW_PASS_16HZ 5
+#define MC32X0_LOW_PASS_8HZ 6
+
+
+
+
+
+typedef struct {
+ unsigned char mode; /**< save current MC32X0 operation mode */
+ unsigned char chip_id; /**< save MC32X0's chip id which has to be 0x00/0x01 after calling mc32x0_init() */
+ unsigned char dev_addr; /**< initializes MC32X0's I2C device address 0x4c */
+ MC32X0_WR_FUNC_PTR; /**< function pointer to the SPI/I2C write function */
+ MC32X0_RD_FUNC_PTR; /**< function pointer to the SPI/I2C read function */
+} mc32x0_t;
+
+
+
+/* Function prototypes */
+
+
+
+
+int mcube_mc32x0_init(mc32x0_t *mc32x0);
+
+int mc32x0_set_image (struct i2c_client *client) ;
+
+int mc32x0_set_range(char);
+
+int mc32x0_get_range(unsigned char*);
+
+int mc32x0_set_mode(struct i2c_client *client, unsigned char mode);
+
+int mc32x0_get_mode(unsigned char *);
+
+int mc32x0_set_bandwidth(char);
+
+int mc32x0_get_bandwidth(unsigned char *);
+
+int mc32x0_read_accel_x(short *);
+
+int mc32x0_read_accel_y(short *);
+
+int mc32x0_read_accel_z(short *);
+
+int mc32x0_read_accel_xyz(struct i2c_client *client, s16 * acc);
+
+int mc32x0_get_interrupt_status(unsigned char *);
+
+int mc32x0_read_reg(unsigned char , unsigned char *, unsigned char);
+
+int mc32x0_write_reg(unsigned char , unsigned char*, unsigned char );
+
+
+#endif
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/Makefile new file mode 100644 index 00000000..de65868d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_mc3xxx
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := mc3xxx.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/mc3xxx.c b/ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/mc3xxx.c new file mode 100644 index 00000000..c7d37a7a --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mc3xxx_gsensor/mc3xxx.c @@ -0,0 +1,2719 @@ +/***************************************************************************** + * + * Copyright (c) 2013 mCube, Inc. All rights reserved. + * + * This source is subject to the mCube Software License. + * This software is protected by Copyright and the information and source code + * contained herein is confidential. The software including the source code + * may not be copied and the information contained herein may not be used or + * disclosed except with the written permission of mCube Inc. + * + * All other rights reserved. + * + * This code and information are provided "as is" without warranty of any + * kind, either expressed or implied, including but not limited to the + * implied warranties of merchantability and/or fitness for a + * particular purpose. + * + * The following software/firmware and/or related documentation ("mCube Software") + * have been modified by mCube Inc. All revisions are subject to any receiver's + * applicable license agreements with mCube Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + * + *****************************************************************************/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/mutex.h> +//#include <linux/earlysuspend.h> +#include <linux/delay.h> +#include <asm/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/platform_device.h> + + +#include <mach/hardware.h> +#include <linux/fs.h> + +#include "../sensor.h" + + +//#include <mach/sys_config.h> + +//=== CONFIGURATIONS ========================================================== +//#define _MC3XXX_DEBUG_ON_ + +//============================================================================= +#ifdef _MC3XXX_DEBUG_ON_ + #define mcprintkreg(x...) printk(x) + #define mcprintkfunc(x...) printk(x) + #define GSE_ERR(x...) printk(x) + #define GSE_LOG(x...) printk(x) +#else + #define mcprintkreg(x...) + #define mcprintkfunc(x...) + #define GSE_ERR(x...) + #define GSE_LOG(x...) +#endif + +static int g_virtual_z = 0; +#define G_2_REVERSE_VIRTUAL_Z 0 //!!!!! 1 +#define SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 +#define LOW_RESOLUTION 1 +#define HIGH_RESOLUTION 2 +#define RBM_RESOLUTION 3 +#ifdef SUPPORT_VIRTUAL_Z_SENSOR +#define Low_Pos_Max 127 +#define Low_Neg_Max -128 +#define High_Pos_Max 8191 +#define High_Neg_Max -8192 +#define VIRTUAL_Z 1 +static int Railed = 0; +#else +#define VIRTUAL_Z 0 +#endif + + +static struct class* l_dev_class = NULL; + + +#define SENSOR_NAME "mc3xxx" +#define SENSOR_DRIVER_VERSION "1.0.0" +#define SENSOR_DATA_SIZE 3 + +//static int mc3xxx_pin_hd; +//static char mc3xxx_on_off_str[32]; +#define G_0 ABS_Y +#define G_1 ABS_X +#define G_2 ABS_Z +#define G_0_REVERSE 1 +#define G_1_REVERSE 1 +#define G_2_REVERSE 1 + +//static unsigned char s_bResolution = 0x00; +static unsigned char s_bPCODE = 0x00; +static unsigned short mc3xxx_i2c_auto_probe_addr[] = { 0x4C, 0x6C, 0x4E, 0x6D, 0x6E, 0x6F }; + +//============================================================================= +#define SENSOR_DMARD_IOCTL_BASE 234 +#define IOCTL_SENSOR_SET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 100) +#define IOCTL_SENSOR_GET_DELAY_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 101) +#define IOCTL_SENSOR_GET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 102) +#define IOCTL_SENSOR_SET_STATE_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 103) +#define IOCTL_SENSOR_GET_DATA_ACCEL _IO(SENSOR_DMARD_IOCTL_BASE, 104) + +#define IOCTL_MSENSOR_SET_DELAY_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 200) +#define IOCTL_MSENSOR_GET_DATA_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 201) +#define IOCTL_MSENSOR_GET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 202) +#define IOCTL_MSENSOR_SET_STATE_MAGNE _IO(SENSOR_DMARD_IOCTL_BASE, 203) + +#define IOCTL_SENSOR_GET_NAME _IO(SENSOR_DMARD_IOCTL_BASE, 301) +#define IOCTL_SENSOR_GET_VENDOR _IO(SENSOR_DMARD_IOCTL_BASE, 302) +#define IOCTL_SENSOR_GET_CONVERT_PARA _IO(SENSOR_DMARD_IOCTL_BASE, 401) +//#define SENSOR_CALIBRATION _IOWR(SENSOR_DMARD_IOCTL_BASE, 402, int[SENSOR_DATA_SIZE]) + +//============================================================================= +#define MC3XXX_CONVERT_PARAMETER (1.5f * (9.80665f) / 256.0f) +#define MC3XXX_DISPLAY_NAME SENSOR_NAME +#define MC3XXX_DIPLAY_VENDOR "mCube" + +//============================================================================= +#define MC3XXX_AXIS_X 0 +#define MC3XXX_AXIS_Y 1 +#define MC3XXX_AXIS_Z 2 +#define MC3XXX_AXIS_NUM 3 +#define MC3XXX_DATA_LEN 6 + + +/*********************************************** + *** REGISTER MAP + ***********************************************/ +#define MC3XXX_REG_XOUT 0x00 +#define MC3XXX_REG_YOUT 0x01 +#define MC3XXX_REG_ZOUT 0x02 +#define MC3XXX_REG_TILT_STATUS 0x03 +#define MC3XXX_REG_SAMPLE_RATE_STATUS 0x04 +#define MC3XXX_REG_SLEEP_COUNT 0x05 +#define MC3XXX_REG_INTERRUPT_ENABLE 0x06 +#define MC3XXX_REG_MODE_FEATURE 0x07 +#define MC3XXX_REG_SAMPLE_RATE 0x08 +#define MC3XXX_REG_TAP_DETECTION_ENABLE 0x09 +#define MC3XXX_REG_TAP_DWELL_REJECT 0x0A +#define MC3XXX_REG_DROP_CONTROL 0x0B +#define MC3XXX_REG_SHAKE_DEBOUNCE 0x0C +#define MC3XXX_REG_XOUT_EX_L 0x0D +#define MC3XXX_REG_XOUT_EX_H 0x0E +#define MC3XXX_REG_YOUT_EX_L 0x0F +#define MC3XXX_REG_YOUT_EX_H 0x10 +#define MC3XXX_REG_ZOUT_EX_L 0x11 +#define MC3XXX_REG_ZOUT_EX_H 0x12 +#define MC3XXX_REG_RANGE_CONTROL 0x20 +#define MC3XXX_REG_SHAKE_THRESHOLD 0x2B +#define MC3XXX_REG_UD_Z_TH 0x2C +#define MC3XXX_REG_UD_X_TH 0x2D +#define MC3XXX_REG_RL_Z_TH 0x2E +#define MC3XXX_REG_RL_Y_TH 0x2F +#define MC3XXX_REG_FB_Z_TH 0x30 +#define MC3XXX_REG_DROP_THRESHOLD 0x31 +#define MC3XXX_REG_TAP_THRESHOLD 0x32 +#define MC3XXX_REG_PRODUCT_CODE 0x3B + +/*********************************************** + *** RETURN CODE + ***********************************************/ +#define MC3XXX_RETCODE_SUCCESS (0) +#define MC3XXX_RETCODE_ERROR_I2C (-1) +#define MC3XXX_RETCODE_ERROR_NULL_POINTER (-2) +#define MC3XXX_RETCODE_ERROR_STATUS (-3) +#define MC3XXX_RETCODE_ERROR_SETUP (-4) +#define MC3XXX_RETCODE_ERROR_GET_DATA (-5) +#define MC3XXX_RETCODE_ERROR_IDENTIFICATION (-6) + + +/*********************************************** + *** CONFIGURATION + ***********************************************/ +#define MC3XXX_BUF_SIZE 256 + +#define MCUBE_1_5G_8BIT 0x01 //MC3XXX_LOW_END +#define MCUBE_8G_14BIT 0x02 //MC3XXX_HIGH_END + +#define DOT_CALI + + +#define SENSOR_DURATION_DEFAULT 20 + +#define INPUT_FUZZ 0 +#define INPUT_FLAT 0 + +/*********************************************** + *** PRODUCT ID + ***********************************************/ +#define MC3XXX_PCODE_3210 0x90 +#define MC3XXX_PCODE_3230 0x19 +#define MC3XXX_PCODE_3250 0x88 +#define MC3XXX_PCODE_3410 0xA8 +#define MC3XXX_PCODE_3410N 0xB8 +#define MC3XXX_PCODE_3430 0x29 +#define MC3XXX_PCODE_3430N 0x39 +#define MC3XXX_PCODE_3510B 0x40 +#define MC3XXX_PCODE_3530B 0x30 +#define MC3XXX_PCODE_3510C 0x10 +#define MC3XXX_PCODE_3530C 0x6E + +//============================================================================= +static unsigned char is_new_mc34x0 = 0; +static unsigned char is_mc3250 = 0; +static unsigned char is_mc35xx = 0; +static unsigned char Sensor_Accuracy = 0; + + +//============================================================================= +#ifdef DOT_CALI +#define CALIB_PATH "/data/data/com.mcube.acc/files/mcube-calib.txt" +//MCUBE_BACKUP_FILE +#define BACKUP_CALIB_PATH "/data/misc/mcube-calib.txt" +static char backup_buf[64]; +//MCUBE_BACKUP_FILE +#define DATA_PATH "/sdcard/mcube-register-map.txt" + +typedef struct { + unsigned short x; /**< X axis */ + unsigned short y; /**< Y axis */ + unsigned short z; /**< Z axis */ +} GSENSOR_VECTOR3D; + +static GSENSOR_VECTOR3D gsensor_gain = { 0 }; +static struct miscdevice mc3xxx_device; + +static struct file * fd_file = NULL; + +static mm_segment_t oldfs = { 0 }; +static unsigned char offset_buf[6] = { 0 }; +static signed int offset_data[3] = { 0 }; +s16 G_RAW_DATA[3] = { 0 }; +static signed int gain_data[3] = { 0 }; +static signed int enable_RBM_calibration = 0; + +#define GSENSOR 0x95 +#define GSENSOR_IOCTL_INIT _IO(GSENSOR, 0x01) +#define GSENSOR_IOCTL_READ_CHIPINFO _IOR(GSENSOR, 0x02, int) +#define GSENSOR_IOCTL_READ_SENSORDATA _IOR(GSENSOR, 0x03, int) +#define GSENSOR_IOCTL_READ_OFFSET _IOR(GSENSOR, 0x04, GSENSOR_VECTOR3D) +#define GSENSOR_IOCTL_READ_GAIN _IOR(GSENSOR, 0x05, GSENSOR_VECTOR3D) +#define GSENSOR_IOCTL_READ_RAW_DATA _IOR(GSENSOR, 0x06, int) +//#define GSENSOR_IOCTL_SET_CALI _IOW(GSENSOR, 0x06, SENSOR_DATA) +#define GSENSOR_IOCTL_GET_CALI _IOW(GSENSOR, 0x07, SENSOR_DATA) +#define GSENSOR_IOCTL_CLR_CALI _IO(GSENSOR, 0x08) +#define GSENSOR_MCUBE_IOCTL_READ_RBM_DATA _IOR(GSENSOR, 0x09, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_SET_RBM_MODE _IO(GSENSOR, 0x0a) +#define GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE _IO(GSENSOR, 0x0b) +#define GSENSOR_MCUBE_IOCTL_SET_CALI _IOW(GSENSOR, 0x0c, SENSOR_DATA) +#define GSENSOR_MCUBE_IOCTL_REGISTER_MAP _IO(GSENSOR, 0x0d) +#define GSENSOR_IOCTL_SET_CALI_MODE _IOW(GSENSOR, 0x0e,int) +#define GSENSOR_MCUBE_IOCTL_READ_PRODUCT_ID _IOR(GSENSOR, 0x0f, int) +#define GSENSOR_MCUBE_IOCTL_READ_FILEPATH _IOR(GSENSOR, 0x10, char[256]) + + +static int MC3XXX_ReadRegMap(struct i2c_client *client, u8 *pbUserBuf); +static int mc3xxx_chip_init(struct i2c_client *client); +static int MC3XXX_ResetCalibration(struct i2c_client *client); +static int MC3XX0_ValidateSensorIC(unsigned char bPCode); + + +typedef struct{ + int x; + int y; + int z; +}SENSOR_DATA; + +static int load_cali_flg = 0; +static int wake_mc3xxx_flg = 0; + +//MCUBE_BACKUP_FILE +static bool READ_FROM_BACKUP = false; +//MCUBE_BACKUP_FILE + +#endif + +#define MC3XXX_WAKE 1 +#define MC3XXX_SNIFF 2 +#define MC3XXX_STANDBY 3 + +struct dev_data { + struct i2c_client *client; +}; + +static struct dev_data dev = { 0 }; + +struct acceleration { + int x; + int y; + int z; +}; + +struct mc3xxx_data { + struct mutex lock; + struct i2c_client *client; + struct delayed_work work; + struct workqueue_struct *mc3xxx_wq; + struct hrtimer timer; + struct device *device; + struct input_dev *input_dev; + int use_count; + int enabled; + volatile unsigned int duration; + int use_irq; + int irq; + unsigned long irqflags; + int gpio; + unsigned int map[3]; + int inv[3]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + // for control + int int_gpio; //0-3 + int op; + int samp; + //int xyz_axis[3][3]; // (axis,direction) + struct proc_dir_entry* sensor_proc; + int isdbg; + int sensor_samp; // + int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor + int test_pass; + int offset[MC3XXX_AXIS_NUM+1]; /*+1: for 4-byte alignment*/ + s16 data[MC3XXX_AXIS_NUM+1]; +}; + +static struct mc3xxx_data l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + /*.xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + },*/ + .sensor_proc = NULL, + .isdbg = 1, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + //.offset={0,0,0}, +}; + + +//============================================================================= +enum mc3xx0_orientation +{ + MC3XX0_TOP_LEFT_DOWN = 0, + MC3XX0_TOP_RIGHT_DOWN, + MC3XX0_TOP_RIGHT_UP, + MC3XX0_TOP_LEFT_UP, + MC3XX0_BOTTOM_LEFT_DOWN, + MC3XX0_BOTTOM_RIGHT_DOWN, + MC3XX0_BOTTOM_RIGHT_UP, + MC3XX0_BOTTOM_LEFT_UP +}; + + +struct mc3xx0_hwmsen_convert +{ + signed int sign[3]; + unsigned int map[3]; +}; + +// Transformation matrix for chip mounting position +static const struct mc3xx0_hwmsen_convert mc3xx0_cvt[] = +{ + {{ 1, 1, 1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 0: top , left-down + {{-1, 1, 1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 1: top , right-down + {{-1, -1, 1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 2: top , right-up + {{ 1, -1, 1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 3: top , left-up + {{-1, 1, -1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 4: bottom, left-down + {{ 1, 1, -1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 5: bottom, right-down + {{ 1, -1, -1}, {MC3XXX_AXIS_X, MC3XXX_AXIS_Y, MC3XXX_AXIS_Z}}, // 6: bottom, right-up + {{-1, -1, -1}, {MC3XXX_AXIS_Y, MC3XXX_AXIS_X, MC3XXX_AXIS_Z}}, // 7: bottom, left-up +}; + +//static unsigned char mc3xx0_current_placement = MC3XX0_TOP_RIGHT_UP; // current soldered placement +static struct mc3xx0_hwmsen_convert *pCvt; + +#ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 +int Verify_Z_Railed(int AccData, int resolution) +{ + int status = 0; + GSE_LOG("%s: AccData = %d",__func__, AccData); + if(resolution == 1) // Low resolution + { + if((AccData >= Low_Pos_Max && AccData >=0)|| (AccData <= Low_Neg_Max && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at Low Resolution",__func__); + } + } + else if (resolution == 2) //High resolution + { + if((AccData >= High_Pos_Max && AccData >=0) || (AccData <= High_Neg_Max && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at High Resolution",__func__); + } + } + else if (resolution == 3) //High resolution + { + if((AccData >= Low_Pos_Max*3 && AccData >=0) || (AccData <= Low_Neg_Max*3 && AccData < 0)) + { + status = 1; + GSE_LOG("%s: Railed at High Resolution",__func__); + } + } + else + GSE_LOG("%s, Wrong resolution",__func__); + + return status; +} + +int SquareRoot(int x) +{ + int lowerbound; + int upperbound; + int root; + + if(x < 0) return -1; + if(x == 0 || x == 1) return x; + lowerbound = 1; + upperbound = x; + root = lowerbound + (upperbound - lowerbound)/2; + + while(root > x/root || root+1 <= x/(root+1)) + { + if(root > x/root) + { + upperbound = root; + } + else + { + lowerbound = root; + } + root = lowerbound + (upperbound - lowerbound)/2; + } + GSE_LOG("%s: Sqrt root is %d",__func__, root); + return root; +} +#endif + + +unsigned int sample_rate_2_memsec(unsigned int rate) +{ + return (1000/rate); +} + + +//============================================================================= +//volatile static short sensor_duration = SENSOR_DURATION_DEFAULT; +//volatile static short sensor_state_flag = 1; + +//============================================================================= +static ssize_t mc3xxx_map_show(struct device *dev, struct device_attribute *attr,char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mc3xxx_data *data = NULL; + int i = 0; + data = i2c_get_clientdata(client); + for (i = 0; i< 3; i++) + { + if(data->inv[i] == 1) + { + switch(data->map[i]) + { + case ABS_X: + buf[i] = 'x'; + break; + case ABS_Y: + buf[i] = 'y'; + break; + case ABS_Z: + buf[i] = 'z'; + break; + default: + buf[i] = '_'; + break; + } + } + else + { + switch(data->map[i]) + { + case ABS_X: + buf[i] = 'X'; + break; + case ABS_Y: + buf[i] = 'Y'; + break; + case ABS_Z: + buf[i] = 'Z'; + break; + default: + buf[i] = '-'; + break; + } + } + } + sprintf(buf+3,"\r\n"); + return 5; +} + +/***************************************** + *** show_regiter_map + *****************************************/ +static ssize_t show_regiter_map(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 _bIndex = 0; + u8 _baRegMap[64] = { 0 }; + ssize_t _tLength = 0; + + struct i2c_client *client = to_i2c_client(dev); + + MC3XXX_ReadRegMap(client, _baRegMap); + + for (_bIndex = 0; _bIndex < 64; _bIndex++) + _tLength += snprintf((buf + _tLength), (PAGE_SIZE - _tLength), "Reg[0x%02X]: 0x%02X\n", _bIndex, _baRegMap[_bIndex]); + + return (_tLength); +} + +static ssize_t mc3xxx_map_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mc3xxx_data *data = NULL; + int i = 0; + data = i2c_get_clientdata(client); + + if(count < 3) return -EINVAL; + + for(i = 0; i< 3; i++) + { + switch(buf[i]) + { + case 'x': + data->map[i] = ABS_X; + data->inv[i] = 1; + break; + case 'y': + data->map[i] = ABS_Y; + data->inv[i] = 1; + break; + case 'z': + data->map[i] = ABS_Z; + data->inv[i] = 1; + break; + case 'X': + data->map[i] = ABS_X; + data->inv[i] = -1; + break; + case 'Y': + data->map[i] = ABS_Y; + data->inv[i] = -1; + break; + case 'Z': + data->map[i] = ABS_Z; + data->inv[i] = -1; + break; + default: + return -EINVAL; + } + } + + return count; +} + +//============================================================================= +static ssize_t mc3xxx_version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", SENSOR_DRIVER_VERSION); +} + +//============================================================================= +static ssize_t mc3xxx_chip_id_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned char bChipID[4] = { 0 }; + struct i2c_client *client = to_i2c_client(dev); + + i2c_smbus_read_i2c_block_data(client, 0x3C, 4, bChipID); + + return sprintf(buf, "%02X-%02X-%02X-%02X\n", bChipID[0], bChipID[1], bChipID[2], bChipID[3]); +} +/* +//============================================================================= +static ssize_t mc3xxx_position_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + printk("%s called\n", __func__); + return sprintf(buf, "%d\n", mc3xx0_current_placement); +} + +//============================================================================= +static ssize_t mc3xxx_position_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + unsigned long position = 0; + + printk("%s called\n", __func__); + + position = simple_strtoul(buf, NULL,10); + + if (position < 8) + mc3xx0_current_placement = position; + + return count; +} +*/ + +static int mc3xxx_enable(struct mc3xxx_data *data, int enable) +{ + if(enable) + { + msleep(10); + //mutex_lock(&data->lock); + mc3xxx_chip_init(data->client); + //mutex_unlock(&data->lock); + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp)));//hrtimer_start(&data->timer, ktime_set(0, sensor_duration*1000000), HRTIMER_MODE_REL); + data->enabled = true; + } + else + { + cancel_delayed_work_sync(&l_sensorconfig.work);//hrtimer_cancel(&data->timer); + data->enabled = false; + } + return 0; +} + +static ssize_t mc3xxx_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); + + struct mc3xxx_data *mc3xxx = i2c_get_clientdata(client); + + + return sprintf(buf, "%d\n", mc3xxx->enabled); +} + +static ssize_t mc3xxx_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + + bool new_enable; + + struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); + + struct mc3xxx_data *mc3xxx = i2c_get_clientdata(client); + + if (sysfs_streq(buf, "1")) + new_enable = true; + else if (sysfs_streq(buf, "0")) + new_enable = false; + else + { + pr_debug("%s: invalid value %d\n", __func__, *buf); + return -EINVAL; + } + + mc3xxx_enable(mc3xxx, new_enable); + + return count; +} + + +static DRIVER_ATTR(regmap , S_IRUGO, show_regiter_map, NULL ); +static DEVICE_ATTR(map, S_IWUSR | S_IRUGO, mc3xxx_map_show, mc3xxx_map_store); +static DEVICE_ATTR(version , S_IRUGO , mc3xxx_version_show , NULL ); +static DEVICE_ATTR(chipid , S_IRUGO , mc3xxx_chip_id_show , NULL ); +//static DEVICE_ATTR(position, S_IRUGO | S_IWUSR | S_IWGRP, mc3xxx_position_show, mc3xxx_position_store); +static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP|S_IWOTH, mc3xxx_enable_show, mc3xxx_enable_store); +static struct attribute* mc3xxx_attrs[] = +{ + &driver_attr_regmap, + &dev_attr_map.attr, + &dev_attr_version.attr, + &dev_attr_chipid.attr, + //&dev_attr_position.attr, + &dev_attr_enable.attr, + NULL +}; + +static const struct attribute_group mc3xxx_group = +{ + .attrs = mc3xxx_attrs, +}; + +//============================================================================= +static int mc3xxx_chip_init(struct i2c_client *client) +{ + unsigned char data = 0; + + data = i2c_smbus_read_byte_data(client, MC3XXX_REG_PRODUCT_CODE); + s_bPCODE =data; + if((data == MC3XXX_PCODE_3230)||(data == MC3XXX_PCODE_3430) + ||(data == MC3XXX_PCODE_3430N)||(data == MC3XXX_PCODE_3530B) + ||((data|0x0E) == MC3XXX_PCODE_3530C)) + Sensor_Accuracy = MCUBE_1_5G_8BIT; //8bit + else if((data == MC3XXX_PCODE_3210)||(data == MC3XXX_PCODE_3410) + ||(data == MC3XXX_PCODE_3250)||(data == MC3XXX_PCODE_3410N) + ||(data == MC3XXX_PCODE_3510B)||(data == MC3XXX_PCODE_3510C)) + Sensor_Accuracy = MCUBE_8G_14BIT; //14bit + else + Sensor_Accuracy = 0; + + if (data == MC3XXX_PCODE_3250) + is_mc3250 = 1; + + if ((data == MC3XXX_PCODE_3430N)||(data == MC3XXX_PCODE_3410N)) + is_new_mc34x0 = 1; + + if((MC3XXX_PCODE_3510B == data) || (MC3XXX_PCODE_3510C == data) + ||(data == MC3XXX_PCODE_3530B)||((data|0x0E) == MC3XXX_PCODE_3530C)) + is_mc35xx = 1; + + + if(MCUBE_8G_14BIT == Sensor_Accuracy) + { + data = 0x43; + i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_SLEEP_COUNT, data); + + data = 0x00; + if (is_mc35xx) + { + data = 0x0A; + } + + i2c_smbus_write_byte_data(client, MC3XXX_REG_SAMPLE_RATE, data); + + data = 0x3F; + if ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE)) + data = 0x25; + else if ((MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == (s_bPCODE|0x0E))) + data = 0x02; + + i2c_smbus_write_byte_data(client, MC3XXX_REG_RANGE_CONTROL, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_TAP_DETECTION_ENABLE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_INTERRUPT_ENABLE, data); + + #ifdef DOT_CALI + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 1024; + #endif + } + else if(MCUBE_1_5G_8BIT == Sensor_Accuracy) + { + data = 0x43; + i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_SLEEP_COUNT, data); + + data = 0x00; + if (is_mc35xx) + { + data = 0x0A; + } + + i2c_smbus_write_byte_data(client, MC3XXX_REG_SAMPLE_RATE, data); + + data = 0x32; + if ((MC3XXX_PCODE_3510B == s_bPCODE) || (MC3XXX_PCODE_3510C == s_bPCODE)) + data = 0x25; + else if ((MC3XXX_PCODE_3530B == s_bPCODE) || (MC3XXX_PCODE_3530C == (s_bPCODE|0x0E))) + data = 0x02; + + i2c_smbus_write_byte_data(client, MC3XXX_REG_RANGE_CONTROL,data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_TAP_DETECTION_ENABLE, data); + data = 0x00; + i2c_smbus_write_byte_data(client, MC3XXX_REG_INTERRUPT_ENABLE, data); + + #ifdef DOT_CALI + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 86; + if (is_mc35xx) + { + gsensor_gain.x = gsensor_gain.y = gsensor_gain.z = 64; + } + #endif + } + + data = 0x41; + i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + + return 0; +} + +//============================================================================= +int mc3xxx_set_mode(struct i2c_client *client, unsigned char mode) +{ + int comres = 0; + unsigned char data = 0; + + if (mode < 4) + { + data = (0x40 | mode); + comres = i2c_smbus_write_byte_data(client, MC3XXX_REG_MODE_FEATURE, data); + } + + return comres; +} + + + +#ifdef DOT_CALI +//============================================================================= +struct file *openFile(char *path,int flag,int mode) +{ + struct file *fp = NULL; + + fp = filp_open(path, flag, mode); + + if (IS_ERR(fp) || !fp->f_op) + { + GSE_LOG("Calibration File filp_open return NULL\n"); + return NULL; + } + + return fp; +} + +//============================================================================= +int readFile(struct file *fp,char *buf,int readlen) +{ + if (fp->f_op && fp->f_op->read) + return fp->f_op->read(fp,buf,readlen, &fp->f_pos); + else + return -1; +} + +//============================================================================= +int writeFile(struct file *fp,char *buf,int writelen) +{ + if (fp->f_op && fp->f_op->write) + return fp->f_op->write(fp,buf,writelen, &fp->f_pos); + else + return -1; +} + +//============================================================================= +int closeFile(struct file *fp) +{ + filp_close(fp,NULL); + + return 0; +} + +//============================================================================= +void initKernelEnv(void) +{ + oldfs = get_fs(); + set_fs(KERNEL_DS); + printk(KERN_INFO "initKernelEnv\n"); +} + +//============================================================================= + int MC3XXX_WriteCalibration(struct i2c_client *client, int dat[MC3XXX_AXIS_NUM]) +{ + int err = 0; + u8 buf[9] = { 0 }; + s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; + s32 x_off = 0, y_off = 0, z_off = 0; + int temp_cali_dat[MC3XXX_AXIS_NUM] = { 0 }; + //const struct mc3xx0_hwmsen_convert *pCvt = NULL; + + u8 bMsbFilter = 0x3F; + s16 wSignBitMask = 0x2000; + s16 wSignPaddingBits = 0xC000; + s32 dwRangePosLimit = 0x1FFF; + s32 dwRangeNegLimit = -0x2000; + + if (is_mc35xx) + { + bMsbFilter = 0x7F; + wSignBitMask = 0x4000; + wSignPaddingBits = 0x8000; + dwRangePosLimit = 0x3FFF; + dwRangeNegLimit = -0x4000; + } + + //pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + + temp_cali_dat[pCvt->map[MC3XXX_AXIS_X]] = pCvt->sign[MC3XXX_AXIS_X] * dat[MC3XXX_AXIS_X]; + temp_cali_dat[pCvt->map[MC3XXX_AXIS_Y]] = pCvt->sign[MC3XXX_AXIS_Y] * dat[MC3XXX_AXIS_Y]; + temp_cali_dat[pCvt->map[MC3XXX_AXIS_Z]] = pCvt->sign[MC3XXX_AXIS_Z] * dat[MC3XXX_AXIS_Z]; + + if ((is_new_mc34x0)||(is_mc35xx)) + { + temp_cali_dat[MC3XXX_AXIS_X] = -temp_cali_dat[MC3XXX_AXIS_X]; + temp_cali_dat[MC3XXX_AXIS_Y] = -temp_cali_dat[MC3XXX_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = temp_cali_dat[MC3XXX_AXIS_X]; + + temp_cali_dat[MC3XXX_AXIS_X] = -temp_cali_dat[MC3XXX_AXIS_Y]; + temp_cali_dat[MC3XXX_AXIS_Y] = temp; + } + + dat[MC3XXX_AXIS_X] = temp_cali_dat[MC3XXX_AXIS_X]; + dat[MC3XXX_AXIS_Y] = temp_cali_dat[MC3XXX_AXIS_Y]; + dat[MC3XXX_AXIS_Z] = temp_cali_dat[MC3XXX_AXIS_Z]; + + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", + dat[MC3XXX_AXIS_X], dat[MC3XXX_AXIS_Y], dat[MC3XXX_AXIS_Z]); + + // read register 0x21~0x29 + err = i2c_smbus_read_i2c_block_data(client , 0x21 , 3 , &buf[0]); + err |= i2c_smbus_read_i2c_block_data(client , 0x24 , 3 , &buf[3]); + err |= i2c_smbus_read_i2c_block_data(client , 0x27 , 3 , &buf[6]); + + + // get x,y,z offset + tmp = ((buf[1] & bMsbFilter) << 8) + buf[0]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + x_off = tmp; + + tmp = ((buf[3] & bMsbFilter) << 8) + buf[2]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + y_off = tmp; + + tmp = ((buf[5] & bMsbFilter) << 8) + buf[4]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + z_off = tmp; + + // get x,y,z gain + x_gain = ((buf[1] >> 7) << 8) + buf[6]; + y_gain = ((buf[3] >> 7) << 8) + buf[7]; + z_gain = ((buf[5] >> 7) << 8) + buf[8]; + + // prepare new offset + x_off = x_off + 16 * dat[MC3XXX_AXIS_X] * 256 * 128 / 3 / gsensor_gain.x / (40 + x_gain); + y_off = y_off + 16 * dat[MC3XXX_AXIS_Y] * 256 * 128 / 3 / gsensor_gain.y / (40 + y_gain); + z_off = z_off + 16 * dat[MC3XXX_AXIS_Z] * 256 * 128 / 3 / gsensor_gain.z / (40 + z_gain); + + //add for over range + if( x_off > dwRangePosLimit) + { + x_off = dwRangePosLimit; + } + else if( x_off < dwRangeNegLimit) + { + x_off = dwRangeNegLimit; + } + + if( y_off > dwRangePosLimit) + { + y_off = dwRangePosLimit; + } + else if( y_off < dwRangeNegLimit) + { + y_off = dwRangeNegLimit; + } + + if( z_off > dwRangePosLimit) + { + z_off = dwRangePosLimit; + } + else if( z_off < dwRangeNegLimit) + { + z_off = dwRangeNegLimit; + } + + //storege the cerrunt offset data with DOT format + offset_data[0] = x_off; + offset_data[1] = y_off; + offset_data[2] = z_off; + + //storege the cerrunt Gain data with GOT format + gain_data[0] = 256*8*128/3/(40+x_gain); + gain_data[1] = 256*8*128/3/(40+y_gain); + gain_data[2] = 256*8*128/3/(40+z_gain); + printk("%d %d ======================\n\n ",gain_data[0],x_gain); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = x_off & 0xff; + buf[1] = ((x_off >> 8) & bMsbFilter) | (x_gain & 0x0100 ? 0x80 : 0); + buf[2] = y_off & 0xff; + buf[3] = ((y_off >> 8) & bMsbFilter) | (y_gain & 0x0100 ? 0x80 : 0); + buf[4] = z_off & 0xff; + buf[5] = ((z_off >> 8) & bMsbFilter) | (z_gain & 0x0100 ? 0x80 : 0); + + i2c_smbus_write_i2c_block_data(client, 0x21, 2, &buf[0]); + i2c_smbus_write_i2c_block_data(client, 0x21+2, 2, &buf[2]); + i2c_smbus_write_i2c_block_data(client, 0x21+4, 2, &buf[4]); + + buf[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07,buf[0]); + + msleep(50); + + return err; + +} + +int mcube_read_cali_file(struct i2c_client *client) +{ + int cali_data[3] = { 0 }; + int err =0; + //char buf[64]; + printk("%s %d\n",__func__,__LINE__); + //MCUBE_BACKUP_FILE + READ_FROM_BACKUP = false; + //MCUBE_BACKUP_FILE + initKernelEnv(); + fd_file = openFile(CALIB_PATH,O_RDONLY,0); + //MCUBE_BACKUP_FILE + if (fd_file == NULL) + { + fd_file = openFile(BACKUP_CALIB_PATH, O_RDONLY, 0); + if(fd_file != NULL) + { + READ_FROM_BACKUP = true; + } + } + //MCUBE_BACKUP_FILE + if (fd_file == NULL) + { + GSE_LOG("fail to open\n"); + cali_data[0] = 0; + cali_data[1] = 0; + cali_data[2] = 0; + + return -1; + } + else + { + printk("%s %d\n",__func__,__LINE__); + memset(backup_buf,0,64); + if ((err = readFile(fd_file,backup_buf,128))>0) + GSE_LOG("buf:%s\n",backup_buf); + else + GSE_LOG("read file error %d\n",err); + printk("%s %d\n",__func__,__LINE__); + + set_fs(oldfs); + closeFile(fd_file); + + sscanf(backup_buf, "%d %d %d",&cali_data[MC3XXX_AXIS_X], &cali_data[MC3XXX_AXIS_Y], &cali_data[MC3XXX_AXIS_Z]); + GSE_LOG("cali_data: %d %d %d\n", cali_data[MC3XXX_AXIS_X], cali_data[MC3XXX_AXIS_Y], cali_data[MC3XXX_AXIS_Z]); + + MC3XXX_WriteCalibration(client, cali_data); + } + return 0; +} + +//============================================================================= +static int mcube_write_log_data(struct i2c_client *client, u8 data[0x3f]) +{ + #define _WRT_LOG_DATA_BUFFER_SIZE (66 * 50) + + s16 rbm_data[3]={0}, raw_data[3]={0}; + int err =0; + char *_pszBuffer = NULL; + int n=0,i=0; + + initKernelEnv(); + fd_file = openFile(DATA_PATH ,O_RDWR | O_CREAT,0); + if (fd_file == NULL) + { + GSE_LOG("mcube_write_log_data fail to open\n"); + } + else + { + rbm_data[MC3XXX_AXIS_X] = (s16)((data[0x0d]) | (data[0x0e] << 8)); + rbm_data[MC3XXX_AXIS_Y] = (s16)((data[0x0f]) | (data[0x10] << 8)); + rbm_data[MC3XXX_AXIS_Z] = (s16)((data[0x11]) | (data[0x12] << 8)); + + raw_data[MC3XXX_AXIS_X] = (rbm_data[MC3XXX_AXIS_X] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + raw_data[MC3XXX_AXIS_Y] = (rbm_data[MC3XXX_AXIS_Y] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + raw_data[MC3XXX_AXIS_Z] = (rbm_data[MC3XXX_AXIS_Z] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + + _pszBuffer = kzalloc(_WRT_LOG_DATA_BUFFER_SIZE, GFP_KERNEL); + if (NULL == _pszBuffer) + { + GSE_ERR("fail to allocate memory for buffer\n"); + closeFile(fd_file); + return -1; + } + memset(_pszBuffer, 0, _WRT_LOG_DATA_BUFFER_SIZE); + + n += sprintf(_pszBuffer+n, "G-sensor RAW X = %d Y = %d Z = %d\n", raw_data[0] ,raw_data[1] ,raw_data[2]); + n += sprintf(_pszBuffer+n, "G-sensor RBM X = %d Y = %d Z = %d\n", rbm_data[0] ,rbm_data[1] ,rbm_data[2]); + for(i=0; i<64; i++) + { + n += sprintf(_pszBuffer+n, "mCube register map Register[%x] = 0x%x\n",i,data[i]); + } + msleep(50); + if ((err = writeFile(fd_file,_pszBuffer,n))>0) + GSE_LOG("buf:%s\n",_pszBuffer); + else + GSE_LOG("write file error %d\n",err); + + kfree(_pszBuffer); + + set_fs(oldfs); + closeFile(fd_file); + } + return 0; +} + +//============================================================================= +void MC3XXX_rbm(struct i2c_client *client, int enable) +{ + char buf1[3] = { 0 }; + if(enable == 1 ) + { + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + buf1[0] = 0x6D; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x3B, buf1[0]); + + buf1[0] = 0x02; + i2c_smbus_write_byte_data(client, 0x14, buf1[0]); + + buf1[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + enable_RBM_calibration = 1; + + GSE_LOG("set rbm!!\n"); + + msleep(10); + } + else if(enable == 0 ) + { + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + buf1[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x14, buf1[0]); + GSE_LOG("set rbm!! %x @@@@\n",s_bPCODE); + + buf1[0] = s_bPCODE; + i2c_smbus_write_byte_data(client, 0x3B, buf1[0]); + + buf1[0] = 0x6D; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1B, buf1[0]); + + buf1[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf1[0]); + + enable_RBM_calibration = 0; + + GSE_LOG("clear rbm!!\n"); + + msleep(10); + } +} + +/*----------------------------------------------------------------------------*/ + int MC3XXX_ReadData_RBM(struct i2c_client *client,int data[MC3XXX_AXIS_NUM]) +{ + u8 addr = 0x0d; + u8 rbm_buf[MC3XXX_DATA_LEN] = {0}; + int err = 0; + + //err = p_mc3xxx->MC3XXX_BUS_READ_FUNC(p_mc3xxx->dev_addr, addr, &rbm_buf[0],6); + err = i2c_smbus_read_i2c_block_data(client , addr , 6 , rbm_buf); + //err = mc3xxx_read_block(client, addr, rbm_buf, 0x06); + + data[MC3XXX_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + data[MC3XXX_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + data[MC3XXX_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + GSE_LOG("rbm_buf<<<<<[%02x %02x %02x %02x %02x %02x]\n",rbm_buf[0], rbm_buf[2], rbm_buf[2], rbm_buf[3], rbm_buf[4], rbm_buf[5]); + GSE_LOG("RBM<<<<<[%04x %04x %04x]\n", data[MC3XXX_AXIS_X], data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); + GSE_LOG("RBM<<<<<[%04d %04d %04d]\n", data[MC3XXX_AXIS_X], data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); + return err; +} + + + int MC3XXX_ReadRBMData(struct i2c_client *client, char *buf) +{ + int res = 0; + int data[3]; + + if (!buf) + { + return EINVAL; + } + + mc3xxx_set_mode(client,MC3XXX_WAKE); + + res = MC3XXX_ReadData_RBM(client,data); + + if(res) + { + GSE_ERR("%s I2C error: ret value=%d",__func__, res); + return EIO; + } + else + { + sprintf(buf, "%04x %04x %04x", data[MC3XXX_AXIS_X], + data[MC3XXX_AXIS_Y], data[MC3XXX_AXIS_Z]); + + } + + return 0; +} + int MC3XXX_ReadOffset(struct i2c_client *client,s16 ofs[MC3XXX_AXIS_NUM]) +{ + int err = 0; + u8 off_data[6] = { 0 }; + + if(Sensor_Accuracy == MCUBE_8G_14BIT) + { + err = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT_EX_L, MC3XXX_DATA_LEN, off_data); + + ofs[MC3XXX_AXIS_X] = ((s16)(off_data[0]))|((s16)(off_data[1])<<8); + ofs[MC3XXX_AXIS_Y] = ((s16)(off_data[2]))|((s16)(off_data[3])<<8); + ofs[MC3XXX_AXIS_Z] = ((s16)(off_data[4]))|((s16)(off_data[5])<<8); + } + else if(Sensor_Accuracy == MCUBE_1_5G_8BIT) + { + err = i2c_smbus_read_i2c_block_data(client, 0, 3, off_data); + + ofs[MC3XXX_AXIS_X] = (s8)off_data[0]; + ofs[MC3XXX_AXIS_Y] = (s8)off_data[1]; + ofs[MC3XXX_AXIS_Z] = (s8)off_data[2]; + } + + GSE_LOG("MC3XXX_ReadOffset %d %d %d\n", ofs[MC3XXX_AXIS_X], ofs[MC3XXX_AXIS_Y], ofs[MC3XXX_AXIS_Z]); + + return err; +} +/*----------------------------------------------------------------------------*/ + static int MC3XXX_ResetCalibration(struct i2c_client *client) +{ + u8 buf[6] = { 0 }; + s16 tmp = 0; + int err = 0; + + u8 bMsbFilter = 0x3F; + s16 wSignBitMask = 0x2000; + s16 wSignPaddingBits = 0xC000; + + buf[0] = 0x43; + err = i2c_smbus_write_byte_data(client, 0x07, buf[0]); + if(err) + { + GSE_ERR("error 0x07: %d\n", err); + } + + err = i2c_smbus_write_i2c_block_data(client, 0x21, 6, offset_buf); + if(err) + { + GSE_ERR("error: %d\n", err); + } + + buf[0] = 0x41; + err = i2c_smbus_write_byte_data(client, 0x07, buf[0]); + if(err) + { + GSE_ERR("error: %d\n", err); + } + + msleep(20); + + + if (is_mc35xx) + { + bMsbFilter = 0x7F; + wSignBitMask = 0x4000; + wSignPaddingBits = 0x8000; + } + + tmp = ((offset_buf[1] & bMsbFilter) << 8) + offset_buf[0]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[0] = tmp; + + tmp = ((offset_buf[3] & bMsbFilter) << 8) + offset_buf[2]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[1] = tmp; + + tmp = ((offset_buf[5] & bMsbFilter) << 8) + offset_buf[4]; + if (tmp & wSignBitMask) + tmp |= wSignPaddingBits; + offset_data[2] = tmp; + + return 0; +} + +//============================================================================= + int MC3XXX_ReadCalibration(struct i2c_client *client,int dat[MC3XXX_AXIS_NUM]) +{ + signed short MC_offset[MC3XXX_AXIS_NUM + 1] = { 0 }; // +1: for 4-byte alignment + int err = 0; + + memset(MC_offset, 0, sizeof(MC_offset)); + + err = MC3XXX_ReadOffset(client, MC_offset); + + if (err) + { + GSE_ERR("read offset fail, %d\n", err); + return err; + } + + dat[MC3XXX_AXIS_X] = MC_offset[MC3XXX_AXIS_X]; + dat[MC3XXX_AXIS_Y] = MC_offset[MC3XXX_AXIS_Y]; + dat[MC3XXX_AXIS_Z] = MC_offset[MC3XXX_AXIS_Z]; + + return 0; +} + +//============================================================================= +int MC3XXX_ReadData(struct i2c_client *client, s16 buffer[MC3XXX_AXIS_NUM]) +{ + unsigned char buf[6] = { 0 }; + signed char buf1[6] = { 0 }; + char rbm_buf[6] = { 0 }; + int ret = 0; + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR + int tempX=0; + int tempY=0; + int tempZ=0; + #endif + + if (enable_RBM_calibration == 0) + { + //err = hwmsen_read_block(client, addr, buf, 0x06); + } + else if (enable_RBM_calibration == 1) + { + memset(rbm_buf, 0, 6); + i2c_smbus_read_i2c_block_data(client, 0x0d , 2, &rbm_buf[0]); + i2c_smbus_read_i2c_block_data(client, 0x0d+2, 2, &rbm_buf[2]); + i2c_smbus_read_i2c_block_data(client, 0x0d+4, 2, &rbm_buf[4]); + } + + if (enable_RBM_calibration == 0) + { + if(Sensor_Accuracy == MCUBE_8G_14BIT) + { + ret = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT_EX_L, 6, buf); + + buffer[0] = (signed short)((buf[0])|(buf[1]<<8)); + buffer[1] = (signed short)((buf[2])|(buf[3]<<8)); + buffer[2] = (signed short)((buf[4])|(buf[5]<<8)); + } + else if(Sensor_Accuracy == MCUBE_1_5G_8BIT) + { + ret = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT, 3, buf1); + + buffer[0] = (signed short)buf1[0]; + buffer[1] = (signed short)buf1[1]; + buffer[2] = (signed short)buf1[2]; + } + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR //add 2013-10-23 + if (g_virtual_z) + { + //printk("%s 1\n", __FUNCTION__); + + tempX = buffer[MC3XXX_AXIS_X]; + tempY = buffer[MC3XXX_AXIS_Y]; + tempZ = buffer[MC3XXX_AXIS_Z]; + //printk(" %d:Verify_Z_Railed() %d\n", (int)buffer[MC32X0_AXIS_Z], Verify_Z_Railed((int)buffer[MC32X0_AXIS_Z], LOW_RESOLUTION)); + if(1 == Verify_Z_Railed((int)buffer[MC3XXX_AXIS_Z], LOW_RESOLUTION)) // z-railed + { + Railed = 1; + + GSE_LOG("%s: Z railed", __func__); + //printk("%s: Z railed \n", __func__); + if (G_2_REVERSE_VIRTUAL_Z == 1) + buffer[MC3XXX_AXIS_Z] = (s8) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC3XXX_AXIS_Z] = (s8) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + else + { + Railed = 0; + } + } + #endif + mcprintkreg("MC3XXX_ReadData: %d %d %d\n", buffer[0], buffer[1], buffer[2]); + } + else if (enable_RBM_calibration == 1) + { + buffer[MC3XXX_AXIS_X] = (s16)((rbm_buf[0]) | (rbm_buf[1] << 8)); + buffer[MC3XXX_AXIS_Y] = (s16)((rbm_buf[2]) | (rbm_buf[3] << 8)); + buffer[MC3XXX_AXIS_Z] = (s16)((rbm_buf[4]) | (rbm_buf[5] << 8)); + + GSE_LOG("%s RBM<<<<<[%08d %08d %08d]\n", __func__, buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + + if(gain_data[0] == 0) + { + buffer[MC3XXX_AXIS_X] = 0; + buffer[MC3XXX_AXIS_Y] = 0; + buffer[MC3XXX_AXIS_Z] = 0; + + return 0; + } + + buffer[MC3XXX_AXIS_X] = (buffer[MC3XXX_AXIS_X] + offset_data[0]/2)*gsensor_gain.x/gain_data[0]; + buffer[MC3XXX_AXIS_Y] = (buffer[MC3XXX_AXIS_Y] + offset_data[1]/2)*gsensor_gain.y/gain_data[1]; + buffer[MC3XXX_AXIS_Z] = (buffer[MC3XXX_AXIS_Z] + offset_data[2]/2)*gsensor_gain.z/gain_data[2]; + + #ifdef SUPPORT_VIRTUAL_Z_SENSOR // add 2013-10-23 + if (g_virtual_z) + { + tempX = buffer[MC3XXX_AXIS_X]; + tempY = buffer[MC3XXX_AXIS_Y]; + tempZ = buffer[MC3XXX_AXIS_Z]; + //printk("%s 2\n", __FUNCTION__); + GSE_LOG("Original RBM<<<<<[%08d %08d %08d]\n", buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + printk("Verify_Z_Railed() %d\n", Verify_Z_Railed((int)buffer[MC3XXX_AXIS_Z], RBM_RESOLUTION)); + if(1 == Verify_Z_Railed(buffer[MC3XXX_AXIS_Z], RBM_RESOLUTION)) // z-railed + { + GSE_LOG("%s: Z Railed in RBM mode",__FUNCTION__); + //printk("%s: Z Railed in RBM mode\n",__FUNCTION__); + if (G_2_REVERSE_VIRTUAL_Z == 1) + buffer[MC3XXX_AXIS_Z] = (s16) ( gsensor_gain.z - (abs(tempX) + abs(tempY))); + else + buffer[MC3XXX_AXIS_Z] = (s16) -( gsensor_gain.z - (abs(tempX) + abs(tempY))); + } + GSE_LOG("RBM<<<<<[%08d %08d %08d]\n", buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + } + #endif + + GSE_LOG("%s offset_data <<<<<[%d %d %d]\n", __func__, offset_data[0], offset_data[1], offset_data[2]); + GSE_LOG("%s gsensor_gain <<<<<[%d %d %d]\n", __func__, gsensor_gain.x, gsensor_gain.y, gsensor_gain.z); + GSE_LOG("%s gain_data <<<<<[%d %d %d]\n", __func__, gain_data[0], gain_data[1], gain_data[2]); + GSE_LOG("%s RBM->RAW <<<<<[%d %d %d]\n", __func__, buffer[MC3XXX_AXIS_X], buffer[MC3XXX_AXIS_Y], buffer[MC3XXX_AXIS_Z]); + } + + return 0; +} + +//============================================================================= +int MC3XXX_ReadRawData(struct i2c_client *client, char * buf) +{ + int res = 0; + s16 raw_buf[3] = { 0 }; + + if (!buf || !client) + { + return -EINVAL; + } + + mc3xxx_set_mode(client, MC3XXX_WAKE); + res = MC3XXX_ReadData(client,&raw_buf[0]); + if(res) + { + printk("%s %d\n",__FUNCTION__, __LINE__); + GSE_ERR("I2C error: ret value=%d", res); + return -EIO; + } + else + { + //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + + GSE_LOG("UPDATE dat: (%+3d %+3d %+3d)\n", + raw_buf[MC3XXX_AXIS_X], raw_buf[MC3XXX_AXIS_Y], raw_buf[MC3XXX_AXIS_Z]); + + if ((is_new_mc34x0)||(is_mc35xx)) + { + raw_buf[MC3XXX_AXIS_X] = -raw_buf[MC3XXX_AXIS_X]; + raw_buf[MC3XXX_AXIS_Y] = -raw_buf[MC3XXX_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_buf[MC3XXX_AXIS_X]; + + raw_buf[MC3XXX_AXIS_X] = raw_buf[MC3XXX_AXIS_Y]; + raw_buf[MC3XXX_AXIS_Y] = -temp; + } + + G_RAW_DATA[MC3XXX_AXIS_X] = pCvt->sign[MC3XXX_AXIS_X] * raw_buf[pCvt->map[MC3XXX_AXIS_X]]; + G_RAW_DATA[MC3XXX_AXIS_Y] = pCvt->sign[MC3XXX_AXIS_Y] * raw_buf[pCvt->map[MC3XXX_AXIS_Y]]; + G_RAW_DATA[MC3XXX_AXIS_Z] = pCvt->sign[MC3XXX_AXIS_Z] * raw_buf[pCvt->map[MC3XXX_AXIS_Z]]; + + G_RAW_DATA[MC3XXX_AXIS_Z] += gsensor_gain.z*(pCvt->sign[MC3XXX_AXIS_Z])*(1);//G_RAW_DATA[MC3XXX_AXIS_Z]+gsensor_gain.z; + + sprintf(buf, "%04x %04x %04x", G_RAW_DATA[MC3XXX_AXIS_X], + G_RAW_DATA[MC3XXX_AXIS_Y], G_RAW_DATA[MC3XXX_AXIS_Z]); + + GSE_LOG("G_RAW_DATA: (%+3d %+3d %+3d)\n", + G_RAW_DATA[MC3XXX_AXIS_X], G_RAW_DATA[MC3XXX_AXIS_Y], G_RAW_DATA[MC3XXX_AXIS_Z]); + } + + return 0; +} + +//============================================================================= +static int MC3XXX_ReadRegMap(struct i2c_client *client, u8 *pbUserBuf) +{ + u8 data[128] = {0}; + //u8 addr = 0x00; + int err = 0; + int i = 0; + + if(NULL == client) + { + err = -EINVAL; + return err; + } + + + for(i = 0; i < 64; i++) + { + data[i] = i2c_smbus_read_byte_data(client, i); + printk(KERN_INFO "mcube register map Register[%x] = 0x%x\n", i ,data[i]); + } + + msleep(50); + + mcube_write_log_data(client, data); + + msleep(50); + + if (NULL != pbUserBuf) + { + printk(KERN_INFO "copy to user buffer\n"); + memcpy(pbUserBuf, data, 64); + } + + return err; +} + +//============================================================================= +void MC3XXX_Reset(struct i2c_client *client) +{ + //s16 tmp = 0, x_gain = 0, y_gain = 0, z_gain = 0; + u8 buf[3] = { 0 }; + int err = 0; + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + i2c_smbus_read_i2c_block_data(client, 0x04, 1, buf); + + if (0x00 == (buf[0] & 0x40)) + { + buf[0] = 0x6d; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + } + + msleep(5); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + + buf[0] = 0x80; + i2c_smbus_write_byte_data(client, 0x1c, buf[0]); + + buf[0] = 0x80; + i2c_smbus_write_byte_data(client, 0x17, buf[0]); + + msleep(5); + + buf[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x1c, buf[0]); + + buf[0] = 0x00; + i2c_smbus_write_byte_data(client, 0x17, buf[0]); + + msleep(5); + + memset(offset_buf, 0, sizeof(offset_buf)); + + err = i2c_smbus_read_i2c_block_data(client, 0x21, 6, offset_buf); + + i2c_smbus_read_i2c_block_data(client, 0x04, 1, buf); + + if (0x00 == (buf[0] & 0x40)) + { + buf[0] = 0x6d; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + + buf[0] = 0x43; + i2c_smbus_write_byte_data(client, 0x1b, buf[0]); + } + + buf[0] = 0x41; + i2c_smbus_write_byte_data(client, 0x07, buf[0]); + +} +#endif + +int mc3xxx_read_accel_xyz(struct i2c_client *client, s16 * acc) +{ + int comres = 0; + s16 raw_data[MC3XXX_AXIS_NUM] = { 0 }; + //const struct mc3xx0_hwmsen_convert *pCvt = &mc3xx0_cvt[mc3xx0_current_placement]; + +#ifdef DOT_CALI + s16 raw_buf[6] = { 0 }; + + comres = MC3XXX_ReadData(client, &raw_buf[0]); + + raw_data[MC3XXX_AXIS_X] = raw_buf[0]; + raw_data[MC3XXX_AXIS_Y] = raw_buf[1]; + raw_data[MC3XXX_AXIS_Z] = raw_buf[2]; +#else + unsigned char raw_buf[6] = { 0 }; + signed char raw_buf1[3] = { 0 }; + + if(Sensor_Accuracy == MCUBE_8G_14BIT) + { + comres = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT_EX_L, 6, raw_buf); + + raw_data[MC3XXX_AXIS_X] = (signed short)((raw_buf[0])|(raw_buf[1]<<8)); + raw_data[MC3XXX_AXIS_Y] = (signed short)((raw_buf[2])|(raw_buf[3]<<8)); + raw_data[MC3XXX_AXIS_Z] = (signed short)((raw_buf[4])|(raw_buf[5]<<8)); + } + else if(Sensor_Accuracy == MCUBE_1_5G_8BIT) + { + comres = i2c_smbus_read_i2c_block_data(client, MC3XXX_REG_XOUT, 3, raw_buf1); + + raw_data[MC3XXX_AXIS_X] = (signed short)raw_buf1[0]; + raw_data[MC3XXX_AXIS_Y] = (signed short)raw_buf1[1]; + raw_data[MC3XXX_AXIS_Z] = (signed short)raw_buf1[2]; + } +#endif + + if((is_new_mc34x0)||(is_mc35xx)) + { + raw_data[MC3XXX_AXIS_X] = -raw_data[MC3XXX_AXIS_X]; + raw_data[MC3XXX_AXIS_Y] = -raw_data[MC3XXX_AXIS_Y]; + } + else if (is_mc3250) + { + s16 temp = 0; + + temp = raw_data[MC3XXX_AXIS_X]; + + raw_data[MC3XXX_AXIS_X] = raw_data[MC3XXX_AXIS_Y]; + raw_data[MC3XXX_AXIS_Y] = -temp; + } + //printk("%s:%d %d %d\n",__FUNCTION__,raw_data[0],raw_data[1],raw_data[2]); + acc[MC3XXX_AXIS_X] = pCvt->sign[MC3XXX_AXIS_X] * raw_data[pCvt->map[MC3XXX_AXIS_X]]; + acc[MC3XXX_AXIS_Y] = pCvt->sign[MC3XXX_AXIS_Y] * raw_data[pCvt->map[MC3XXX_AXIS_Y]]; + acc[MC3XXX_AXIS_Z] = pCvt->sign[MC3XXX_AXIS_Z] * raw_data[pCvt->map[MC3XXX_AXIS_Z]]; + + return comres; +} + +//============================================================================= +static void mc3xxx_work_func(struct work_struct *work) +{ + struct mc3xxx_data *data = &l_sensorconfig;//container_of(work, struct mc3xxx_data, work); + //int ret = 0; + s16 raw[3] = { 0 }; + +#ifdef DOT_CALI + if( load_cali_flg > 0) + { + /* ret = mcube_read_cali_file(data->client); + + if(ret == 0) + load_cali_flg = ret; + else + load_cali_flg--; + + GSE_LOG("load_cali %d\n",ret); */ + MC3XXX_WriteCalibration(data->client,l_sensorconfig.offset); + load_cali_flg = 0; + } +#endif +#if 1 +//gsensor not use when resume + if(wake_mc3xxx_flg==1){ + wake_mc3xxx_flg=0; + + + mc3xxx_chip_init(data->client); + MC3XXX_ResetCalibration(data->client); + + MC3XXX_WriteCalibration(data->client,l_sensorconfig.offset); + /*ret =mcube_read_cali_file(data->client); + if(ret !=0) + printk("*load_cali %d\n",ret); */ + } +#endif + + mc3xxx_read_accel_xyz(data->client, &raw[0]); + //printk("%s:%d %d %d\n",__FUNCTION__,raw[0],raw[1],raw[2]); + input_report_abs(data->input_dev, ABS_X, raw[0]); + input_report_abs(data->input_dev, ABS_Y, raw[1]); + input_report_abs(data->input_dev, ABS_Z, raw[2]); + input_sync(data->input_dev); + + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); +} +/* +//============================================================================= +static enum hrtimer_restart mc3xxx_timer_func(struct hrtimer *timer) +{ + struct mc3xxx_data *data = container_of(timer, struct mc3xxx_data, timer); + + queue_work(data->mc3xxx_wq, &data->work); + + hrtimer_start(&data->timer, ktime_set(0, sensor_duration*1000000), HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} +*/ +//MCUBE_BACKUP_FILE +static void mcube_copy_file(const char *dstFilePath) +{ + int err =0; + initKernelEnv(); + + fd_file = openFile(dstFilePath,O_RDWR,0); + if (fd_file == NULL) + { + GSE_LOG("open %s fail\n",dstFilePath); + return; + } + + if ((err = writeFile(fd_file,backup_buf,64))>0) + GSE_LOG("buf:%s\n",backup_buf); + else + GSE_LOG("write file error %d\n",err); + + set_fs(oldfs); ; + closeFile(fd_file); + +} +//MCUBE_BACKUP_FILE + +extern int wmt_setsyspara(char *varname, char *varval); +static void update_var(void) +{ + char varbuf[64]; + int varlen; + + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + sprintf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + (pCvt->map[MC3XXX_AXIS_X]), + (pCvt->sign[MC3XXX_AXIS_X]), + (pCvt->map[MC3XXX_AXIS_Y]), + (pCvt->sign[MC3XXX_AXIS_Y]), + (pCvt->map[MC3XXX_AXIS_Z]), + (pCvt->sign[MC3XXX_AXIS_Z]), + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + + wmt_setsyspara("wmt.io.mc3230sensor",varbuf); +} + +static long wmt_mc3xxx_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + short enable = 0; + short delay = 0; + unsigned int temp; + + switch (cmd){ + + case ECS_IOCTL_APP_SET_AFLAG: + // enable/disable sensor + if (copy_from_user(&enable, (short*)arg, sizeof(short))) + { + errlog("Can't get enable flag!!!\n"); + return -EFAULT; + } + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor. l_sensorconfig.sensor_samp=%d\n", enable, l_sensorconfig.sensor_samp); + + if (enable != l_sensorconfig.sensor_enable) + { + + l_sensorconfig.sensor_enable = enable; + + } + } else { + errlog("Wrong enable argument!!!\n"); + return -EFAULT; + } + break; + case ECS_IOCTL_APP_SET_DELAY://IOCTL_SENSOR_SET_DELAY_ACCEL: + // set the rate of g-sensor + if (copy_from_user(&delay,(short*)arg, sizeof(short))) + { + errlog("Can't get set delay!!!\n"); + return -EFAULT; + } + dbg("Get delay=%d \n", delay); + + if ((delay >=0) && (delay < 20)) + { + delay = 20; + } else if (delay > 200) + { + delay = 200; + } + if (delay > 0) + { + l_sensorconfig.sensor_samp = 1000/delay; + } else { + errlog("error delay argument(delay=%d)!!!\n",delay); + return -EFAULT; + } + + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + temp = MC3230_DRVID; + if (copy_to_user((unsigned int*)arg, &temp, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mc32x0_driver_id:%d\n",temp); + break; + case WMT_IOCTL_SENOR_GET_RESOLUTION: + if(Sensor_Accuracy &MCUBE_1_5G_8BIT){ + if(is_mc35xx) //mc3236:8 bit ,+/-2g + temp = (8<<8) | 4; + else + temp = (8<<8) | 3; //mc3230:8 bit ,+/-1.5g + + } + if (copy_to_user((unsigned int *)arg, &temp, sizeof(unsigned int))) + { + return -EFAULT; + } + printk("<<<<<<<resolution:0x%x\n",temp); + break; + default: + return -EINVAL; + break; + } + return 0; +} + + +static long mc3xxx_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + //int intBuf[SENSOR_DATA_SIZE] = { 0 }; + int ret = 0; + float convert_para = 0.0f; + + int prod = -1; + + +#ifdef DOT_CALI + void __user *data1 = NULL; + char strbuf[256] = { 0 }; + //int cali[3] = { 0 }; + SENSOR_DATA sensor_data = { 0 }; + struct i2c_client *client = container_of(mc3xxx_device.parent, struct i2c_client, dev); +#endif + + struct mc3xxx_data *data = NULL; + + data = i2c_get_clientdata(client); + + switch (cmd) { + + +/* case IOCTL_SENSOR_SET_DELAY_ACCEL: + if(copy_from_user((void *)&sensor_duration, (void __user *) arg, sizeof(short))!=0){ + printk("copy from error in %s.\n",__func__); + } + + break; + + case IOCTL_SENSOR_GET_DELAY_ACCEL: + if(copy_to_user((void __user *) arg, (const void *)&sensor_duration, sizeof(short))!=0){ + printk("copy to error in %s.\n",__func__); + } + + break; + + case IOCTL_SENSOR_GET_STATE_ACCEL: + if(copy_to_user((void __user *) arg, (const void *)&sensor_state_flag, sizeof(short))!=0){ + printk("copy to error in %s.\n",__func__); + } + + break; + + case IOCTL_SENSOR_SET_STATE_ACCEL: + if(copy_from_user((void *)&sensor_state_flag, (void __user *) arg, sizeof(short))!=0){ + printk("copy from error in %s.\n",__func__); + } + + break;*/ + case IOCTL_SENSOR_GET_NAME: + if(copy_to_user((void __user *) arg,(const void *)MC3XXX_DISPLAY_NAME, sizeof(MC3XXX_DISPLAY_NAME))!=0){ + printk("copy to error in %s.\n",__func__); + } + break; + + case IOCTL_SENSOR_GET_VENDOR: + if(copy_to_user((void __user *) arg,(const void *)MC3XXX_DIPLAY_VENDOR, sizeof(MC3XXX_DIPLAY_VENDOR))!=0){ + printk("copy to error in %s.\n",__func__); + } + break; + + case IOCTL_SENSOR_GET_CONVERT_PARA: + convert_para = MC3XXX_CONVERT_PARAMETER; + if(copy_to_user((void __user *) arg,(const void *)&convert_para,sizeof(float))!=0){ + printk("copy to error in %s.\n",__func__); + } + break; + +#ifdef DOT_CALI + case GSENSOR_IOCTL_READ_SENSORDATA: + case GSENSOR_IOCTL_READ_RAW_DATA: + //case GSENSOR_MCUBE_IOCTL_READ_RBM_DATA: + GSE_LOG("fwq GSENSOR_IOCTL_READ_RAW_DATA\n"); + + //mutex_lock(&data->lock); + MC3XXX_ReadRawData(client, strbuf); + //mutex_unlock(&data->lock); + + if (copy_to_user((void __user *) arg, &strbuf, strlen(strbuf)+1)) + { + printk("failed to copy sense data to user space."); + return -EFAULT; + } + break; + + case GSENSOR_MCUBE_IOCTL_SET_CALI: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_CALI!!\n"); + data1 = (void __user *)arg; + + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + if(copy_from_user(&sensor_data, data1, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + else + { + l_sensorconfig.offset[MC3XXX_AXIS_X] = sensor_data.x; + l_sensorconfig.offset[MC3XXX_AXIS_Y] = sensor_data.y; + l_sensorconfig.offset[MC3XXX_AXIS_Z] = sensor_data.z; + update_var(); + GSE_LOG("GSENSOR_MCUBE_IOCTL_SET_CALI %d %d %d %d %d %d!!\n", l_sensorconfig.offset[MC3XXX_AXIS_X], l_sensorconfig.offset[MC3XXX_AXIS_Y],l_sensorconfig.offset[MC3XXX_AXIS_Z] ,sensor_data.x, sensor_data.y ,sensor_data.z); + + //mutex_lock(&data->lock); + ret = MC3XXX_WriteCalibration(client, l_sensorconfig.offset); + //mutex_unlock(&data->lock); + } + break; + + case GSENSOR_IOCTL_CLR_CALI: + GSE_LOG("fwq GSENSOR_IOCTL_CLR_CALI!!\n"); + //mutex_lock(&data->lock); + l_sensorconfig.offset[0] = 0; + l_sensorconfig.offset[1] = 0; + l_sensorconfig.offset[2] = 0; + + update_var(); + ret = MC3XXX_ResetCalibration(client); + //mutex_unlock(&data->lock); + break; + + case GSENSOR_IOCTL_GET_CALI: + GSE_LOG("fwq mc3xxx GSENSOR_IOCTL_GET_CALI\n"); + + data1 = (unsigned char*)arg; + + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + + if((ret = MC3XXX_ReadCalibration(client,l_sensorconfig.offset))) + { + GSE_LOG("fwq mc3xxx MC3XXX_ReadCalibration error!!!!\n"); + break; + } + + sensor_data.x = l_sensorconfig.offset[MC3XXX_AXIS_X]; + sensor_data.y = l_sensorconfig.offset[MC3XXX_AXIS_Y]; + sensor_data.z = l_sensorconfig.offset[MC3XXX_AXIS_Z]; + + if(copy_to_user(data1, &sensor_data, sizeof(sensor_data))) + { + ret = -EFAULT; + break; + } + break; + + case GSENSOR_IOCTL_SET_CALI_MODE: + GSE_LOG("fwq mc3xxx GSENSOR_IOCTL_SET_CALI_MODE\n"); + break; + + case GSENSOR_MCUBE_IOCTL_READ_RBM_DATA: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_READ_RBM_DATA\n"); + data1 = (void __user *) arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + MC3XXX_ReadRBMData(client,(char *)&strbuf); + if(copy_to_user(data1, &strbuf, strlen(strbuf)+1)) + { + ret = -EFAULT; + break; + } + break; + case GSENSOR_MCUBE_IOCTL_SET_RBM_MODE: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_SET_RBM_MODE\n"); + //MCUBE_BACKUP_FILE + if(READ_FROM_BACKUP==true) + { + + //mcube_copy_file(CALIB_PATH); + + READ_FROM_BACKUP = false; + } + //MCUBE_BACKUP_FILE + //mutex_lock(&data->lock); + MC3XXX_rbm(client, 1); + //mutex_unlock(&data->lock); + break; + + case GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_CLEAR_RBM_MODE\n"); + //mutex_lock(&data->lock); + MC3XXX_rbm(client, 0); + //mutex_unlock(&data->lock); + break; + + case GSENSOR_MCUBE_IOCTL_REGISTER_MAP: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_REGISTER_MAP\n"); + MC3XXX_ReadRegMap(client, NULL); + break; + + case GSENSOR_MCUBE_IOCTL_READ_PRODUCT_ID: + GSE_LOG("fwq GSENSOR_MCUBE_IOCTL_READ_PRODUCT_ID\n"); + data1 = (void __user *) arg; + if(data1 == NULL) + { + ret = -EINVAL; + break; + } + + if (MC3XXX_RETCODE_SUCCESS != (prod = MC3XX0_ValidateSensorIC(s_bPCODE))) + GSE_LOG("Not mCube accelerometers!\n"); + + if(copy_to_user(data1, &prod, sizeof(prod))) + { + GSE_LOG("%s: read pcode fail to copy!\n", __func__); + return -EFAULT; + } + break; +#endif + + default: + ret = -EINVAL; + break; + } + + return ret; +} + + +static int mc3xxx_open(struct inode *inode, struct file *filp) +{ + return nonseekable_open(inode, filp); +} + +static int mc3xxx_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int wmt_mc3xxx_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int wmt_mc3xxx_release(struct inode *inode, struct file *filp) +{ + return 0; +} + + +//============================================================================= +static struct file_operations sensor_fops = +{ + .owner = THIS_MODULE, + .open = mc3xxx_open, + .release = mc3xxx_release, + .unlocked_ioctl = mc3xxx_ioctl, +}; + +static struct file_operations wmt_sensor_fops = +{ + .owner = THIS_MODULE, + .open = wmt_mc3xxx_open, + .release = wmt_mc3xxx_release, + .unlocked_ioctl = wmt_mc3xxx_ioctl, +}; + + + +static int sensor_writeproc( struct file *file, + const char *buffer, + unsigned long count, + void *data ) +{ + + //int inputval = -1; + int enable, sample = -1; + char tembuf[8]; + //unsigned int amsr = 0; + int test = 0; + + mutex_lock(&l_sensorconfig.lock); + memset(tembuf, 0, sizeof(tembuf)); + // get sensor level and set sensor level + if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg)) + { + // only set the dbg flag + } else if (sscanf(buffer, "samp=%d\n", &sample)) + { + if (sample > 0) + { + if (sample != l_sensorconfig.sensor_samp) + { + // should do sth + } + //printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr); + } else { + klog("Wrong sample argumnet of sensor.\n"); + } + } else if (sscanf(buffer, "enable=%d\n", &enable)) + { + if ((enable < 0) || (enable > 1)) + { + dbg("The argument to enable/disable g-sensor should be 0 or 1 !!!\n"); + } else if (enable != l_sensorconfig.sensor_enable) + { + //mma_enable_disable(enable); + l_sensorconfig.sensor_enable = enable; + } + } else if (sscanf(buffer, "sensor_test=%d\n", &test)) + { // for test begin + l_sensorconfig.test_pass = 0; + } else if (sscanf(buffer, "sensor_testend=%d\n", &test)) + { // Don nothing only to be compatible the before testing program + } + mutex_unlock(&l_sensorconfig.lock); + return count; +} + +static int sensor_readproc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len = sprintf(page, + "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n", + l_sensorconfig.test_pass, + l_sensorconfig.isdbg, + l_sensorconfig.sensor_samp, + l_sensorconfig.sensor_enable + ); + return len; +} + + +//#ifdef CONFIG_HAS_EARLYSUSPEND +static void mc3xxx_early_suspend(struct platform_device *pdev, pm_message_t state) +{ + /*struct mc3xxx_data *data = NULL; + + data = container_of(handler, struct mc3xxx_data, early_suspend); + + hrtimer_cancel(&data->timer);*/ + + cancel_delayed_work_sync(&l_sensorconfig.work); + mc3xxx_set_mode(l_sensorconfig.client,MC3XXX_STANDBY); +} + +//============================================================================= +static void mc3xxx_early_resume(struct platform_device *pdev) +{ + struct mc3xxx_data *data = &l_sensorconfig; + + wake_mc3xxx_flg =1; + //data = container_of(handler, struct mc3xxx_data, early_suspend); + + mc3xxx_set_mode(data->client,MC3XXX_WAKE); + + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); + //hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); +} +//#endif + +//============================================================================= +static struct miscdevice mc3xxx_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = SENSOR_NAME, + .fops = &sensor_fops, +}; + +static struct miscdevice mc3xxx_wmt_device = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "sensor_ctrl", + .fops = &wmt_sensor_fops, +}; + + + +/***************************************** + *** MC3XX0_ValidateSensorIC + *****************************************/ +static int MC3XX0_ValidateSensorIC(unsigned char bPCode) +{ + unsigned char _baOurSensorList[] = { MC3XXX_PCODE_3210 , MC3XXX_PCODE_3230 , + MC3XXX_PCODE_3250 , + MC3XXX_PCODE_3410 , MC3XXX_PCODE_3430 , + MC3XXX_PCODE_3410N, MC3XXX_PCODE_3430N, + MC3XXX_PCODE_3510B, MC3XXX_PCODE_3530B, + MC3XXX_PCODE_3510C, MC3XXX_PCODE_3530C + }; + + int _nSensorCount = (sizeof(_baOurSensorList) / sizeof(_baOurSensorList[0])); + int _nCheckIndex = 0; + + GSE_LOG("[%s] code to be verified: 0x%X, _nSensorCount: %d\n", __FUNCTION__, bPCode, _nSensorCount); + + for (_nCheckIndex = 0; _nCheckIndex < _nSensorCount; _nCheckIndex++) + { + if (_baOurSensorList[_nCheckIndex] == bPCode) + return (MC3XXX_RETCODE_SUCCESS); + } + + if (MC3XXX_PCODE_3530C == (bPCode | 0x0E)) + return (MC3XXX_RETCODE_SUCCESS); + + return (MC3XXX_RETCODE_ERROR_IDENTIFICATION); +} + +/***************************************** + *** _mc3xxx_i2c_auto_probe + *****************************************/ +static int _mc3xxx_i2c_auto_probe(struct i2c_client *client) +{ + unsigned char _baDataBuf[2] = {0}; + int _nProbeAddrCount = (sizeof(mc3xxx_i2c_auto_probe_addr) / sizeof(mc3xxx_i2c_auto_probe_addr[0])); + int _nCount = 0; + int _nCheckCount = 0; + + //GSE_FUN(); + + s_bPCODE = 0x00; + + for (_nCount = 0; _nCount < _nProbeAddrCount; _nCount++) + { + _nCheckCount = 0; + client->addr = mc3xxx_i2c_auto_probe_addr[_nCount]; + + //GSE_LOG("[%s] probing addr: 0x%X\n", __FUNCTION__, client->addr); + +_I2C_AUTO_PROBE_RECHECK_: + _baDataBuf[0] = MC3XXX_REG_PRODUCT_CODE; + if (0 > i2c_master_send(client, &(_baDataBuf[0]), 1)) + { + //GSE_ERR("ERR: addr: 0x%X fail to communicate-2!\n", client->addr); + continue; + } + + if (0 > i2c_master_recv(client, &(_baDataBuf[0]), 1)) + { + //GSE_ERR("ERR: addr: 0x%X fail to communicate-3!\n", client->addr); + continue; + } + + _nCheckCount++; + + //GSE_LOG("[%s][%d] addr: 0x%X ok to read REG(0x3B): 0x%X\n", __FUNCTION__, _nCheckCount, client->addr, _baDataBuf[0]); + + if (0x00 == _baDataBuf[0]) + { + if (1 == _nCheckCount) + { + MC3XXX_Reset(client); + goto _I2C_AUTO_PROBE_RECHECK_; + } + } + + if (MC3XXX_RETCODE_SUCCESS == MC3XX0_ValidateSensorIC(_baDataBuf[0])) + { + //GSE_LOG("[%s] addr: 0x%X confirmed ok to use.\n", __FUNCTION__, client->addr); + + s_bPCODE = _baDataBuf[0]; + + return (MC3XXX_RETCODE_SUCCESS); + } + } + + return (MC3XXX_RETCODE_ERROR_I2C); +} + + +//============================================================================= +//static int mc3xxx_probe(struct i2c_client *client, +// const struct i2c_device_id *id) +static int mc3xxx_probe(struct platform_device *pdev) +{ + int ret = 0; + //int product_code = 0; + struct mc3xxx_data *data = &l_sensorconfig; + struct i2c_client *client = l_sensorconfig.client; + + #ifdef DOT_CALI + load_cali_flg = 30; + #endif +/* + if (MC3XXX_RETCODE_SUCCESS != _mc3xxx_i2c_auto_probe(client)) + { + GSE_ERR("ERR: fail to probe mCube sensor!\n"); + goto err_check_functionality_failed; + } + + data = kzalloc(sizeof(struct mc3xxx_data), GFP_KERNEL); + if(data == NULL) + { + ret = -ENOMEM; + goto err_alloc_data_failed; + } +*/ + data->sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/); + if (data->sensor_proc != NULL) + { + data->sensor_proc->write_proc = sensor_writeproc; + data->sensor_proc->read_proc = sensor_readproc; + } + + data->mc3xxx_wq = create_singlethread_workqueue("mc3xxx_wq"); + if (!data->mc3xxx_wq ) + { + ret = -ENOMEM; + goto err_create_workqueue_failed; + } + INIT_DELAYED_WORK(&data->work, mc3xxx_work_func); + mutex_init(&data->lock); + + //sensor_duration = SENSOR_DURATION_DEFAULT; + //sensor_state_flag = 1; + + + data->client = client; + dev.client=client; + + i2c_set_clientdata(client, data); + + data->input_dev = input_allocate_device(); + if (!data->input_dev) { + ret = -ENOMEM; + goto exit_input_dev_alloc_failed; + } + + #ifdef DOT_CALI + MC3XXX_Reset(client); + #endif + + ret = mc3xxx_chip_init(client); + if (ret < 0) { + goto err_chip_init_failed; + } + + set_bit(EV_ABS, data->input_dev->evbit); + data->map[0] = G_0; + data->map[1] = G_1; + data->map[2] = G_2; + data->inv[0] = G_0_REVERSE; + data->inv[1] = G_1_REVERSE; + data->inv[2] = G_2_REVERSE; + + input_set_abs_params(data->input_dev, ABS_X, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Y, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + input_set_abs_params(data->input_dev, ABS_Z, -32*8, 32*8, INPUT_FUZZ, INPUT_FLAT); + + data->input_dev->name = "g-sensor"; + + ret = input_register_device(data->input_dev); + if (ret) { + goto exit_input_register_device_failed; + } + + mc3xxx_device.parent = &client->dev; + + ret = misc_register(&mc3xxx_device); + if (ret) { + goto exit_misc_device_register_failed; + } + + ret = misc_register(&mc3xxx_wmt_device); + if (ret) { + goto exit_misc_device_register_failed; + } + + ret = sysfs_create_group(&data->input_dev->dev.kobj, &mc3xxx_group); +/* + if (!data->use_irq){ + hrtimer_init(&data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + data->timer.function = mc3xxx_timer_func; + //hrtimer_start(&data->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } +*/ + +#ifdef CONFIG_HAS_EARLYSUSPEND + data->early_suspend.suspend = mc3xxx_early_suspend; + data->early_suspend.resume = mc3xxx_early_resume; + register_early_suspend(&data->early_suspend); +#endif + data->enabled = 1; + queue_delayed_work(data->mc3xxx_wq, &data->work, msecs_to_jiffies(sample_rate_2_memsec(data->sensor_samp))); + //strcpy(mc3xxx_on_off_str,"gsensor_int2"); + //gpio_set_one_pin_io_status(mc3xxx_pin_hd,0,mc3xxx_on_off_str); + + printk("mc3xxx probe ok \n"); + + return 0; +exit_misc_device_register_failed: +exit_input_register_device_failed: + input_free_device(data->input_dev); +err_chip_init_failed: +exit_input_dev_alloc_failed: + destroy_workqueue(data->mc3xxx_wq); +err_create_workqueue_failed: + kfree(data); +//err_alloc_data_failed: +//err_check_functionality_failed: + printk("mc3xxx probe failed \n"); + return ret; + +} + +//static int mc3xxx_remove(struct i2c_client *client) +static int mc3xxx_remove(struct platform_device *pdev) +{ + /*struct mc3xxx_data *data = i2c_get_clientdata(client); + + hrtimer_cancel(&data->timer); + input_unregister_device(data->input_dev); +// gpio_release(mc3xxx_pin_hd, 2); + misc_deregister(&mc3xxx_device); + sysfs_remove_group(&data->input_dev->dev.kobj, &mc3xxx_group); + kfree(data); + return 0;*/ + + if (NULL != l_sensorconfig.mc3xxx_wq) + { + cancel_delayed_work_sync(&l_sensorconfig.work); + flush_workqueue(l_sensorconfig.mc3xxx_wq); + destroy_workqueue(l_sensorconfig.mc3xxx_wq); + l_sensorconfig.mc3xxx_wq = NULL; + } + if (l_sensorconfig.sensor_proc != NULL) + { + remove_proc_entry(GSENSOR_PROC_NAME, NULL); + l_sensorconfig.sensor_proc = NULL; + } + misc_deregister(&mc3xxx_device); + misc_deregister(&mc3xxx_wmt_device); + sysfs_remove_group(&l_sensorconfig.input_dev->dev.kobj, &mc3xxx_group); + input_unregister_device(l_sensorconfig.input_dev); + return 0; +} + +//============================================================================= +/* +static void mc3xxx_shutdown(struct i2c_client *client) +{ + struct mc3xxx_data *data = i2c_get_clientdata(client); + + if(data->enabled) + mc3xxx_enable(data, 0); +} +*/ + +//============================================================================= + +static const struct i2c_device_id mc3xxx_id[] = +{ + { SENSOR_NAME, 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, mc3xxx_id); +/* +static struct i2c_driver mc3xxx_driver = +{ + .class = I2C_CLASS_HWMON, + + .driver = { + .owner = THIS_MODULE, + .name = SENSOR_NAME, + }, + .id_table = mc3xxx_id, + .probe = mc3xxx_probe, + .remove = mc3xxx_remove, + //.shutdown = mc3xxx_shutdown, +}; +*/ +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void) +{ + char varbuf[64]; + int n; + int varlen; + //int tmpoff[3] = {0}; + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + + pCvt = (struct mc3xx0_hwmsen_convert *)kzalloc(sizeof(struct mc3xx0_hwmsen_convert), GFP_KERNEL); + + if (wmt_getsyspara("wmt.io.mc3230.virtualz", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + //return -1; + } else { + sscanf(varbuf, "%d", &g_virtual_z); + + } + printk("%s g_virtual_z %d\n", __FUNCTION__, g_virtual_z); + memset(varbuf, 0, sizeof(varbuf)); + if (wmt_getsyspara("wmt.io.mc3230sensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; //open it for no env just,not insmod such module 2014-6-30 + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(pCvt->map[MC3XXX_AXIS_X]), + &(pCvt->sign[MC3XXX_AXIS_X]), + &(pCvt->map[MC3XXX_AXIS_Y]), + &(pCvt->sign[MC3XXX_AXIS_Y]), + &(pCvt->map[MC3XXX_AXIS_Z]), + &(pCvt->sign[MC3XXX_AXIS_Z]), + &(l_sensorconfig.offset[0]), + &(l_sensorconfig.offset[1]), + &(l_sensorconfig.offset[2]) + ); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + pCvt->map[MC3XXX_AXIS_X], + pCvt->sign[MC3XXX_AXIS_X], + pCvt->map[MC3XXX_AXIS_Y], + pCvt->sign[MC3XXX_AXIS_Y], + pCvt->map[MC3XXX_AXIS_Z], + pCvt->sign[MC3XXX_AXIS_Z], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + +static void mc3xxx_platform_release(struct device *device) +{ + return; +} + + +static struct platform_device mc3xxx_pdevice = { + .name = SENSOR_NAME, + .id = 0, + .dev = { + .release = mc3xxx_platform_release, + }, +}; + +static struct platform_driver mc3xxx_pdriver = { + .probe = mc3xxx_probe, + .remove = mc3xxx_remove, + .suspend = mc3xxx_early_suspend, + .resume = mc3xxx_early_resume, + //.shutdown = mc3xxx_shutdown, + .driver = { + .name = SENSOR_NAME, + }, +}; + + +static int __init mc3xxx_init(void) +{ + int ret = -1; + struct i2c_client *this_client; + printk("mc3xxx: init\n"); + + //ret = i2c_add_driver(&mc3xxx_driver); + + // parse g-sensor u-boot arg + ret = get_axisset(); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + + if (!(this_client = sensor_i2c_register_device(0, mc3xxx_i2c_auto_probe_addr[0], SENSOR_NAME))) + { + printk(KERN_ERR"Can't register gsensor i2c device!\n"); + return -1; + } + + if (MC3XXX_RETCODE_SUCCESS != _mc3xxx_i2c_auto_probe(this_client)) + { + GSE_ERR("ERR: fail to auto_probe mCube sensor!\n"); + sensor_i2c_unregister_device(this_client); + return -1; + } + + + l_sensorconfig.client = this_client; + + l_dev_class = class_create(THIS_MODULE, SENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&mc3xxx_pdevice))) + { + klog("Can't register mc3xxx platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&mc3xxx_pdriver)) != 0) + { + errlog("Can't register mc3xxx platform driver!!!\n"); + return ret; + } + + + return ret; +} + +static void __exit mc3xxx_exit(void) +{ + //i2c_del_driver(&mc3xxx_driver); +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&l_sensorconfig.earlysuspend); +#endif + platform_driver_unregister(&mc3xxx_pdriver); + platform_device_unregister(&mc3xxx_pdevice); + sensor_i2c_unregister_device(l_sensorconfig.client); + class_destroy(l_dev_class); +} + +//============================================================================= +module_init(mc3xxx_init); +module_exit(mc3xxx_exit); + +MODULE_DESCRIPTION("mc3xxx accelerometer driver"); +MODULE_AUTHOR("mCube-inc"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(SENSOR_DRIVER_VERSION); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile new file mode 100755 index 00000000..99ecc6a1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_mma7660
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := mma7660.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c new file mode 100755 index 00000000..f0a0b1ee --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.c @@ -0,0 +1,1052 @@ +#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <mach/hardware.h>
+#include "mma7660.h"
+
+
+//#define DEBUG 1
+
+#undef dbg
+
+//#if 0
+ #define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+ //#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+
+#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+
+ //#define dbg(format, arg...) printk(KERN_ALERT format, ## arg)
+
+
+//#else
+// #define dbg(format, arg...)
+//#endif
+
+/////////////////////Macro constant
+#define SENSOR_POLL_WAIT_TIME 1837
+#define MAX_FAILURE_COUNT 10
+#define MMA7660_ADDR 0x4C
+#define LAND_PORT_MASK 0x1C
+#define LAND_LEFT 0x1
+#define LAND_RIGHT 0x2
+#define PORT_INVERT 0x5
+#define PORT_NORMAL 0x6
+
+#define LANDSCAPE_LOCATION 0
+#define PORTRAIT_LOCATION 1
+
+#define SENSOR_UI_MODE 0
+#define SENSOR_GRAVITYGAME_MODE 1
+
+#define UI_SAMPLE_RATE 0xFC
+
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define GSENSOR_MAJOR 161 +#define GSENSOR_NAME "mma7660"
+#define GSENSOR_DRIVER_NAME "mma7660_drv"
+
+
+#define sin30_1000 500
+#define cos30_1000 866
+
+#define DISABLE 0
+#define ENABLE 1
+
+////////////////////////the rate of g-sensor/////////////////////////////////////////////
+#define SENSOR_DELAY_FASTEST 0
+#define SENSOR_DELAY_GAME 20
+#define SENSOR_DELAY_UI 60
+#define SENSOR_DELAY_NORMAL 200
+
+#define FASTEST_MMA_AMSR 0 // 120 samples/sec
+#define GAME_MMA_AMSR 1 // 1, (64, samples/sec)
+#define UI_MMA_AMSR 3 // 2, 3,4, (16, 8,32 samples/sec)
+#define NORMAL_MMA_AMSR 5 // 5, 6, 7 (4, 2, 1 samples/sec)
+
+/////////////////////////////////////////////////////////////////////////
+static int xyz_g_table[64] = {
+0,47,94,141,188,234,281,328,
+375,422,469,516,563,609,656,703,
+750,797,844,891,938,984,1031,1078,
+1125,1172,1219,1266,1313,1359,1406,1453,
+-1500,-1453,-1406,-1359,-1313,-1266,-1219,-1172,
+-1125,-1078,-1031,-984,-938,-891,-844,-797,
+-750,-703,-656,-609,-563,-516,-469,-422,
+-375,-328,-281,-234,-188,-141,-94,-47
+};
+
+static struct platform_device *this_pdev;
+
+static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +
+
+
+struct mma7660_config
+{
+ int op;
+ int int_gpio; //0-3
+ int xyz_axis[3][2]; // (axis,direction)
+ int rxyz_axis[3][2];
+ int irq;
+ struct proc_dir_entry* sensor_proc;
+ int sensorlevel;
+ int shake_enable; // 1--enable shake, 0--disable shake
+ int manual_rotation; // 0--landance, 90--vertical
+ struct input_dev *input_dev;
+ //struct work_struct work;
+ struct delayed_work work; // for polling
+ struct workqueue_struct *queue;
+ int isdbg; // 0-- no debug log, 1--show debug log
+ int sensor_samp; // 1,2,4,8,16,32,64,120
+ int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor
+ int test_pass;
+ spinlock_t spinlock;
+ int pollcnt; // the counts of polling
+ int offset[3];
+};
+
+static struct mma7660_config l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },
+ .irq = 6,
+ .int_gpio = 3,
+ .sensor_proc = NULL,
+ .sensorlevel = SENSOR_GRAVITYGAME_MODE,
+ .shake_enable = 0, // default enable shake
+ .isdbg = 0,
+ .sensor_samp = 10, // 4sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds
+ .offset = {0,0,0},
+};
+
+
+static struct timer_list l_polltimer; // for shaking
+static int is_sensor_good = 0; // 1-- work well, 0 -- exception
+struct work_struct poll_work;
+static struct mutex sense_data_mutex;
+static int revision = -1;
+static int l_resumed = 0; // 1: suspend --> resume;2: suspend but not resumed; other values have no meaning
+
+//////////////////Macro function//////////////////////////////////////////////////////
+
+#define SET_MMA_SAMPLE(buf,samp) { \
+ buf[0] = 0; \
+ sensor_i2c_write(MMA7660_ADDR,7,buf,1); \
+ buf[0] = samp; \
+ sensor_i2c_write(MMA7660_ADDR,8,buf,1); \
+ buf[0] = 0x01; \
+ sensor_i2c_write(MMA7660_ADDR,7,buf,1); \
+}
+
+////////////////////////Function define/////////////////////////////////////////////////////////
+
+static unsigned int mma_sample2AMSR(unsigned int samp);
+
+////////////////////////Function implement/////////////////////////////////////////////////
+// rate: 1,2,4,8,16,32,64,120
+static unsigned int sample_rate_2_memsec(unsigned int rate)
+{
+ return (1000/rate);
+}
+
+
+
+static ssize_t gsensor_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ sprintf(buf, "MMA7660_%#x\n", revision);
+ ret = strlen(buf) + 1;
+
+ return ret;
+}
+
+static DEVICE_ATTR(vendor, 0444, gsensor_vendor_show, NULL);
+
+static struct kobject *android_gsensor_kobj;
+static int gsensor_sysfs_init(void)
+{
+ int ret ;
+
+ android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL);
+ if (android_gsensor_kobj == NULL) {
+ printk(KERN_ERR
+ "mma7660 gsensor_sysfs_init:"\
+ "subsystem_register failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_vendor.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "mma7660 gsensor_sysfs_init:"\
+ "sysfs_create_group failed\n");
+ goto err4;
+ }
+
+ return 0 ;
+err4:
+ kobject_del(android_gsensor_kobj);
+err:
+ return ret ;
+}
+
+static int gsensor_sysfs_exit(void)
+{
+ sysfs_remove_file(android_gsensor_kobj, &dev_attr_vendor.attr);
+ kobject_del(android_gsensor_kobj);
+ return 0;
+}
+
+//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id);
+extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size);
+extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size);
+
+int sensor_i2c_write(unsigned int addr,unsigned int index,char *pdata,int len)
+{
+ /*struct i2c_msg msg[1];
+ unsigned char buf[len+1];
+
+ //addr = (addr >> 1);
+ buf[0] = index;
+ memcpy(&buf[1],pdata,len);
+ msg[0].addr = addr;
+ msg[0].flags = 0 ;
+ msg[0].flags &= ~(I2C_M_RD);
+ msg[0].len = len+1;
+ msg[0].buf = buf;
+//tmp sensor_i2c_do_xfer(msg,1);
+ if (wmt_i2c_xfer_continue_if_4(msg,1,0) <= 0)
+ {
+ klog("write error!\n");
+ return -1;
+ }*/
+ int ret;
+ ret = i2c_api_do_send(0, addr, index, pdata, len);
+ if (ret <= 0) {
+ klog("i2c_api_do_send error!\n");
+ return -1;
+ }
+
+#ifdef DEBUG
+{
+ int i;
+
+ printk("sensor_i2c_write(addr 0x%x,index 0x%x,len %d\n",addr,index,len);
+ for(i=0;i<len;i+=8){
+ printk("%d : 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",i,
+ pdata[i],pdata[i+1],pdata[i+2],pdata[i+3],pdata[i+4],pdata[i+5],pdata[i+6],pdata[i+7]);
+ }
+}
+#endif
+ return 0;
+} /* End of sensor_i2c_write */
+
+int sensor_i2c_read(unsigned int addr,unsigned int index,char *pdata,int len)
+{
+ /*struct i2c_msg msg[2];
+ unsigned char buf[len+1];
+ int ret = 0;
+
+ //addr = (addr >> 1);
+ memset(buf,0x55,len+1);
+ buf[0] = index;
+ buf[1] = 0x0;
+
+ msg[0].addr = addr;
+ msg[0].flags = 0 ;
+ msg[0].flags &= ~(I2C_M_RD);
+ msg[0].len = 1;
+ msg[0].buf = buf;
+
+ msg[1].addr = addr;
+ msg[1].flags = 0 ;
+ msg[1].flags |= (I2C_M_RD);
+ msg[1].len = len;
+ msg[1].buf = buf;
+
+ //tmp sensor_i2c_do_xfer(msg, 2);
+ ret = wmt_i2c_xfer_continue_if_4(msg, 2,0);
+ if (ret < 0)
+ {
+ klog("read error!\n");
+ return ret;
+ }
+
+ memcpy(pdata,buf,len);*/
+ int ret;
+ ret = i2c_api_do_recv(0, addr, index, pdata, len);
+ if (ret <= 0) {
+ klog("i2c_api_do_recv error!\n");
+ return -1;
+ }
+#ifdef DEBUG
+{
+ int i;
+
+ printk("sensor_i2c_read(addr 0x%x,index 0x%x,len %d\n",addr,index,len);
+ for(i=0;i<len;i+=8){
+ printk("%d : 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",i,
+ pdata[i],pdata[i+1],pdata[i+2],pdata[i+3],pdata[i+4],pdata[i+5],pdata[i+6],pdata[i+7]);
+ }
+}
+#endif
+ return 0;
+} /* End of sensor_i2c_read */
+
+void mma7660_chip_init(void)
+{
+ char txData[1];
+ char amsr = 0;
+
+ // the default mode is for UI
+ txData[0]=0;
+ sensor_i2c_write(MMA7660_ADDR,7,txData,1);
+ txData[0] = 0;
+ sensor_i2c_write(MMA7660_ADDR,5,txData,1);
+ //txData[0] = (1 == l_sensorconfig.shake_enable) ? 0xF0:0x10;
+ txData[0] = 0; // disable all int ,for polling
+ sensor_i2c_write(MMA7660_ADDR,6,txData,1);
+ amsr = 0;// 8 - i;
+ txData[0] = 0xF8 | amsr;
+ dbg("G-Sensor: SR = 0x%X\n", txData[0]);
+ sensor_i2c_write(MMA7660_ADDR,8,txData,1);
+ txData[0] = 0x01; // for polling
+ sensor_i2c_write(MMA7660_ADDR,7,txData,1);
+ return;
+}
+
+static unsigned int mma_sample2AMSR(unsigned int samp)
+{
+ int i = 0;
+ unsigned int amsr;
+
+ if (samp >= 120)
+ {
+ return 0;
+ }
+ while (samp)
+ {
+ samp = samp >> 1;
+ i++;
+ }
+ amsr = 8 - i;
+ return amsr;
+}
+
+static int mma_enable_disable(int enable)
+{
+ char buf[1];
+
+ // disable all interrupt of g-sensor
+ memset(buf, 0, sizeof(buf));
+ if ((enable < 0) || (enable > 1))
+ {
+ return -1;
+ }
+ buf[0] = 0;
+ sensor_i2c_write(MMA7660_ADDR,7,buf,1);
+ if (enable != 0)
+ {
+ buf[0] = (1 == l_sensorconfig.shake_enable) ? 0xF0:0x10;
+ } else {
+ buf[0] = 0;
+ }
+ sensor_i2c_write(MMA7660_ADDR,6,buf,1);
+ buf[0] = 0xf9;
+ sensor_i2c_write(MMA7660_ADDR,7,buf,1);
+ return 0;
+}
+
+// To contol the g-sensor for UI
+static int mmad_open(struct inode *inode, struct file *file)
+{
+ dbg("Open the g-sensor node...\n");
+ return 0;
+}
+
+static int mmad_release(struct inode *inode, struct file *file)
+{
+ dbg("Close the g-sensor node...\n");
+ return 0;
+}
+
+static /*int*/ long
+mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ char rwbuf[5];
+ short delay, enable; //amsr = -1;
+ unsigned int uval = 0;
+ int i = 0;
+ unsigned char rxData[3] = {0};
+ int intBuf[3] = {0};
+ dbg("g-sensor ioctr...\n");
+ memset(rwbuf, 0, sizeof(rwbuf));
+ switch (cmd) {
+ case ECS_IOCTL_APP_SET_DELAY:
+ // set the rate of g-sensor
+ if (copy_from_user(&delay, argp, sizeof(short)))
+ {
+ printk(KERN_ALERT "Can't get set delay!!!\n");
+ return -EFAULT;
+ }
+ klog("Get delay=%d\n", delay);
+ //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp);
+ if ((delay >=0) && (delay < 20))
+ {
+ delay = 20;
+ } else if (delay > 200)
+ {
+ delay = 200;
+ }
+ l_sensorconfig.sensor_samp = 1000/delay;
+
+ break;
+ case ECS_IOCTL_APP_SET_AFLAG:
+ // enable/disable sensor
+ if (copy_from_user(&enable, argp, sizeof(short)))
+ {
+ printk(KERN_ERR "Can't get enable flag!!!\n");
+ return -EFAULT;
+ }
+ klog("enable=%d\n",enable);
+ if ((enable >=0) && (enable <=1))
+ {
+ dbg("driver: disable/enable(%d) gsensor.\n", enable);
+
+ l_sensorconfig.sensor_enable = enable;
+
+ } else {
+ printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ break;
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = MMA7660_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ dbg("mma7660_driver_id:%d\n",uval);
+ break;
+ case ECS_IOCTL_APP_READ_XYZ:
+ sensor_i2c_read(MMA7660_ADDR,0,rxData,3);
+
+ for (i=0; i < 3; i++)
+ {
+ if (rxData[i]&0x40) break;
+ }
+ //if (l_sensorconfig.pollcnt >= 20)
+ if (3 == i)
+ {
+ intBuf[0] = xyz_g_table[rxData[l_sensorconfig.xyz_axis[0][0]]]*l_sensorconfig.xyz_axis[0][1];
+ intBuf[1] = xyz_g_table[rxData[l_sensorconfig.xyz_axis[1][0]]]*l_sensorconfig.xyz_axis[1][1];
+ intBuf[2] = xyz_g_table[rxData[l_sensorconfig.xyz_axis[2][0]]]*l_sensorconfig.xyz_axis[2][1];
+
+ if (copy_to_user((unsigned int*)arg, intBuf, sizeof(intBuf)))
+ {
+ return -EFAULT;
+ }
+ }
+ break;
+ }
+
+
+
+ return 0;
+}
+
+
+static void mma_work_func(struct work_struct *work)
+{
+ struct mma7660_config *data;
+ unsigned char rxData[3];
+ //unsigned char tiltval = 0;
+ int i = 0;
+ int x,y,z;
+
+ dbg("enter...\n");
+ data = dev_get_drvdata(&this_pdev->dev);
+ if (!l_sensorconfig.sensor_enable)
+ {
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+ return;
+ }
+ mutex_lock(&sense_data_mutex);
+ is_sensor_good = 1; // for watchdog
+ l_sensorconfig.test_pass = 1; // for testing
+
+ /*sensor_i2c_read(MMA7660_ADDR,3,rxData,1);
+ tiltval = rxData[0];
+ if (tiltval & 0x80) {
+ if (1 == l_sensorconfig.shake_enable) {
+ printk(KERN_NOTICE "shake!!!\n");
+ input_report_key(data->input_dev, KEY_NEXTSONG, 1);
+ input_report_key(data->input_dev, KEY_NEXTSONG, 0);
+ input_sync(data->input_dev);
+
+ }
+ } else*/ {
+ sensor_i2c_read(MMA7660_ADDR,0,rxData,3);
+ /* dbg(KERN_DEBUG "Angle: x=%d, y=%d, z=%d\n",
+ xy_degree_table[rxData[0]],
+ xy_degree_table[rxData[1]],
+ z_degree_table[rxData[2]]);
+ dbg(KERN_DEBUG "G value: x=%d, y=%d, z=%d\n",
+ xyz_g_table[rxData[0]],
+ xyz_g_table[rxData[1]],
+ xyz_g_table[rxData[2]]);
+ */
+ for (i=0; i < 3; i++)
+ {
+ if (rxData[i]&0x40) break;
+ }
+ //if (l_sensorconfig.pollcnt >= 20)
+ if (3 == i)
+ {
+ x = xyz_g_table[rxData[l_sensorconfig.xyz_axis[0][0]]]*l_sensorconfig.xyz_axis[0][1];
+ y = xyz_g_table[rxData[l_sensorconfig.xyz_axis[1][0]]]*l_sensorconfig.xyz_axis[1][1];
+ z = xyz_g_table[rxData[l_sensorconfig.xyz_axis[2][0]]]*l_sensorconfig.xyz_axis[2][1];
+ input_report_abs(data->input_dev, ABS_X, x);
+ input_report_abs(data->input_dev, ABS_Y, y);
+ input_report_abs(data->input_dev, ABS_Z, z);
+ input_sync(data->input_dev);
+ dbg("gx=%x,gy=%x,gz=%x\n",x,y,z);
+ }
+ }
+ //gsensor_int_ctrl(ENABLE);
+ mutex_unlock(&sense_data_mutex);
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+}
+
+static int sensor_writeproc( struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data )
+{
+
+ int inputval = -1;
+ int enable, sample = -1;
+ char tembuf[8];
+ unsigned int amsr = 0;
+ int test = 0;
+
+ mutex_lock(&sense_data_mutex);
+ // disable int
+ //gsensor_int_ctrl(DISABLE);
+ memset(tembuf, 0, sizeof(tembuf));
+ // get sensor level and set sensor level
+ if (sscanf(buffer, "level=%d\n", &l_sensorconfig.sensorlevel))
+ {
+ } else if (sscanf(buffer, "shakenable=%d\n", &l_sensorconfig.shake_enable))
+ {
+ /*
+ regval[0] = 0;
+ sensor_i2c_write(MMA7660_ADDR,7,regval,1); // standard mode
+ sensor_i2c_read(MMA7660_ADDR,6,regval,1);
+ switch (l_sensorconfig.shake_enable)
+ {
+ case 0: // disable shake
+ regval[0] &= 0x1F;
+ sensor_i2c_write(MMA7660_ADDR,6, regval,1);
+ dbg("Shake disable!!\n");
+ break;
+ case 1: // enable shake
+ regval[0] |= 0xE0;
+ sensor_i2c_write(MMA7660_ADDR,6, regval,1);
+ dbg("Shake enable!!\n");
+ break;
+ };
+ sensor_i2c_write(MMA7660_ADDR,7,&oldval,1);
+ */
+ } /*else if (sscanf(buffer, "rotation=%d\n", &l_sensorconfig.manual_rotation))
+ {
+ switch (l_sensorconfig.manual_rotation)
+ {
+ case 90:
+ // portrait
+ input_report_abs(mma7660data->input_dev, ABS_X, cos30_1000);
+ input_report_abs(mma7660data->input_dev, ABS_Y, 0);
+ input_report_abs(mma7660data->input_dev, ABS_Z, sin30_1000);
+ input_sync(mma7660data->input_dev);
+ break;
+ case 0:
+ // landscape
+ input_report_abs(mma7660data->input_dev, ABS_X, 0);
+ input_report_abs(mma7660data->input_dev, ABS_Y, cos30_1000);
+ input_report_abs(mma7660data->input_dev, ABS_Z, sin30_1000);
+ input_sync(mma7660data->input_dev);
+ break;
+ };
+ }*/ else if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg))
+ {
+ // only set the dbg flag
+ } else if (sscanf(buffer, "init=%d\n", &inputval))
+ {
+ mma7660_chip_init();
+ dbg("Has reinit sensor !!!\n");
+ } else if (sscanf(buffer, "samp=%d\n", &sample))
+ {
+ if (sample > 0)
+ {
+ if (sample != l_sensorconfig.sensor_samp)
+ {
+ amsr = mma_sample2AMSR(sample);
+ SET_MMA_SAMPLE(tembuf, amsr);
+ klog("sample:%d ,amsr:%d \n", sample, amsr);
+ l_sensorconfig.sensor_samp = sample;
+ }
+ printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr);
+ } else {
+ printk(KERN_ALERT "Wrong sample argumnet of sensor.\n");
+ }
+ } else if (sscanf(buffer, "enable=%d\n", &enable))
+ {
+ if ((enable < 0) || (enable > 1))
+ {
+ printk(KERN_ERR "The argument to enable/disable g-sensor should be 0 or 1 !!!\n");
+ } else if (enable != l_sensorconfig.sensor_enable)
+ {
+ mma_enable_disable(enable);
+ l_sensorconfig.sensor_enable = enable;
+ }
+ } else if (sscanf(buffer, "sensor_test=%d\n", &test))
+ { // for test begin
+ l_sensorconfig.test_pass = 0;
+ } else if (sscanf(buffer, "sensor_testend=%d\n", &test))
+ { // Don nothing only to be compatible the before testing program
+ }
+ mutex_unlock(&sense_data_mutex);
+ return count;
+}
+
+static int sensor_readproc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len = sprintf(page,
+ "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n",
+ l_sensorconfig.test_pass,
+ l_sensorconfig.isdbg,
+ l_sensorconfig.sensor_samp,
+ l_sensorconfig.sensor_enable
+ );
+ return len;
+}
+
+
+
+static int mma7660_init_client(struct platform_device *pdev)
+{
+ struct mma7660_config *data;
+// int ret;
+
+ data = dev_get_drvdata(&pdev->dev);
+ mutex_init(&sense_data_mutex);
+ /*Only for polling, not interrupt*/
+ l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/);
+ if (l_sensorconfig.sensor_proc != NULL)
+ {
+ l_sensorconfig.sensor_proc->write_proc = sensor_writeproc;
+ l_sensorconfig.sensor_proc->read_proc = sensor_readproc;
+ }
+
+
+ return 0;
+
+//err:
+// return ret;
+}
+
+static struct file_operations mmad_fops = {
+ .owner = THIS_MODULE,
+ .open = mmad_open,
+ .release = mmad_release,
+ .unlocked_ioctl = mmad_ioctl,
+};
+
+
+static struct miscdevice mmad_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sensor_ctrl",
+ .fops = &mmad_fops,
+};
+
+static int mma7660_probe(
+ struct platform_device *pdev)
+{
+ int err;
+
+ this_pdev = pdev;
+ l_sensorconfig.queue = create_singlethread_workqueue("sensor-intterupt-handle");
+ INIT_DELAYED_WORK(&l_sensorconfig.work, mma_work_func);
+
+ l_sensorconfig.input_dev = input_allocate_device();
+ if (!l_sensorconfig.input_dev) {
+ err = -ENOMEM;
+ printk(KERN_ERR
+ "mma7660_probe: Failed to allocate input device\n");
+ goto exit_input_dev_alloc_failed;
+ }
+ l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY);
+ set_bit(KEY_NEXTSONG, l_sensorconfig.input_dev->keybit);
+
+ /* x-axis acceleration */
+ input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -65532, 65532, 0, 0);
+ /* y-axis acceleration */
+ input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -65532, 65532, 0, 0);
+ /* z-axis acceleration */
+ input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -65532, 65532, 0, 0);
+
+ l_sensorconfig.input_dev->name = "g-sensor";
+
+ err = input_register_device(l_sensorconfig.input_dev);
+
+ if (err) {
+ printk(KERN_ERR
+ "mma7660_probe: Unable to register input device: %s\n",
+ l_sensorconfig.input_dev->name);
+ goto exit_input_register_device_failed;
+ }
+
+ err = misc_register(&mmad_device);
+ if (err) {
+ printk(KERN_ERR
+ "mma7660_probe: mmad_device register failed\n");
+ goto exit_misc_device_register_failed;
+ }
+
+ dev_set_drvdata(&pdev->dev, &l_sensorconfig);
+ mma7660_chip_init();
+ mma7660_init_client(pdev);
+ gsensor_sysfs_init();
+
+ // satrt the polling work
+ l_sensorconfig.sensor_samp = 10;
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+ return 0;
+
+exit_misc_device_register_failed:
+exit_input_register_device_failed:
+ input_free_device(l_sensorconfig.input_dev);
+//exit_alloc_data_failed:
+exit_input_dev_alloc_failed:
+//exit_check_functionality_failed:
+ return err;
+}
+
+static int mma7660_remove(struct platform_device *pdev)
+{
+ if (NULL != l_sensorconfig.queue)
+ {
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+ flush_workqueue(l_sensorconfig.queue);
+ destroy_workqueue(l_sensorconfig.queue);
+ l_sensorconfig.queue = NULL;
+ }
+ gsensor_sysfs_exit();
+ misc_deregister(&mmad_device);
+ input_unregister_device(l_sensorconfig.input_dev);
+ if (l_sensorconfig.sensor_proc != NULL)
+ {
+ remove_proc_entry(GSENSOR_PROC_NAME, NULL);
+ l_sensorconfig.sensor_proc = NULL;
+ }
+ //free_irq(l_sensorconfig.irq, &l_sensorconfig);
+ return 0;
+}
+
+static int mma7660_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ //gsensor_int_ctrl(DISABLE);
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+ del_timer(&l_polltimer);
+ dbg("...ok\n");
+ //l_resumed = 2;
+
+ return 0;
+}
+
+static int mma7660_resume(struct platform_device *pdev)
+{
+
+ //mma7660_chip_init();
+ //gsensor_int_ctrl(ENABLE);
+ //mma_enable_disable(1);
+ l_resumed = 1;
+ mod_timer(&l_polltimer, jiffies + msecs_to_jiffies(SENSOR_POLL_WAIT_TIME));
+ dbg("...ok\n");
+
+ return 0;
+}
+
+static void mma7660_platform_release(struct device *device)
+{
+ return;
+}
+
+static void mma7660_shutdown(struct platform_device *pdev)
+{
+
+ flush_delayed_work_sync(&l_sensorconfig.work);
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+
+}
+
+static struct platform_device mma7660_device = {
+ .name = "mma7660",
+ .id = 0,
+ .dev = {
+ .release = mma7660_platform_release,
+ },
+};
+
+static struct platform_driver mma7660_driver = {
+ .probe = mma7660_probe,
+ .remove = mma7660_remove,
+ .suspend = mma7660_suspend,
+ .resume = mma7660_resume,
+ .shutdown = mma7660_shutdown,
+ .driver = {
+ .name = "mma7660",
+ },
+};
+
+/*
+ * Brief:
+ * Get the configure of sensor from u-boot.
+ * Input:
+ * no use.
+ * Output:
+ * no use.
+ * Return:
+ * 0--success, -1--error.
+ * History:
+ * Created by HangYan on 2010-4-19
+ * Author:
+ * Hang Yan in ShenZhen.
+ */
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static int get_axisset(void* param)
+{
+ char varbuf[64];
+ int n;
+ int varlen;
+
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+ if (wmt_getsyspara("wmt.io.mma7660gsensor", varbuf, &varlen)) {
+ printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n");
+ return -1;
+ } else {
+ n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &l_sensorconfig.op,
+ &(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]),
+ &(l_sensorconfig.offset[0]),
+ &(l_sensorconfig.offset[1]),
+ &(l_sensorconfig.offset[2]));
+ if (n != 10) {
+ printk(KERN_ERR "gsensor format is error in u-boot!!!\n");
+ return -1;
+ }
+
+ dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ l_sensorconfig.op,
+ 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],
+ l_sensorconfig.offset[0],
+ l_sensorconfig.offset[1],
+ l_sensorconfig.offset[2]
+ );
+ }
+ return 0;
+}
+
+
+// Add one timer to reinit sensor every 5s
+static void sensor_polltimer_timeout(unsigned long timeout)
+{
+ schedule_work(&poll_work);
+}
+
+static void poll_work_func(struct work_struct *work)
+{
+ char rxData[1];
+
+ //mutex_lock(&sense_data_mutex);
+ if (l_sensorconfig.pollcnt != 20)
+ {
+ l_sensorconfig.pollcnt++;
+ }
+ dbg("read to work!\n");
+ //spin_lock(&l_sensorconfig.spinlock);
+ mutex_lock(&sense_data_mutex);
+ if (1 == l_resumed)
+ {
+ mma7660_chip_init();
+ //gsensor_int_ctrl(ENABLE);
+ //mma_enable_disable(1);
+ dbg("reinit for resume...\n");
+ l_resumed = 0;
+ //spin_unlock(&l_sensorconfig.spinlock);
+ mutex_unlock(&sense_data_mutex);
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+
+ return;
+ }
+ //spin_unlock(&l_sensorconfig.spinlock);
+ mutex_unlock(&sense_data_mutex);
+ if (!is_sensor_good)
+ {
+ //mma7660_chip_init();
+ // if ic is blocked then wake g-sensor
+ sensor_i2c_read(MMA7660_ADDR,3,rxData,1);
+ } else {
+ is_sensor_good = 0;
+ }
+
+ //mutex_unlock(&sense_data_mutex);
+ mod_timer(&l_polltimer, jiffies + msecs_to_jiffies(SENSOR_POLL_WAIT_TIME));
+
+}
+
+static int mma7660_open(struct inode *inode, struct file *file)
+{ + return 0;
+} + +static int mma7660_release(struct inode *inode, struct file *file)
+{ + return 0; +} +
+
+static struct file_operations mma7660_fops = {
+ .owner = THIS_MODULE, + .open = mma7660_open,
+ .release = mma7660_release,
+};
+
+static int is_mma7660(void)
+{
+ char txData[2];
+ int i = 0;
+
+ txData[1] = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if(sensor_i2c_write(MMA7660_ADDR,7,txData,1) == 0)
+ {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int __init mma7660_init(void)
+{
+ int ret = 0;
+
+ if (is_mma7660())
+ {
+ printk(KERN_ERR "Can't find mma7660!!\n");
+ return -1;
+ }
+ ret = get_axisset(NULL); // get gsensor config from u-boot
+ if (ret < 0)
+ {
+ printk("<<<<<%s user choose to no sensor chip!\n", __func__);
+ return ret;
+ }
+ /*if ((ret != 0) || !l_sensorconfig.op)
+ return -EINVAL;*/
+
+
+ printk(KERN_INFO "mma7660fc g-sensor driver init\n");
+
+ spin_lock_init(&l_sensorconfig.spinlock);
+ INIT_WORK(&poll_work, poll_work_func);
+ // Create device node + if (register_chrdev (GSENSOR_MAJOR, GSENSOR_NAME, &mma7660_fops)) {
+ printk (KERN_ERR "unable to get major %d\n", GSENSOR_MAJOR);
+ return -EIO; + } + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, GSENSOR_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",GSENSOR_NAME); + return ret; + } +
+ if((ret = platform_device_register(&mma7660_device)))
+ {
+ printk(KERN_ERR "%s Can't register mma7660 platform devcie!!!\n", __FUNCTION__);
+ return ret;
+ }
+ if ((ret = platform_driver_register(&mma7660_driver)) != 0)
+ {
+ printk(KERN_ERR "%s Can't register mma7660 platform driver!!!\n", __FUNCTION__);
+ return ret;
+ }
+
+ setup_timer(&l_polltimer, sensor_polltimer_timeout, 0);
+ mod_timer(&l_polltimer, jiffies + msecs_to_jiffies(SENSOR_POLL_WAIT_TIME));
+ is_sensor_good = 1;
+
+ return 0;
+}
+
+static void __exit mma7660_exit(void)
+{
+ del_timer(&l_polltimer);
+ platform_driver_unregister(&mma7660_driver);
+ platform_device_unregister(&mma7660_device);
+ device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0));
+ unregister_chrdev(GSENSOR_MAJOR, GSENSOR_NAME); + class_destroy(l_dev_class); +
+}
+
+module_init(mma7660_init);
+module_exit(mma7660_exit);
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h new file mode 100755 index 00000000..db6c06c0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma7660_gsensor/mma7660.h @@ -0,0 +1,106 @@ +/*
+ * Definitions for akm8976 compass chip.
+ */
+#ifndef AKM8976_H
+#define AKM8976_H
+
+#include <linux/ioctl.h>
+
+/* Compass device dependent definition */
+#define AKECS_MODE_MEASURE 0x00 /* Starts measurement. Please use AKECS_MODE_MEASURE_SNG */
+ /* or AKECS_MODE_MEASURE_SEQ instead of this. */
+#define AKECS_MODE_PFFD 0x01 /* Start pedometer and free fall detect. */
+#define AKECS_MODE_E2P_READ 0x02 /* E2P access mode (read). */
+#define AKECS_MODE_POWERDOWN 0x03 /* Power down mode */
+
+#define AKECS_MODE_MEASURE_SNG 0x10 /* Starts single measurement */
+#define AKECS_MODE_MEASURE_SEQ 0x11 /* Starts sequential measurement */
+
+/* Default register settings */
+#define CSPEC_AINT 0x01 /* Amplification for acceleration sensor */
+#define CSPEC_SNG_NUM 0x01 /* Single measurement mode */
+#define CSPEC_SEQ_NUM 0x02 /* Sequential measurement mode */
+#define CSPEC_SFRQ_32 0x00 /* Measurement frequency: 32Hz */
+#define CSPEC_SFRQ_64 0x01 /* Measurement frequency: 64Hz */
+#define CSPEC_MCS 0x07 /* Clock frequency */
+#define CSPEC_MKS 0x01 /* Clock type: CMOS level */
+#define CSPEC_INTEN 0x01 /* Interruption pin enable: Enable */
+
+#define RBUFF_SIZE 31 /* Rx buffer size */
+#define MAX_CALI_SIZE 0x1000U /* calibration buffer size */
+
+/* AK8976A register address */
+#define AKECS_REG_ST 0xC0
+#define AKECS_REG_TMPS 0xC1
+#define AKECS_REG_MS1 0xE0
+#define AKECS_REG_MS2 0xE1
+#define AKECS_REG_MS3 0xE2
+
+#define AKMIO 0xA1
+
+/* IOCTLs for AKM library */
+#define ECS_IOCTL_RESET _IO(AKMIO, 0x04)
+#define ECS_IOCTL_INT_STATUS _IO(AKMIO, 0x05)
+#define ECS_IOCTL_FFD_STATUS _IO(AKMIO, 0x06)
+#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x07, short)
+#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1])
+#define ECS_IOCTL_GET_NUMFRQ _IOR(AKMIO, 0x09, char[2])
+#define ECS_IOCTL_SET_PERST _IO(AKMIO, 0x0A)
+#define ECS_IOCTL_SET_G0RST _IO(AKMIO, 0x0B)
+#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12])
+#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int)
+#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int)
+#define ECS_IOCTL_GET_CALI_DATA _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE])
+#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short)
+
+/* IOCTLs for APPs */
+#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short)
+#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short)
+#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short)
+#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short)
+#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short)
+#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short)
+#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17)
+#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY
+#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) /* Set raw magnetic vector flag */
+#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) /* Get raw magnetic vector flag */
+
+/* IOCTLs for pedometer */
+#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short)
+#define SENSOR_DATA_SIZE 3
+#define WMTGSENSOR_IOCTL_MAGIC 0x09
+#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short)
+#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short)
+#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int)
+#define ECS_IOCTL_APP_READ_XYZ _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x05, int[SENSOR_DATA_SIZE])
+
+#define MMA7660_DRVID 0
+
+
+
+/* Default GPIO setting */
+#define ECS_RST 146 /*MISC4, bit2 */
+#define ECS_CLK_ON 155 /*MISC5, bit3 */
+#define ECS_INTR 161 /*INT2, bit1 */
+
+/* MISC */
+#define MMA7660_ADDR 0x4C
+#define SENSOR_UI_MODE 0
+#define SENSOR_GRAVITYGAME_MODE 1
+#define UI_SAMPLE_RATE 0xFC
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define sin30_1000 500
+#define cos30_1000 866
+#define DISABLE 0
+#define ENABLE 1
+
+struct mma7660_platform_data {
+ int reset;
+ int clk_on;
+ int intr;
+};
+
+extern char *get_mma_cal_ram(void);
+
+#endif
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile new file mode 100755 index 00000000..4dcceb42 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_mma8452q
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := mma8x5x.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c new file mode 100755 index 00000000..443d3b18 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.c @@ -0,0 +1,982 @@ +#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/miscdevice.h>
+#include <linux/gpio.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/workqueue.h>
+#include <linux/freezer.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <mach/hardware.h>
+#include "mma8x5x.h" //"mma8452q.h"
+#include "../sensor.h"
+
+//#define DEBUG 1
+
+#undef dbg
+
+//#if 0
+ #define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+ //#define dbg(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+
+#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+
+ //#define dbg(format, arg...) printk(KERN_ALERT format, ## arg)
+
+
+//#else
+// #define dbg(format, arg...)
+//#endif
+
+/////////////////////Macro constant
+#define SENSOR_POLL_WAIT_TIME 1837
+#define MAX_FAILURE_COUNT 10
+#define MMA8452_ADDR 0x1C //slave 0x1D??high
+#define LAND_PORT_MASK 0x1C
+#define LAND_LEFT 0x1
+#define LAND_RIGHT 0x2
+#define PORT_INVERT 0x5
+#define PORT_NORMAL 0x6
+
+#define LANDSCAPE_LOCATION 0
+#define PORTRAIT_LOCATION 1
+
+#define SENSOR_UI_MODE 0
+#define SENSOR_GRAVITYGAME_MODE 1
+
+#define UI_SAMPLE_RATE 0xFC
+
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define GSENSOR_MAJOR 161 +#define GSENSOR_NAME "mma8452q"
+#define GSENSOR_DRIVER_NAME "mma8452q_drv"
+
+
+#define sin30_1000 500
+#define cos30_1000 866
+
+#define DISABLE 0
+#define ENABLE 1
+
+////////////////////////the rate of g-sensor/////////////////////////////////////////////
+#define SENSOR_DELAY_FASTEST 0
+#define SENSOR_DELAY_GAME 20
+#define SENSOR_DELAY_UI 60
+#define SENSOR_DELAY_NORMAL 200
+
+#define FASTEST_MMA_AMSR 0 // 120 samples/sec
+#define GAME_MMA_AMSR 1 // 1, (64, samples/sec)
+#define UI_MMA_AMSR 3 // 2, 3,4, (16, 8,32 samples/sec)
+#define NORMAL_MMA_AMSR 5 // 5, 6, 7 (4, 2, 1 samples/sec)
+
+#define MMA8451_ID 0x1A
+#define MMA8452_ID 0x2A
+#define MMA8453_ID 0x3A
+#define MMA8652_ID 0x4A
+#define MMA8653_ID 0x5A
+#define MODE_CHANGE_DELAY_MS 100
+/* register enum for mma8x5x registers */
+enum {
+ MMA8X5X_STATUS = 0x00,
+ MMA8X5X_OUT_X_MSB,
+ MMA8X5X_OUT_X_LSB,
+ MMA8X5X_OUT_Y_MSB,
+ MMA8X5X_OUT_Y_LSB,
+ MMA8X5X_OUT_Z_MSB,
+ MMA8X5X_OUT_Z_LSB,
+
+ MMA8X5X_F_SETUP = 0x09,
+ MMA8X5X_TRIG_CFG,
+ MMA8X5X_SYSMOD,
+ MMA8X5X_INT_SOURCE,
+ MMA8X5X_WHO_AM_I,
+ MMA8X5X_XYZ_DATA_CFG,
+ MMA8X5X_HP_FILTER_CUTOFF,
+
+ MMA8X5X_PL_STATUS,
+ MMA8X5X_PL_CFG,
+ MMA8X5X_PL_COUNT,
+ MMA8X5X_PL_BF_ZCOMP,
+ MMA8X5X_P_L_THS_REG,
+
+ MMA8X5X_FF_MT_CFG,
+ MMA8X5X_FF_MT_SRC,
+ MMA8X5X_FF_MT_THS,
+ MMA8X5X_FF_MT_COUNT,
+
+ MMA8X5X_TRANSIENT_CFG = 0x1D,
+ MMA8X5X_TRANSIENT_SRC,
+ MMA8X5X_TRANSIENT_THS,
+ MMA8X5X_TRANSIENT_COUNT,
+
+ MMA8X5X_PULSE_CFG,
+ MMA8X5X_PULSE_SRC,
+ MMA8X5X_PULSE_THSX,
+ MMA8X5X_PULSE_THSY,
+ MMA8X5X_PULSE_THSZ,
+ MMA8X5X_PULSE_TMLT,
+ MMA8X5X_PULSE_LTCY,
+ MMA8X5X_PULSE_WIND,
+
+ MMA8X5X_ASLP_COUNT,
+ MMA8X5X_CTRL_REG1,
+ MMA8X5X_CTRL_REG2,
+ MMA8X5X_CTRL_REG3,
+ MMA8X5X_CTRL_REG4,
+ MMA8X5X_CTRL_REG5,
+
+ MMA8X5X_OFF_X,
+ MMA8X5X_OFF_Y,
+ MMA8X5X_OFF_Z,
+
+ MMA8X5X_REG_END,
+};
+
+enum {
+ MODE_2G = 0,
+ MODE_4G,
+ MODE_8G,
+};
+
+static int mma8x5x_chip_id[] ={
+ MMA8451_ID,
+ MMA8452_ID,
+ MMA8453_ID,
+ MMA8652_ID,
+ MMA8653_ID,
+};
+
+static struct i2c_client *this_client = NULL;
+/////////////////////////////////////////////////////////////////////////
+
+static struct platform_device *this_pdev;
+
+static struct class* l_dev_class = NULL; +static struct device *l_clsdevice = NULL; +
+
+
+struct mma8452q_config
+{
+ int op;
+ int int_gpio; //0-3
+ int xyz_axis[3][2]; // (axis,direction)
+ int rxyz_axis[3][2];
+ int irq;
+ struct proc_dir_entry* sensor_proc;
+ int sensorlevel;
+ int shake_enable; // 1--enable shake, 0--disable shake
+ int manual_rotation; // 0--landance, 90--vertical
+ struct input_dev *input_dev;
+ //struct work_struct work;
+ struct delayed_work work; // for polling
+ struct workqueue_struct *queue;
+ int isdbg; // 0-- no debug log, 1--show debug log
+ int sensor_samp; // 1,2,4,8,16,32,64,120
+ int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor
+ int test_pass;
+ spinlock_t spinlock;
+ int pollcnt; // the counts of polling
+ int offset[3];
+};
+
+static struct mma8452q_config l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },
+ .irq = 6,
+ .int_gpio = 3,
+ .sensor_proc = NULL,
+ .sensorlevel = SENSOR_GRAVITYGAME_MODE,
+ .shake_enable = 0, // default enable shake
+ .isdbg = 0,
+ .sensor_samp = 10, // 4sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds
+ .offset = {0,0,0},
+};
+
+
+
+struct work_struct poll_work;
+static struct mutex sense_data_mutex;
+static int revision = -1;
+static int l_resumed = 0; // 1: suspend --> resume;2: suspend but not resumed; other values have no meaning
+
+//////////////////Macro function//////////////////////////////////////////////////////
+
+#define SET_MMA_SAMPLE(buf,samp) { \
+ buf[0] = 0; \
+ sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1); \
+ buf[0] = samp; \
+ sensor_i2c_write(/*MMA8452_ADDR,*/8,buf,1); \
+ buf[0] = 0x01; \
+ sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1); \
+}
+
+////////////////////////Function define/////////////////////////////////////////////////////////
+
+static unsigned int mma_sample2AMSR(unsigned int samp);
+
+////////////////////////Function implement/////////////////////////////////////////////////
+// rate: 1,2,4,8,16,32,64,120
+static unsigned int sample_rate_2_memsec(unsigned int rate)
+{
+ return (1000/rate);
+}
+
+
+
+static ssize_t gsensor_vendor_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ sprintf(buf, "MMA8452_%#x\n", revision);
+ ret = strlen(buf) + 1;
+
+ return ret;
+}
+
+static DEVICE_ATTR(vendor, 0444, gsensor_vendor_show, NULL);
+
+static struct kobject *android_gsensor_kobj;
+static int gsensor_sysfs_init(void)
+{
+ int ret ;
+
+ android_gsensor_kobj = kobject_create_and_add("android_gsensor", NULL);
+ if (android_gsensor_kobj == NULL) {
+ printk(KERN_ERR
+ "mma8452q gsensor_sysfs_init:"\
+ "subsystem_register failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = sysfs_create_file(android_gsensor_kobj, &dev_attr_vendor.attr);
+ if (ret) {
+ printk(KERN_ERR
+ "mma8452q gsensor_sysfs_init:"\
+ "sysfs_create_group failed\n");
+ goto err4;
+ }
+
+ return 0 ;
+err4:
+ kobject_del(android_gsensor_kobj);
+err:
+ return ret ;
+}
+
+static int gsensor_sysfs_exit(void)
+{
+ sysfs_remove_file(android_gsensor_kobj, &dev_attr_vendor.attr);
+ kobject_del(android_gsensor_kobj);
+ return 0;
+}
+
+//extern int wmt_i2c_xfer_continue_if_4(struct i2c_msg *msg, unsigned int num, int bus_id);
+extern int i2c_api_do_send(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size);
+extern int i2c_api_do_recv(int bus_id, char chip_addr, char sub_addr, char *buf, unsigned int size);
+
+int sensor_i2c_write(/*unsigned int addr,*/unsigned int index,char *pdata,int len)
+{
+
+ char wrData[12] = {0};
+ struct i2c_client *client = this_client;
+
+ struct i2c_msg msgs =
+ {.addr = client->addr, .flags = 0, .len = len+1, .buf = wrData,};
+
+
+ if (!client || (!pdata))
+ {
+ printk("%s NULL client!\n", __FUNCTION__);
+ return -EIO;
+ }
+
+ wrData[0] = index;
+ strncpy(&wrData[1], pdata, len);
+
+ if (i2c_transfer(client->adapter, &msgs, 1) < 0) {
+ printk( "%s: transfer failed.", __func__);
+ return -EIO;
+ }
+
+ return 0;
+} /* End of sensor_i2c_write */
+
+int sensor_i2c_read(/*unsigned int addr,*/unsigned int index,char *pdata,int len)
+{
+ char rdData[2] = {0};
+ struct i2c_client *client = this_client;
+
+ struct i2c_msg msgs[2] =
+ {
+ {.addr = client->addr, .flags = 0|I2C_M_NOSTART, .len = 1, .buf = rdData,},
+ {.addr = client->addr, .flags = I2C_M_RD, .len = len, .buf = pdata,},
+ };
+ rdData[0] = index;
+ if (!client || (!pdata))
+ {
+ printk("%s NULL client!\n", __FUNCTION__);
+ return -EIO;
+ }
+ if (i2c_transfer(client->adapter, msgs, 2) < 0) {
+ printk( "%s: transfer failed.", __func__);
+ return -EIO;
+ }
+
+ return 0;//rdData[0]; i2c read ok!!
+
+} /* End of sensor_i2c_read */
+
+//****************add for mma8452q******************************
+
+static int mma8452q_chip_init(void)
+{
+ char txData[1] = {0};
+
+ int result;
+
+ txData[0] = 0x1; //active mode
+ result = sensor_i2c_write(/*MMA8452_ADDR,*/MMA8X5X_CTRL_REG1,txData,1);
+ if (result < 0)
+ goto out;
+
+ txData[0] = MODE_2G;
+ result = sensor_i2c_write(/*MMA8452_ADDR,*/MMA8X5X_XYZ_DATA_CFG,txData,1);
+ if (result < 0)
+ goto out;
+
+ txData[0] = 0x1; //wake mode
+ result = sensor_i2c_write(/*MMA8452_ADDR,*/MMA8X5X_SYSMOD,txData,1);
+ if (result < 0)
+ goto out;
+
+ msleep(MODE_CHANGE_DELAY_MS);
+ return 0;
+out:
+
+ return result;
+
+}
+
+static unsigned int mma_sample2AMSR(unsigned int samp)
+{
+ int i = 0;
+ unsigned int amsr;
+
+ if (samp >= 120)
+ {
+ return 0;
+ }
+ while (samp)
+ {
+ samp = samp >> 1;
+ i++;
+ }
+ amsr = 8 - i;
+ return amsr;
+}
+
+static int mma_enable_disable(int enable)
+{
+ char buf[1];
+
+ // disable all interrupt of g-sensor
+ memset(buf, 0, sizeof(buf));
+ if ((enable < 0) || (enable > 1))
+ {
+ return -1;
+ }
+ buf[0] = 0;
+ sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1);
+ if (enable != 0)
+ {
+ buf[0] = (1 == l_sensorconfig.shake_enable) ? 0xF0:0x10;
+ } else {
+ buf[0] = 0;
+ }
+ sensor_i2c_write(/*MMA8452_ADDR,*/6,buf,1);
+ buf[0] = 0xf9;
+ sensor_i2c_write(/*MMA8452_ADDR,*/7,buf,1);
+ return 0;
+}
+
+// To contol the g-sensor for UI
+static int mmad_open(struct inode *inode, struct file *file)
+{
+ dbg("Open the g-sensor node...\n");
+ return 0;
+}
+
+static int mmad_release(struct inode *inode, struct file *file)
+{
+ dbg("Close the g-sensor node...\n");
+ return 0;
+}
+
+static long
+mmad_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ char rwbuf[5];
+ short delay, enable; //amsr = -1;
+ unsigned int uval = 0;
+
+ dbg("g-sensor ioctr...\n");
+ memset(rwbuf, 0, sizeof(rwbuf));
+ switch (cmd) {
+ case ECS_IOCTL_APP_SET_DELAY:
+ // set the rate of g-sensor
+ if (copy_from_user(&delay, argp, sizeof(short)))
+ {
+ printk(KERN_ALERT "Can't get set delay!!!\n");
+ return -EFAULT;
+ }
+ klog("Get delay=%d\n", delay);
+ //klog("before change sensor sample:%d...\n", l_sensorconfig.sensor_samp);
+ if ((delay >=0) && (delay < 20))
+ {
+ delay = 20;
+ } else if (delay > 200)
+ {
+ delay = 200;
+ }
+ l_sensorconfig.sensor_samp = 1000/delay;
+
+ break;
+ case ECS_IOCTL_APP_SET_AFLAG:
+ // enable/disable sensor
+ if (copy_from_user(&enable, argp, sizeof(short)))
+ {
+ printk(KERN_ERR "Can't get enable flag!!!\n");
+ return -EFAULT;
+ }
+ klog("enable=%d\n",enable);
+ if ((enable >=0) && (enable <=1))
+ {
+ dbg("driver: disable/enable(%d) gsensor.\n", enable);
+
+ l_sensorconfig.sensor_enable = enable;
+
+ } else {
+ printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ break;
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+ uval = MMA8452Q_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ dbg("mma8452q_driver_id:%d\n",uval);
+ break;
+ case WMT_IOCTL_SENOR_GET_RESOLUTION:
+
+ uval = (16<<8) | 4; // 16bit:4g 0xxx xx //mma8452Q
+ if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ printk("<<<<<<<resolution:0x%x\n",uval);
+ default:
+ break;
+ }
+
+
+
+ return 0;
+}
+
+
+static void mma_work_func(struct work_struct *work)
+{
+ struct mma8452q_config *data;
+ /*unsigned*/ short rxData[3] = {0};
+ //unsigned char tiltval = 0;
+ int i = 0;
+ int x,y,z;
+ char tmp[6] = {0};
+
+ data = dev_get_drvdata(&this_pdev->dev);
+ if (!l_sensorconfig.sensor_enable)
+ {
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+ return;
+ }
+ mutex_lock(&sense_data_mutex);
+
+
+ i = sensor_i2c_read(/*MMA8452_ADDR,*/MMA8X5X_OUT_X_MSB,tmp, sizeof(tmp));
+#if 0
+ for (i=0; i<6; i++)
+ sensor_i2c_read(/*MMA8452_ADDR,*/MMA8X5X_OUT_X_MSB+i,&tmp[i], 1);
+ i = 0;
+#endif
+
+ if (0 == i)
+ {
+ rxData[0] = ((tmp[0] << 8 )&0xff00 ) | (tmp[1] );
+ rxData[1] = ((tmp[2] << 8) &0xff00 ) | (tmp[3] );
+ rxData[2] = ((tmp[4] << 8) &0xff00 ) | (tmp[5] );
+ x = rxData[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1];
+ y = rxData[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1];
+ z = rxData[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1];
+ #if 0
+ x = (x*9800) >> 14;
+ y = (y*9800) >> 14;
+ z = (z*9800) >> 14;
+ #endif
+ //printk("x,y,z (%d, %d, %d) \n", rxData[0], rxData[1], rxData[2]);
+ //printk("x,y,z (%d, %d, %d) \n", x, y, z);
+ //printk("x 0x%x\n", tmp[0]);
+ input_report_abs(data->input_dev, ABS_X, x);
+ input_report_abs(data->input_dev, ABS_Y, y);
+ input_report_abs(data->input_dev, ABS_Z, z);
+ input_sync(data->input_dev);
+ }
+
+
+ mutex_unlock(&sense_data_mutex);
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+}
+
+static int sensor_writeproc( struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data )
+{
+
+ int inputval = -1;
+ int enable, sample = -1;
+ char tembuf[8];
+ unsigned int amsr = 0;
+ int test = 0;
+
+ mutex_lock(&sense_data_mutex);
+ // disable int
+ //gsensor_int_ctrl(DISABLE);
+ memset(tembuf, 0, sizeof(tembuf));
+ // get sensor level and set sensor level
+ if (sscanf(buffer, "level=%d\n", &l_sensorconfig.sensorlevel))
+ {
+ } else if (sscanf(buffer, "shakenable=%d\n", &l_sensorconfig.shake_enable))
+ {
+
+ }
+ else if (sscanf(buffer, "isdbg=%d\n", &l_sensorconfig.isdbg))
+ {
+ // only set the dbg flag
+ } else if (sscanf(buffer, "init=%d\n", &inputval))
+ {
+ mma8452q_chip_init();
+ dbg("Has reinit sensor !!!\n");
+ } else if (sscanf(buffer, "samp=%d\n", &sample))
+ {
+ if (sample > 0)
+ {
+ if (sample != l_sensorconfig.sensor_samp)
+ {
+ amsr = mma_sample2AMSR(sample);
+ SET_MMA_SAMPLE(tembuf, amsr);
+ klog("sample:%d ,amsr:%d \n", sample, amsr);
+ l_sensorconfig.sensor_samp = sample;
+ }
+ printk(KERN_ALERT "sensor samp=%d(amsr:%d) has been set.\n", sample, amsr);
+ } else {
+ printk(KERN_ALERT "Wrong sample argumnet of sensor.\n");
+ }
+ } else if (sscanf(buffer, "enable=%d\n", &enable))
+ {
+ if ((enable < 0) || (enable > 1))
+ {
+ printk(KERN_ERR "The argument to enable/disable g-sensor should be 0 or 1 !!!\n");
+ } else if (enable != l_sensorconfig.sensor_enable)
+ {
+ mma_enable_disable(enable);
+ l_sensorconfig.sensor_enable = enable;
+ }
+ } else if (sscanf(buffer, "sensor_test=%d\n", &test))
+ { // for test begin
+ l_sensorconfig.test_pass = 0;
+ } else if (sscanf(buffer, "sensor_testend=%d\n", &test))
+ { // Don nothing only to be compatible the before testing program
+ }
+ mutex_unlock(&sense_data_mutex);
+ return count;
+}
+
+static int sensor_readproc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+
+ len = sprintf(page,
+ "test_pass=%d\nisdbg=%d\nrate=%d\nenable=%d\n",
+ l_sensorconfig.test_pass,
+ l_sensorconfig.isdbg,
+ l_sensorconfig.sensor_samp,
+ l_sensorconfig.sensor_enable
+ );
+ return len;
+}
+
+
+
+static int mma8452q_init_client(struct platform_device *pdev)
+{
+ struct mma8452q_config *data;
+// int ret;
+
+ data = dev_get_drvdata(&pdev->dev);
+ mutex_init(&sense_data_mutex);
+ /*Only for polling, not interrupt*/
+ l_sensorconfig.sensor_proc = create_proc_entry(GSENSOR_PROC_NAME, 0666, NULL/*&proc_root*/);
+ if (l_sensorconfig.sensor_proc != NULL)
+ {
+ l_sensorconfig.sensor_proc->write_proc = sensor_writeproc;
+ l_sensorconfig.sensor_proc->read_proc = sensor_readproc;
+ }
+
+
+ return 0;
+
+//err:
+// return ret;
+}
+
+static struct file_operations mmad_fops = {
+ .owner = THIS_MODULE,
+ .open = mmad_open,
+ .release = mmad_release,
+ .unlocked_ioctl = mmad_ioctl,
+};
+
+
+static struct miscdevice mmad_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sensor_ctrl",
+ .fops = &mmad_fops,
+};
+
+static int mma8452q_probe(struct platform_device *pdev)
+{
+ int err;
+
+ this_pdev = pdev;
+ l_sensorconfig.queue = create_singlethread_workqueue("sensor-intterupt-handle");
+ INIT_DELAYED_WORK(&l_sensorconfig.work, mma_work_func);
+
+ l_sensorconfig.input_dev = input_allocate_device();
+ if (!l_sensorconfig.input_dev) {
+ err = -ENOMEM;
+ printk(KERN_ERR
+ "mma8452q_probe: Failed to allocate input device\n");
+ goto exit_input_dev_alloc_failed;
+ }
+ l_sensorconfig.input_dev->evbit[0] = BIT(EV_ABS) | BIT_MASK(EV_KEY);
+ set_bit(KEY_NEXTSONG, l_sensorconfig.input_dev->keybit);
+
+ /* x-axis acceleration */
+ input_set_abs_params(l_sensorconfig.input_dev, ABS_X, -65532, 65532, 0, 0);
+ /* y-axis acceleration */
+ input_set_abs_params(l_sensorconfig.input_dev, ABS_Y, -65532, 65532, 0, 0);
+ /* z-axis acceleration */
+ input_set_abs_params(l_sensorconfig.input_dev, ABS_Z, -65532, 65532, 0, 0);
+
+ l_sensorconfig.input_dev->name = "g-sensor";
+
+ err = input_register_device(l_sensorconfig.input_dev);
+
+ if (err) {
+ printk(KERN_ERR
+ "mma8452q_probe: Unable to register input device: %s\n",
+ l_sensorconfig.input_dev->name);
+ goto exit_input_register_device_failed;
+ }
+
+ err = misc_register(&mmad_device);
+ if (err) {
+ printk(KERN_ERR
+ "mma8452q_probe: mmad_device register failed\n");
+ goto exit_misc_device_register_failed;
+ }
+
+ dev_set_drvdata(&pdev->dev, &l_sensorconfig);
+ mma8452q_chip_init();
+ mma8452q_init_client(pdev);
+ gsensor_sysfs_init();
+
+ // satrt the polling work
+ l_sensorconfig.sensor_samp = 10;
+ queue_delayed_work(l_sensorconfig.queue, &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+ return 0;
+
+exit_misc_device_register_failed:
+exit_input_register_device_failed:
+ input_free_device(l_sensorconfig.input_dev);
+
+exit_input_dev_alloc_failed:
+
+ return err;
+}
+
+static int mma8452q_remove(struct platform_device *pdev)
+{
+ if (NULL != l_sensorconfig.queue)
+ {
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+ flush_workqueue(l_sensorconfig.queue);
+ destroy_workqueue(l_sensorconfig.queue);
+ l_sensorconfig.queue = NULL;
+ }
+ gsensor_sysfs_exit();
+ misc_deregister(&mmad_device);
+ input_unregister_device(l_sensorconfig.input_dev);
+ if (l_sensorconfig.sensor_proc != NULL)
+ {
+ remove_proc_entry(GSENSOR_PROC_NAME, NULL);
+ l_sensorconfig.sensor_proc = NULL;
+ }
+
+ return 0;
+}
+
+static int mma8452q_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ //gsensor_int_ctrl(DISABLE);
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+
+ dbg("...ok\n");
+ //l_resumed = 2;
+
+ return 0;
+}
+
+static int mma8452q_resume(struct platform_device *pdev)
+{
+
+ l_resumed = 1;
+
+ mma8452q_chip_init();
+ queue_delayed_work(l_sensorconfig.queue, \
+ &l_sensorconfig.work, msecs_to_jiffies(sample_rate_2_memsec(l_sensorconfig.sensor_samp)));
+ dbg("...ok\n");
+
+ return 0;
+}
+
+static void mma8452q_platform_release(struct device *device)
+{
+ return;
+}
+
+static void mma8452q_shutdown(struct platform_device *pdev)
+{
+ flush_delayed_work_sync(&l_sensorconfig.work);
+ cancel_delayed_work_sync(&l_sensorconfig.work);
+
+}
+
+static struct platform_device mma8452q_device = {
+ .name = "mma8452q",
+ .id = 0,
+ .dev = {
+ .release = mma8452q_platform_release,
+ },
+};
+
+static struct platform_driver mma8452q_driver = {
+ .probe = mma8452q_probe,
+ .remove = mma8452q_remove,
+ .suspend = mma8452q_suspend,
+ .resume = mma8452q_resume,
+ .shutdown = mma8452q_shutdown,
+ .driver = {
+ .name = "mma8452q",
+ },
+};
+
+/*
+ * Brief:
+ * Get the configure of sensor from u-boot.
+ * Input:
+ * no use.
+ * Output:
+ * no use.
+ * Return:
+ * 0--success, -1--error.
+ * History:
+ * Created by HangYan on 2010-4-19
+ * Author:
+ * Hang Yan in ShenZhen.
+ */
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static int get_axisset(void* param)
+{
+ char varbuf[64];
+ int n;
+ int varlen;
+
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+ if (wmt_getsyspara("wmt.io.mma8452qgsensor", varbuf, &varlen)) {
+ printk(KERN_DEBUG "Can't get gsensor config in u-boot!!!!\n");
+ return -1;
+ } else {
+ n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &l_sensorconfig.op,
+ &(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]),
+ &(l_sensorconfig.offset[0]),
+ &(l_sensorconfig.offset[1]),
+ &(l_sensorconfig.offset[2]));
+ if (n != 10) {
+ printk(KERN_ERR "gsensor format is error in u-boot!!!\n");
+ return -1;
+ }
+
+ printk("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ l_sensorconfig.op,
+ 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],
+ l_sensorconfig.offset[0],
+ l_sensorconfig.offset[1],
+ l_sensorconfig.offset[2]
+ );
+ }
+ return 0;
+}
+
+static int is_mma8452q(void)
+{
+ char rxData[2] = {0};
+ int ret = 0;
+ int i = 0;
+ //char rdData[10] = {0};
+ //char wbuf[6] = {0};
+ //char rbuf[0x33] = {0};
+
+ ret = sensor_i2c_read(MMA8X5X_WHO_AM_I,rxData,1);
+ //printk("<<<<%s ret %d, val 0x%x\n", __FUNCTION__, ret, rxData[0]);
+ for(i = 0 ; i < sizeof(mma8x5x_chip_id)/sizeof(mma8x5x_chip_id[0]);i++)
+ if(rxData[0] == mma8x5x_chip_id[i])
+ return 0;
+#if 0
+ struct i2c_client* client = gsensor_get_i2c_client();
+ if (!client){
+ printk("client NULL!\n");
+ return -1;
+ }
+
+ for (i=0; i<6; i++)
+ wbuf[i] = i+2;
+ //sensor_i2c_write(0x25, wbuf, 6);
+ //rbuf[0] = 0x11;
+ //sensor_i2c_read(0xb, rbuf, 0x1);
+ mma8452q_chip_init();
+ for (i=0; i<0x12; i++) {
+ sensor_i2c_read(0xb+i, rbuf, 0x1);
+ printk("<<<<%s reg 0x%x val 0x%x\n", __FUNCTION__, 0xb+i, rbuf[0]);
+ }
+#endif
+ return -1;
+}
+
+static int __init mma8452q_init(void)
+{
+ int ret = 0;
+
+ ret = get_axisset(NULL);
+ if (ret < 0)
+ {
+ printk("<<<<<%s user choose to no sensor chip!\n", __func__);
+ return ret;
+ }
+
+ if (!(this_client = sensor_i2c_register_device(0, GSENSOR_I2C_ADDR, GSENSOR_I2C_NAME)))
+ {
+ printk(KERN_EMERG"Can't register gsensor i2c device!\n");
+ return -1;
+ }
+
+ if (is_mma8452q())
+ {
+ printk(KERN_ERR "Can't find mma8452q!!\n");
+ sensor_i2c_unregister_device(this_client);
+ return -1;
+ }
+
+
+
+ printk(KERN_INFO "mma8452qfc g-sensor driver init\n");
+
+ spin_lock_init(&l_sensorconfig.spinlock);
+
+ // Create device node + + l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME);
+ //for S40 module to judge whether insmod is ok + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + l_clsdevice = device_create(l_dev_class, NULL, MKDEV(GSENSOR_MAJOR, 0), NULL, GSENSOR_NAME); + if (IS_ERR(l_clsdevice)){ + ret = PTR_ERR(l_clsdevice); + printk(KERN_ERR "Failed to create device %s !!!",GSENSOR_NAME); + return ret; + } +
+ if((ret = platform_device_register(&mma8452q_device)))
+ {
+ printk(KERN_ERR "%s Can't register mma8452q platform devcie!!!\n", __FUNCTION__);
+ return ret;
+ }
+ if ((ret = platform_driver_register(&mma8452q_driver)) != 0)
+ {
+ printk(KERN_ERR "%s Can't register mma8452q platform driver!!!\n", __FUNCTION__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit mma8452q_exit(void)
+{
+ platform_driver_unregister(&mma8452q_driver);
+ platform_device_unregister(&mma8452q_device);
+ device_destroy(l_dev_class, MKDEV(GSENSOR_MAJOR, 0));
+ + class_destroy(l_dev_class);
+ sensor_i2c_unregister_device(this_client); +
+}
+
+module_init(mma8452q_init);
+module_exit(mma8452q_exit);
+MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h new file mode 100755 index 00000000..d8d386b2 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mma8452q_gsensor/mma8x5x.h @@ -0,0 +1,107 @@ +/*
+ * Definitions for akm8976 compass chip.
+ */
+#ifndef AKM8976_H
+#define AKM8976_H
+
+#include <linux/ioctl.h>
+
+#define GSENSOR_I2C_NAME "mma8452q"
+#define GSENSOR_I2C_ADDR 0x1c
+/* Compass device dependent definition */
+#define AKECS_MODE_MEASURE 0x00 /* Starts measurement. Please use AKECS_MODE_MEASURE_SNG */
+ /* or AKECS_MODE_MEASURE_SEQ instead of this. */
+#define AKECS_MODE_PFFD 0x01 /* Start pedometer and free fall detect. */
+#define AKECS_MODE_E2P_READ 0x02 /* E2P access mode (read). */
+#define AKECS_MODE_POWERDOWN 0x03 /* Power down mode */
+
+#define AKECS_MODE_MEASURE_SNG 0x10 /* Starts single measurement */
+#define AKECS_MODE_MEASURE_SEQ 0x11 /* Starts sequential measurement */
+
+/* Default register settings */
+#define CSPEC_AINT 0x01 /* Amplification for acceleration sensor */
+#define CSPEC_SNG_NUM 0x01 /* Single measurement mode */
+#define CSPEC_SEQ_NUM 0x02 /* Sequential measurement mode */
+#define CSPEC_SFRQ_32 0x00 /* Measurement frequency: 32Hz */
+#define CSPEC_SFRQ_64 0x01 /* Measurement frequency: 64Hz */
+#define CSPEC_MCS 0x07 /* Clock frequency */
+#define CSPEC_MKS 0x01 /* Clock type: CMOS level */
+#define CSPEC_INTEN 0x01 /* Interruption pin enable: Enable */
+
+#define RBUFF_SIZE 31 /* Rx buffer size */
+#define MAX_CALI_SIZE 0x1000U /* calibration buffer size */
+
+/* AK8976A register address */
+#define AKECS_REG_ST 0xC0
+#define AKECS_REG_TMPS 0xC1
+#define AKECS_REG_MS1 0xE0
+#define AKECS_REG_MS2 0xE1
+#define AKECS_REG_MS3 0xE2
+
+#define AKMIO 0xA1
+
+/* IOCTLs for AKM library */
+#define ECS_IOCTL_RESET _IO(AKMIO, 0x04)
+#define ECS_IOCTL_INT_STATUS _IO(AKMIO, 0x05)
+#define ECS_IOCTL_FFD_STATUS _IO(AKMIO, 0x06)
+#define ECS_IOCTL_SET_MODE _IOW(AKMIO, 0x07, short)
+#define ECS_IOCTL_GETDATA _IOR(AKMIO, 0x08, char[RBUFF_SIZE+1])
+#define ECS_IOCTL_GET_NUMFRQ _IOR(AKMIO, 0x09, char[2])
+#define ECS_IOCTL_SET_PERST _IO(AKMIO, 0x0A)
+#define ECS_IOCTL_SET_G0RST _IO(AKMIO, 0x0B)
+#define ECS_IOCTL_SET_YPR _IOW(AKMIO, 0x0C, short[12])
+#define ECS_IOCTL_GET_OPEN_STATUS _IOR(AKMIO, 0x0D, int)
+#define ECS_IOCTL_GET_CLOSE_STATUS _IOR(AKMIO, 0x0E, int)
+#define ECS_IOCTL_GET_CALI_DATA _IOR(AKMIO, 0x0F, char[MAX_CALI_SIZE])
+#define ECS_IOCTL_GET_DELAY _IOR(AKMIO, 0x30, short)
+
+/* IOCTLs for APPs */
+#define ECS_IOCTL_APP_SET_MODE _IOW(AKMIO, 0x10, short)
+#define ECS_IOCTL_APP_SET_MFLAG _IOW(AKMIO, 0x11, short)
+#define ECS_IOCTL_APP_GET_MFLAG _IOW(AKMIO, 0x12, short)
+#define ECS_IOCTL_APP_GET_AFLAG _IOR(AKMIO, 0x14, short)
+#define ECS_IOCTL_APP_SET_TFLAG _IOR(AKMIO, 0x15, short)
+#define ECS_IOCTL_APP_GET_TFLAG _IOR(AKMIO, 0x16, short)
+#define ECS_IOCTL_APP_RESET_PEDOMETER _IO(AKMIO, 0x17)
+#define ECS_IOCTL_APP_GET_DELAY ECS_IOCTL_GET_DELAY
+#define ECS_IOCTL_APP_SET_MVFLAG _IOW(AKMIO, 0x19, short) /* Set raw magnetic vector flag */
+#define ECS_IOCTL_APP_GET_MVFLAG _IOR(AKMIO, 0x1A, short) /* Get raw magnetic vector flag */
+
+/* IOCTLs for pedometer */
+#define ECS_IOCTL_SET_STEP_CNT _IOW(AKMIO, 0x20, short)
+
+#define WMTGSENSOR_IOCTL_MAGIC 0x09
+#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short)
+#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short)
+#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int)
+
+//#define MMA8452_DRVID 6
+
+
+
+/* Default GPIO setting */
+#define ECS_RST 146 /*MISC4, bit2 */
+#define ECS_CLK_ON 155 /*MISC5, bit3 */
+#define ECS_INTR 161 /*INT2, bit1 */
+
+/* MISC */
+#define MMA8452_ADDR 0x1C
+#define SENSOR_UI_MODE 0
+#define SENSOR_GRAVITYGAME_MODE 1
+#define UI_SAMPLE_RATE 0xFC
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define sin30_1000 500
+#define cos30_1000 866
+#define DISABLE 0
+#define ENABLE 1
+
+struct mma7660_platform_data {
+ int reset;
+ int clk_on;
+ int intr;
+};
+
+extern char *get_mma_cal_ram(void);
+
+#endif
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/Makefile new file mode 100755 index 00000000..bdf4598d --- /dev/null +++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.c b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.c new file mode 100755 index 00000000..335ad266 --- /dev/null +++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.h b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mecs.h new file mode 100755 index 00000000..c328e585 --- /dev/null +++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.c b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.c new file mode 100755 index 00000000..4148b5f1 --- /dev/null +++ b/ANDROID_3.4.5/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/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.h b/ANDROID_3.4.5/drivers/input/sensor/mmc328x_msensor/mmc328x.h new file mode 100755 index 00000000..f272ea1d --- /dev/null +++ b/ANDROID_3.4.5/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__ */ + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile new file mode 100755 index 00000000..16baea79 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../
+#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8
+CROSS = arm_1103_le-
+CC= $(CROSS)gcc
+LD= $(CROSS)ld
+STRIP = $(CROSS)strip
+
+DEBUG = n
+
+# Add your debugging flag (or not) to EXTRA_CFLAGS
+ifeq ($(DEBUG),y)
+# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines
+
+else
+ DEBFLAGS = -O2 -Wall
+endif
+
+EXTRA_CFLAGS += $(DEBFLAGS)
+
+
+MY_MODULE_NAME=s_wmt_gsensor_mxc622x
+
+obj-m := $(MY_MODULE_NAME).o
+$(MY_MODULE_NAME)-objs := mxc622x.o
+
+default:
+ $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
+ $(STRIP) --strip-debug $(MY_MODULE_NAME).ko
+ rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c new file mode 100755 index 00000000..9c94b6ed --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.c @@ -0,0 +1,1151 @@ +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** + * + * File Name : mxc622x_acc.c + * Description : MXC622X accelerometer sensor API + * + ******************************************************************************* + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE + * PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. + * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, + * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE + * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING + * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. + * + + ******************************************************************************/ +#include <linux/module.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/i2c.h> + +#include <linux/input.h> +#include <linux/input-polldev.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/slab.h> + +#include <linux/workqueue.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#include <linux/platform_device.h> + +#include "mxc622x.h" +#include "../sensor.h" +#ifdef CONFIG_ARCH_SC8810 +#include <mach/eic.h> +#endif + +#define G_MAX 16000 /** Maximum polled-device-reported g value */ +#define WHOAMI_MXC622X_ACC 0x25 /* Expctd content for WAI */ + +/* CONTROL REGISTERS */ +#define WHO_AM_I 0x08 /* WhoAmI register */ + +#define FUZZ 32 +#define FLAT 32 +#define I2C_RETRY_DELAY 5 +#define I2C_RETRIES 5 +#define I2C_AUTO_INCREMENT 0x80 + +/* RESUME STATE INDICES */ + +#define RESUME_ENTRIES 20 +#define DEVICE_INFO "Memsic, MXC622X" +#define DEVICE_INFO_LEN 32 + +/* end RESUME STATE INDICES */ + +#define DEBUG +//#define MXC622X_DEBUG + +#define MAX_INTERVAL 50 + +#ifdef __KERNEL__ +static struct mxc622x_acc_platform_data mxc622x_plat_data = { + .poll_interval = 20, + .min_interval = 10, +}; +#endif + +#ifdef I2C_BUS_NUM_STATIC_ALLOC +static struct i2c_board_info mxc622x_i2c_boardinfo = { + I2C_BOARD_INFO(MXC622X_ACC_I2C_NAME, MXC622X_ACC_I2C_ADDR), +#ifdef __KERNEL__ + .platform_data = &mxc622x_plat_data +#endif +}; +#endif + +struct mxc622x_acc_data { + struct i2c_client *client; + struct mxc622x_acc_platform_data *pdata; + + struct mutex lock; + struct delayed_work input_work; + + struct input_dev *input_dev; + + int hw_initialized; + /* hw_working=-1 means not tested yet */ + int hw_working; + atomic_t enabled; + int on_before_suspend; + + u8 resume_state[RESUME_ENTRIES]; + +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +/* + * Because misc devices can not carry a pointer from driver register to + * open, we keep this global. This limits the driver to a single instance. + */ +struct mxc622x_acc_data *mxc622x_acc_misc_data; +struct i2c_client *mxc622x_i2c_client = NULL; +static struct class* l_dev_class = NULL; +struct i2c_client *this_client = NULL; +////////////////////////////////////////////////////// +struct mx622x_sensordata{ + // for control + int int_gpio; //0-3 + int op; + int samp; + int xyz_axis[3][3]; // (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]; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + s16 offset[3+1]; /*+1: for 4-byte alignment*/ + + +}; + +static struct mx622x_sensordata l_sensorconfig = { + .op = 0, + .int_gpio = 3, + .samp = 16, + .xyz_axis = { + {ABS_X, -1}, + {ABS_Y, 1}, + {ABS_Z, -1}, + }, + .sensor_proc = NULL, + .isdbg = 0, + .sensor_samp = 1, // 1 sample/second + .sensor_enable = 1, // enable sensor + .test_pass = 0, // for test program + //.offset={0,0,0}, +}; + +////////////////////////////////////////////////////// + + +static int mxc622x_acc_i2c_read(struct mxc622x_acc_data *acc, u8 * buf, int len) +{ + int err; + int tries = 0; + + struct i2c_msg msgs[] = { + { + .addr = acc->client->addr, + .flags = acc->client->flags & I2C_M_TEN, + .len = 1, + .buf = buf, }, + { + .addr = acc->client->addr, + .flags = (acc->client->flags & I2C_M_TEN) | I2C_M_RD, + .len = len, + .buf = buf, }, + }; + + do { + err = i2c_transfer(acc->client->adapter, msgs, 2); + if (err != 2) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != 2) && (++tries < I2C_RETRIES)); + + if (err != 2) { + dev_err(&acc->client->dev, "read transfer error\n"); + err = -EIO; + } else { + err = 0; + } + + return err; +} + +static int mxc622x_acc_i2c_write(struct mxc622x_acc_data *acc, u8 * buf, int len) +{ + int err; + int tries = 0; + + struct i2c_msg msgs[] = { { .addr = acc->client->addr, + .flags = acc->client->flags & I2C_M_TEN, + .len = len + 1, .buf = buf, }, }; + do { + err = i2c_transfer(acc->client->adapter, msgs, 1); + if (err != 1) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != 1) && (++tries < I2C_RETRIES)); + + if (err != 1) { + dev_err(&acc->client->dev, "write transfer error\n"); + err = -EIO; + } else { + err = 0; + } + + return err; +} + +static int mxc622x_acc_hw_init(struct mxc622x_acc_data *acc) +{ + int err = -1; + u8 buf[7]; + + printk(KERN_INFO "%s: hw init start\n", MXC622X_ACC_DEV_NAME); + + buf[0] = WHO_AM_I; + err = mxc622x_acc_i2c_read(acc, buf, 1); + if (err < 0) + goto error_firstread; + else + acc->hw_working = 1; + if ((buf[0] & 0x3F) != WHOAMI_MXC622X_ACC) { + err = -1; /* choose the right coded error */ + goto error_unknown_device; + } + + acc->hw_initialized = 1; + printk(KERN_INFO "%s: hw init done\n", MXC622X_ACC_DEV_NAME); + return 0; + +error_firstread: + acc->hw_working = 0; + dev_warn(&acc->client->dev, "Error reading WHO_AM_I: is device " + "available/working?\n"); + goto error1; +error_unknown_device: + dev_err(&acc->client->dev, + "device unknown. Expected: 0x%x," + " Replies: 0x%x\n", WHOAMI_MXC622X_ACC, buf[0]); +error1: + acc->hw_initialized = 0; + dev_err(&acc->client->dev, "hw init error 0x%x,0x%x: %d\n", buf[0], + buf[1], err); + return err; +} + +static void mxc622x_acc_device_power_off(struct mxc622x_acc_data *acc) +{ + int err; + u8 buf[2] = { MXC622X_REG_CTRL, MXC622X_CTRL_PWRDN }; + + err = mxc622x_acc_i2c_write(acc, buf, 1); + if (err < 0) + dev_err(&acc->client->dev, "soft power off failed: %d\n", err); +} + +static int mxc622x_acc_device_power_on(struct mxc622x_acc_data *acc) +{ + int err = -1; + u8 buf[2] = { MXC622X_REG_CTRL, MXC622X_CTRL_PWRON }; + + err = mxc622x_acc_i2c_write(acc, buf, 1); + if (err < 0) + dev_err(&acc->client->dev, "soft power on failed: %d\n", err); + + if (!acc->hw_initialized) { + err = mxc622x_acc_hw_init(acc); + if (acc->hw_working == 1 && err < 0) { + mxc622x_acc_device_power_off(acc); + return err; + } + } + + return 0; +} + + +/* */ + +static int mxc622x_acc_register_write(struct mxc622x_acc_data *acc, u8 *buf, + u8 reg_address, u8 new_value) +{ + int err = -1; + + if (atomic_read(&acc->enabled)) { + /* Sets configuration register at reg_address + * NOTE: this is a straight overwrite */ + buf[0] = reg_address; + buf[1] = new_value; + err = mxc622x_acc_i2c_write(acc, buf, 1); + if (err < 0) + return err; + } + return err; +} + +static int mxc622x_acc_register_read(struct mxc622x_acc_data *acc, u8 *buf, + u8 reg_address) +{ + + int err = -1; + buf[0] = (reg_address); + err = mxc622x_acc_i2c_read(acc, buf, 1); + return err; +} + +static int mxc622x_acc_register_update(struct mxc622x_acc_data *acc, u8 *buf, + u8 reg_address, u8 mask, u8 new_bit_values) +{ + int err = -1; + u8 init_val; + u8 updated_val; + err = mxc622x_acc_register_read(acc, buf, reg_address); + if (!(err < 0)) { + init_val = buf[1]; + updated_val = ((mask & new_bit_values) | ((~mask) & init_val)); + err = mxc622x_acc_register_write(acc, buf, reg_address, + updated_val); + } + return err; +} + +/* */ + +static int mxc622x_acc_get_acceleration_data(struct mxc622x_acc_data *acc, + int *xyz) +{ + int err = -1; + /* Data bytes from hardware x, y */ + u8 acc_data[2]; + + acc_data[0] = MXC622X_REG_DATA; + err = mxc622x_acc_i2c_read(acc, acc_data, 2); + + if (err < 0) + { + #ifdef DEBUG + printk(KERN_INFO "%s I2C read error %d\n", MXC622X_ACC_I2C_NAME, err); + #endif + return err; + } + + xyz[0] = (signed char)acc_data[0]; + xyz[1] = (signed char)acc_data[1]; + xyz[2] = 8; //32; + + #ifdef MXC622X_DEBUG + printk("x = %d, y = %d\n", xyz[0], xyz[1]); + #endif + + #ifdef MXC622X_DEBUG + + printk(KERN_INFO "%s read x=%d, y=%d, z=%d\n", + MXC622X_ACC_DEV_NAME, xyz[0], xyz[1], xyz[2]); + printk(KERN_INFO "%s poll interval %d\n", MXC622X_ACC_DEV_NAME, acc->pdata->poll_interval); + + #endif + return err; +} + +static void mxc622x_acc_report_values(struct mxc622x_acc_data *acc, int *xyz) +{ + int txyz,tx,ty,tz = 0; + static int suf=0; // To report every merging value + + tx = xyz[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1]; + ty = xyz[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1]; + tz = xyz[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1]; + suf++; + if (suf > 5) + { + suf = 0; + } + + // packet the x,y,z + txyz = (tx&0x00FF) | ((ty&0xFF)<<8) | ((tz&0xFF)<<16) | ((suf&0xFF)<<24); + input_report_abs(acc->input_dev, ABS_X, txyz); + /*input_report_abs(acc->input_dev, ABS_Y, xyz[1]); + input_report_abs(acc->input_dev, ABS_Z, xyz[2]);*/ + input_sync(acc->input_dev); +} + +static int mxc622x_acc_enable(struct mxc622x_acc_data *acc) +{ + int err; + + if (!atomic_cmpxchg(&acc->enabled, 0, 1)) { + err = mxc622x_acc_device_power_on(acc); + if (err < 0) { + atomic_set(&acc->enabled, 0); + return err; + } + + schedule_delayed_work(&acc->input_work, msecs_to_jiffies( + acc->pdata->poll_interval)); + } + + return 0; +} + +static int mxc622x_acc_disable(struct mxc622x_acc_data *acc) +{ + if (atomic_cmpxchg(&acc->enabled, 1, 0)) { + cancel_delayed_work_sync(&acc->input_work); + mxc622x_acc_device_power_off(acc); + } + + return 0; +} + +static int mxc622x_acc_misc_open(struct inode *inode, struct file *file) +{ + int err; + err = nonseekable_open(inode, file); + if (err < 0) + return err; + + file->private_data = mxc622x_acc_misc_data; + + return 0; +} + +static /*int*/long mxc622x_acc_misc_ioctl(/*struct inode *inode, */struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //u8 buf[4]; + //u8 mask; + //u8 reg_address; + //u8 bit_values; + int err; + int interval; + int xyz[3] = {0}; + struct mxc622x_acc_data *acc = file->private_data; + unsigned int uval = 0; + +// printk(KERN_INFO "%s: %s call with cmd 0x%x and arg 0x%x\n", +// MXC622X_ACC_DEV_NAME, __func__, cmd, (unsigned int)arg); + + switch (cmd) { + case MXC622X_ACC_IOCTL_GET_DELAY: + interval = acc->pdata->poll_interval; + if (copy_to_user(argp, &interval, sizeof(interval))) + return -EFAULT; + break; + + //case MXC622X_ACC_IOCTL_SET_DELAY: + case ECS_IOCTL_APP_SET_DELAY: + if (copy_from_user(&interval, argp, sizeof(interval))) + return -EFAULT; + if (interval < 0 || interval > 1000) + return -EINVAL; + //if(interval > MAX_INTERVAL) + //interval = MAX_INTERVAL; + acc->pdata->poll_interval = max(interval, + acc->pdata->min_interval); + break; + + //case MXC622X_ACC_IOCTL_SET_ENABLE: + case ECS_IOCTL_APP_SET_AFLAG: + if (copy_from_user(&interval, argp, sizeof(interval))) + return -EFAULT; + if (interval > 1) + return -EINVAL; + if (interval) + err = mxc622x_acc_enable(acc); + else + err = mxc622x_acc_disable(acc); + return err; + break; + + case MXC622X_ACC_IOCTL_GET_ENABLE: + interval = atomic_read(&acc->enabled); + if (copy_to_user(argp, &interval, sizeof(interval))) + return -EINVAL; + break; + case MXC622X_ACC_IOCTL_GET_COOR_XYZ: + err = mxc622x_acc_get_acceleration_data(acc, xyz); + if (err < 0) + return err; + #ifdef DEBUG + // printk(KERN_ALERT "%s Get coordinate xyz:[%d, %d, %d]\n", + // __func__, xyz[0], xyz[1], xyz[2]); + #endif + if (copy_to_user(argp, xyz, sizeof(xyz))) { + printk(KERN_ERR " %s %d error in copy_to_user \n", + __func__, __LINE__); + return -EINVAL; + } + break; + case MXC622X_ACC_IOCTL_GET_CHIP_ID: + { + u8 devid = 0; + u8 devinfo[DEVICE_INFO_LEN] = {0}; + err = mxc622x_acc_register_read(acc, &devid, WHO_AM_I); + if (err < 0) { + printk("%s, error read register WHO_AM_I\n", __func__); + return -EAGAIN; + } + sprintf(devinfo, "%s, %#x", DEVICE_INFO, devid); + + if (copy_to_user(argp, devinfo, sizeof(devinfo))) { + printk("%s error in copy_to_user(IOCTL_GET_CHIP_ID)\n", __func__); + return -EINVAL; + } + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: + uval = MXC622X_DRVID; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("mxc622x_driver_id:%d\n",uval); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int mxc622x_acc_misc_close(struct inode *inode, struct file *filp) +{ + return 0; +} + + +static const struct file_operations mxc622x_acc_misc_fops = { + .owner = THIS_MODULE, + .open = mxc622x_acc_misc_open, + .unlocked_ioctl = mxc622x_acc_misc_ioctl, + .release = mxc622x_acc_misc_close, +}; + +static struct miscdevice mxc622x_acc_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = GSENSOR_DEV_NODE,//MXC622X_ACC_DEV_NAME, + .fops = &mxc622x_acc_misc_fops, +}; + +static void mxc622x_acc_input_work_func(struct work_struct *work) +{ + struct mxc622x_acc_data *acc; + + int xyz[3] = { 0 }; + int err; + + acc = mxc622x_acc_misc_data; /*container_of((struct delayed_work *)work, + struct mxc622x_acc_data, input_work); */ + + mutex_lock(&acc->lock); + err = mxc622x_acc_get_acceleration_data(acc, xyz); + if (err < 0) + dev_err(&acc->client->dev, "get_acceleration_data failed\n"); + else + mxc622x_acc_report_values(acc, xyz); + + schedule_delayed_work(&acc->input_work, msecs_to_jiffies( + acc->pdata->poll_interval)); + mutex_unlock(&acc->lock); +} + +#ifdef MXC622X_OPEN_ENABLE +int mxc622x_acc_input_open(struct input_dev *input) +{ + struct mxc622x_acc_data *acc = input_get_drvdata(input); + + return mxc622x_acc_enable(acc); +} + +void mxc622x_acc_input_close(struct input_dev *dev) +{ + struct mxc622x_acc_data *acc = input_get_drvdata(dev); + + mxc622x_acc_disable(acc); +} +#endif + +static int mxc622x_acc_validate_pdata(struct mxc622x_acc_data *acc) +{ + acc->pdata->poll_interval = max(acc->pdata->poll_interval, + acc->pdata->min_interval); + + /* Enforce minimum polling interval */ + if (acc->pdata->poll_interval < acc->pdata->min_interval) { + dev_err(&acc->client->dev, "minimum poll interval violated\n"); + return -EINVAL; + } + + return 0; +} + +static int mxc622x_acc_input_init(struct mxc622x_acc_data *acc) +{ + int err; + // Polling rx data when the interrupt is not used. + if (1/*acc->irq1 == 0 && acc->irq1 == 0*/) { + INIT_DELAYED_WORK(&acc->input_work, mxc622x_acc_input_work_func); + } + + acc->input_dev = input_allocate_device(); + if (!acc->input_dev) { + err = -ENOMEM; + dev_err(&acc->client->dev, "input device allocate failed\n"); + goto err0; + } + +#ifdef MXC622X_ACC_OPEN_ENABLE + acc->input_dev->open = mxc622x_acc_input_open; + acc->input_dev->close = mxc622x_acc_input_close; +#endif + + input_set_drvdata(acc->input_dev, acc); + + set_bit(EV_ABS, acc->input_dev->evbit); + + input_set_abs_params(acc->input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(acc->input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); + input_set_abs_params(acc->input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); + + acc->input_dev->name = GSENSOR_INPUT_NAME;//MXC622X_ACC_INPUT_NAME; + + err = input_register_device(acc->input_dev); + if (err) { + dev_err(&acc->client->dev, + "unable to register input polled device %s\n", + acc->input_dev->name); + goto err1; + } + + return 0; + +err1: + input_free_device(acc->input_dev); +err0: + return err; +} + +static void mxc622x_acc_input_cleanup(struct mxc622x_acc_data *acc) +{ + input_unregister_device(acc->input_dev); + input_free_device(acc->input_dev); +} + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void mxc622x_early_suspend (struct early_suspend* es); +static void mxc622x_early_resume (struct early_suspend* es); +#endif + +static int is_mxc622x(struct i2c_client *client) +{ + int tempvalue; + + /* read chip id */ + tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I); + if ((tempvalue & 0x003F) == WHOAMI_MXC622X_ACC) { + //printk(KERN_INFO "%s I2C driver registered!\n", + // MXC622X_ACC_DEV_NAME); + return 1; + } + return 0; +} + +static int mxc622x_acc_probe(struct i2c_client *client) +{ + + struct mxc622x_acc_data *acc; + + int err = -1; + int tempvalue; + + pr_info("%s: probe start.\n", MXC622X_ACC_DEV_NAME); + + /*if (client->dev.platform_data == NULL) { + dev_err(&client->dev, "platform data is NULL. exiting.\n"); + err = -ENODEV; + goto exit_check_functionality_failed; + }*/ + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "client not i2c capable\n"); + err = -ENODEV; + goto exit_check_functionality_failed; + } + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA)) { + dev_err(&client->dev, "client not smb-i2c capable:2\n"); + err = -EIO; + goto exit_check_functionality_failed; + } + + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)){ + dev_err(&client->dev, "client not smb-i2c capable:3\n"); + err = -EIO; + goto exit_check_functionality_failed; + } + /* + * OK. From now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + */ + + acc = kzalloc(sizeof(struct mxc622x_acc_data), GFP_KERNEL); + if (acc == NULL) { + err = -ENOMEM; + dev_err(&client->dev, + "failed to allocate memory for module data: " + "%d\n", err); + goto exit_alloc_data_failed; + } + + mutex_init(&acc->lock); + mutex_lock(&acc->lock); + + acc->client = client; + mxc622x_i2c_client = client; + i2c_set_clientdata(client, acc); + + /* read chip id */ + tempvalue = i2c_smbus_read_word_data(client, WHO_AM_I); + + if ((tempvalue & 0x003F) == WHOAMI_MXC622X_ACC) { + printk(KERN_INFO "%s I2C driver registered!\n", + MXC622X_ACC_DEV_NAME); + } else { + acc->client = NULL; + printk(KERN_INFO "I2C driver not registered!" + " Device unknown 0x%x\n", tempvalue); + goto err_mutexunlockfreedata; + } + acc->pdata = kzalloc(sizeof(struct mxc622x_acc_platform_data), GFP_KERNEL); + if (acc->pdata == NULL) { + err = -ENOMEM; + dev_err(&client->dev, + "failed to allocate memory for pdata: %d\n", + err); + goto exit_kfree_pdata; + } + + //memcpy(acc->pdata, client->dev.platform_data, sizeof(*acc->pdata)); + acc->pdata->poll_interval = 20; + acc->pdata->min_interval = 10; + + err = mxc622x_acc_validate_pdata(acc); + if (err < 0) { + dev_err(&client->dev, "failed to validate platform data\n"); + goto exit_kfree_pdata; + } + + i2c_set_clientdata(client, acc); + + + /*if (acc->pdata->init) { + err = acc->pdata->init(); + if (err < 0) { + dev_err(&client->dev, "init failed: %d\n", err); + goto err2; + } + }*/ + + err = mxc622x_acc_device_power_on(acc); + if (err < 0) { + dev_err(&client->dev, "power on failed: %d\n", err); + goto err2; + } + + atomic_set(&acc->enabled, 1); + + err = mxc622x_acc_input_init(acc); + if (err < 0) { + dev_err(&client->dev, "input init failed\n"); + goto err_power_off; + } + mxc622x_acc_misc_data = acc; + + err = misc_register(&mxc622x_acc_misc_device); + if (err < 0) { + dev_err(&client->dev, + "misc MXC622X_ACC_DEV_NAME register failed\n"); + goto err_input_cleanup; + } + + mxc622x_acc_device_power_off(acc); + + /* As default, do not report information */ + atomic_set(&acc->enabled, 0); + + acc->on_before_suspend = 0; + + #ifdef CONFIG_HAS_EARLYSUSPEND + acc->early_suspend.suspend = mxc622x_early_suspend; + acc->early_suspend.resume = mxc622x_early_resume; + acc->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; + register_early_suspend(&acc->early_suspend); +#endif + + mutex_unlock(&acc->lock); + + dev_info(&client->dev, "%s: probed\n", MXC622X_ACC_DEV_NAME); + + return 0; + +err_input_cleanup: + mxc622x_acc_input_cleanup(acc); +err_power_off: + mxc622x_acc_device_power_off(acc); +err2: + if (acc->pdata->exit) acc->pdata->exit(); +exit_kfree_pdata: + kfree(acc->pdata); +err_mutexunlockfreedata: + kfree(acc); + mutex_unlock(&acc->lock); + i2c_set_clientdata(client, NULL); + mxc622x_acc_misc_data = NULL; +exit_alloc_data_failed: +exit_check_functionality_failed: + printk(KERN_ERR "%s: Driver Init failed\n", MXC622X_ACC_DEV_NAME); + return err; +} + +static int __devexit mxc622x_acc_remove(struct i2c_client *client) +{ + /* TODO: revisit ordering here once _probe order is finalized */ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data;//i2c_get_clientdata(client); + + misc_deregister(&mxc622x_acc_misc_device); + mxc622x_acc_input_cleanup(acc); + mxc622x_acc_device_power_off(acc); + if (acc->pdata->exit) + acc->pdata->exit(); + kfree(acc->pdata); + kfree(acc); + + return 0; +} + +static int mxc622x_acc_resume(struct platform_device *pdev) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; + + if (acc != NULL && acc->on_before_suspend) { + acc->on_before_suspend = 0; + acc->hw_initialized = 0; + return mxc622x_acc_enable(acc); + } + return 0; +} + +static int mxc622x_acc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; + if (acc != NULL) { + if (atomic_read(&acc->enabled)) { + acc->on_before_suspend = 1; + return mxc622x_acc_disable(acc); + } + } + return 0; +} + +static int mxc622x_probe(struct platform_device *pdev) +{ + return 0; +} + +static int mxc622x_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver mxc622x_driver = { + .probe = mxc622x_probe, + .remove = mxc622x_remove, + .suspend = mxc622x_acc_suspend, + .resume = mxc622x_acc_resume, + .driver = { + .name = GSENSOR_I2C_NAME, + }, +}; + + +#ifdef CONFIG_HAS_EARLYSUSPEND + +static void mxc622x_early_suspend (struct early_suspend* es) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; //i2c_get_clientdata(client); +#ifdef MXC622X_DEBUG + printk("%s.\n", __func__); +#endif + if (acc != NULL) { + if (atomic_read(&acc->enabled)) { + acc->on_before_suspend = 1; + return mxc622x_acc_disable(acc); + } + } +} + +static void mxc622x_early_resume (struct early_suspend* es) +{ + struct mxc622x_acc_data *acc = mxc622x_acc_misc_data; //i2c_get_clientdata(client); +#ifdef MXC622X_DEBUG + printk("%s.\n", __func__); +#endif + + if (acc != NULL && acc->on_before_suspend) { + acc->on_before_suspend = 0; + acc->hw_initialized = 0; + return mxc622x_acc_enable(acc); + } + +} + +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +static const struct i2c_device_id mxc622x_acc_id[] + = { { MXC622X_ACC_DEV_NAME, 0 }, { }, }; + +MODULE_DEVICE_TABLE(i2c, mxc622x_acc_id); + +#if 0 +static struct i2c_driver mxc622x_acc_driver = { + .driver = { + .name = MXC622X_ACC_I2C_NAME, + }, + .probe = mxc622x_acc_probe, + .remove = __devexit_p(mxc622x_acc_remove), + .resume = mxc622x_acc_resume, + .suspend = mxc622x_acc_suspend, + .id_table = mxc622x_acc_id, +}; +#endif + +#ifdef I2C_BUS_NUM_STATIC_ALLOC + +int i2c_static_add_device(struct i2c_board_info *info) +{ + struct i2c_adapter *adapter; + struct i2c_client *client; + int err; + + adapter = i2c_get_adapter(I2C_STATIC_BUS_NUM); + if (!adapter) { + pr_err("%s: can't get i2c adapter\n", __FUNCTION__); + err = -ENODEV; + goto i2c_err; + } + + client = i2c_new_device(adapter, info); + if (!client) { + pr_err("%s: can't add i2c device at 0x%x\n", + __FUNCTION__, (unsigned int)info->addr); + err = -ENODEV; + goto i2c_err; + } + + i2c_put_adapter(adapter); + + return 0; + +i2c_err: + return err; +} + +#endif /*I2C_BUS_NUM_STATIC_ALLOC*/ + +static void mxc622x_platform_release(struct device *device) +{ + dbg("...\n"); + return; +} + + +static struct platform_device mxc622x_device = { + .name = GSENSOR_I2C_NAME, + .id = 0, + .dev = { + .release = mxc622x_platform_release, + }, +}; + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int get_axisset(void* param) +{ + char varbuf[64]; + int n; + int varlen; + + int tmp_offset[3] = {0}; + memset(varbuf, 0, sizeof(varbuf)); + varlen = sizeof(varbuf); + if (wmt_getsyspara("wmt.io.mxc622xsensor", varbuf, &varlen)) { + errlog("Can't get gsensor config in u-boot!!!!\n"); + return -1; + } else { + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_sensorconfig.op, + &l_sensorconfig.int_gpio, + &l_sensorconfig.samp, + &(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]), + &tmp_offset[0], + &tmp_offset[1], + &tmp_offset[2] + ); + if (n != 12) { + printk(KERN_ERR "gsensor format is error in u-boot!!!\n"); + return -1; + } + l_sensorconfig.offset[0] = tmp_offset[0]; + l_sensorconfig.offset[1] = tmp_offset[1]; + l_sensorconfig.offset[2] = tmp_offset[2]; + l_sensorconfig.sensor_samp = l_sensorconfig.samp; + + dbg("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n", + l_sensorconfig.op, + l_sensorconfig.int_gpio, + l_sensorconfig.samp, + 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], + l_sensorconfig.offset[0], + l_sensorconfig.offset[1], + l_sensorconfig.offset[2] + ); + } + return 0; +} + + +static int __init mxc622x_acc_init(void) +{ + int ret = 0; + + printk(KERN_INFO "%s accelerometer driver: init\n", + MXC622X_ACC_I2C_NAME); + ret = get_axisset(NULL); + if (ret < 0) + { + printk("<<<<<%s user choose to no sensor chip!\n", __func__); + return ret; + } + + if (!(this_client = sensor_i2c_register_device(0, GSENSOR_I2C_ADDR, GSENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if(!is_mxc622x(this_client)) + { + dbg("isn't mxc622x gsensor!\n"); + return -1; + } + // parse g-sensor u-boot arg + + /*if (ret) + { + errlog("only for test!\n"); + return -1; + }*/ +#ifdef I2C_BUS_NUM_STATIC_ALLOC + ret = i2c_static_add_device(&mxc622x_i2c_boardinfo); + if (ret < 0) { + pr_err("%s: add i2c device error %d\n", __FUNCTION__, ret); + goto init_err; + } +#endif + ret = mxc622x_acc_probe(this_client); + if (ret) + { + sensor_i2c_unregister_device(this_client); + return -1; + } + // create the platform device + l_dev_class = class_create(THIS_MODULE, GSENSOR_I2C_NAME); + if (IS_ERR(l_dev_class)){ + ret = PTR_ERR(l_dev_class); + printk(KERN_ERR "Can't class_create gsensor device !!\n"); + return ret; + } + if((ret = platform_device_register(&mxc622x_device))) + { + klog("Can't register mc3230 platform devcie!!!\n"); + return ret; + } + if ((ret = platform_driver_register(&mxc622x_driver)) != 0) + { + errlog("Can't register mc3230 platform driver!!!\n"); + return ret; + } + + //return i2c_add_driver(&mxc622x_acc_driver); + +init_err: + return ret; +} + +static void __exit mxc622x_acc_exit(void) +{ + //printk(KERN_INFO "%s accelerometer driver exit\n", MXC622X_ACC_DEV_NAME); + + platform_driver_unregister(&mxc622x_driver); + platform_device_unregister(&mxc622x_device); + class_destroy(l_dev_class); + mxc622x_acc_remove(mxc622x_i2c_client); + sensor_i2c_unregister_device(this_client); + #ifdef I2C_BUS_NUM_STATIC_ALLOC + i2c_unregister_device(mxc622x_i2c_client); + #endif + + //i2c_del_driver(&mxc622x_acc_driver); + return; +} + +module_init(mxc622x_acc_init); +module_exit(mxc622x_acc_exit); + +MODULE_DESCRIPTION("mxc622x accelerometer misc driver"); +MODULE_AUTHOR("Memsic"); +MODULE_LICENSE("GPL"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h new file mode 100755 index 00000000..2b83bb7b --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/mxc622x_gsensor/mxc622x.h @@ -0,0 +1,83 @@ + +/******************** (C) COPYRIGHT 2010 STMicroelectronics ******************** +* +* File Name : mxc622x.h +* Authors : MH - C&I BU - Application Team +* +******************************************************************************** +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES +* OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE +* PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. +* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, +* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE +* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING +* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. +* +* THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. +* +*******************************************************************************/ + + +#ifndef __MXC622X_H__ +#define __MXC622X_H__ + +#include <linux/ioctl.h> /* For IOCTL macros */ +#include <linux/input.h> + +#ifndef DEBUG +#define DEBUG +#endif + +#define GSENSOR_I2C_NAME "mxc622x" +#define GSENSOR_I2C_ADDR 0x15 + +#define MXC622X_ACC_IOCTL_BASE 77 +/** The following define the IOCTL command values via the ioctl macros */ +#define MXC622X_ACC_IOCTL_SET_DELAY _IOW(MXC622X_ACC_IOCTL_BASE, 0, int) +#define MXC622X_ACC_IOCTL_GET_DELAY _IOR(MXC622X_ACC_IOCTL_BASE, 1, int) +#define MXC622X_ACC_IOCTL_SET_ENABLE _IOW(MXC622X_ACC_IOCTL_BASE, 2, int) +#define MXC622X_ACC_IOCTL_GET_ENABLE _IOR(MXC622X_ACC_IOCTL_BASE, 3, int) +#define MXC622X_ACC_IOCTL_GET_COOR_XYZ _IOW(MXC622X_ACC_IOCTL_BASE, 22, int) +#define MXC622X_ACC_IOCTL_GET_CHIP_ID _IOR(MXC622X_ACC_IOCTL_BASE, 255, char[32]) + +/************************************************/ +/* Accelerometer defines section */ +/************************************************/ +#define MXC622X_ACC_DEV_NAME "mxc622x" +#define MXC622X_ACC_INPUT_NAME "accelerometer" +#define MXC622X_ACC_I2C_ADDR 0x15 +#define MXC622X_ACC_I2C_NAME MXC622X_ACC_DEV_NAME + +/* MXC622X register address */ +#define MXC622X_REG_CTRL 0x04 +#define MXC622X_REG_DATA 0x00 + +/* MXC622X control bit */ +#define MXC622X_CTRL_PWRON 0x00 /* power on */ +#define MXC622X_CTRL_PWRDN 0x80 /* power donw */ + +//#if defined(CONFIG_MACH_SP6810A) +//#define I2C_BUS_NUM_STATIC_ALLOC +#define I2C_STATIC_BUS_NUM ( 0) // Need to be modified according to actual setting +//#endif + +struct mxc622x_acc_platform_data { + int poll_interval; + int min_interval; + + int (*init)(void); + void (*exit)(void); + int (*power_on)(void); + int (*power_off)(void); + +}; + +#endif /* __MXC622X_H__ */ + + + diff --git a/ANDROID_3.4.5/drivers/input/sensor/sensor.c b/ANDROID_3.4.5/drivers/input/sensor/sensor.c new file mode 100755 index 00000000..5a82a9fb --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/sensor.c @@ -0,0 +1,114 @@ +#include <linux/i2c.h>
+#include <linux/export.h>
+//#include <linux/mutex.h>
+#include "sensor.h"
+//DEFINE_MUTEX(mutex_client);
+//static struct i2c_client *sensor_client=NULL;
+struct i2c_client *sensor_i2c_register_device(int bus_no, int client_addr, const char *client_name)
+{
+ struct i2c_adapter *adapter = NULL;
+ struct i2c_client *sensor_client=NULL;
+
+ struct i2c_board_info sensor_i2c_board_info = {
+ .type = "unused",
+ .flags = 0x00,
+ .addr = 0xff,
+ .platform_data = NULL,
+ .archdata = NULL,
+ .irq = -1,
+ };
+
+ if ((bus_no<0) || (client_addr>0x7f) || (client_addr<0)|| (!client_name))
+ {
+ printk(KERN_ERR "%s param error! pls check out!\n", __FUNCTION__);
+ return NULL;
+ }
+ printk(KERN_INFO "%s busno %d client_addr 0x%x client_name %s \n", __FUNCTION__, \
+ bus_no, client_addr, client_name);
+
+ sensor_i2c_board_info.addr = client_addr;
+ //sensor_i2c_board_info.type = client_name;
+ strcpy(sensor_i2c_board_info.type, client_name);
+
+ adapter = i2c_get_adapter(bus_no);/*in bus NR*/
+
+ if (NULL == adapter) {
+ printk("can not get i2c adapter, client address error\n");
+ return NULL;
+ }
+
+ //mutex_lock(&mutex_client);
+ sensor_client = i2c_new_device(adapter, &sensor_i2c_board_info);
+
+
+ if (sensor_client == NULL) {
+ printk("allocate i2c client failed\n");
+ //mutex_unlock(&mutex_client);
+ return NULL;
+ }
+ i2c_put_adapter(adapter);
+ //mutex_unlock(&mutex_client);
+
+ return sensor_client;
+}
+EXPORT_SYMBOL(sensor_i2c_register_device);
+
+struct i2c_client *sensor_i2c_register_device2(int bus_no, int client_addr, const char *client_name,void *pdata)
+{
+ struct i2c_adapter *adapter = NULL;
+ struct i2c_client *sensor_client=NULL;
+
+ struct i2c_board_info sensor_i2c_board_info = {
+ .type = "unused",
+ .flags = 0x00,
+ .addr = 0xff,
+ .platform_data = NULL,
+ .archdata = NULL,
+ .irq = -1,
+ };
+
+ if ((bus_no<0) || (client_addr>0x7f) || (client_addr<0)|| (!client_name))
+ {
+ printk(KERN_ERR "%s param error! pls check out!\n", __FUNCTION__);
+ return NULL;
+ }
+ printk(KERN_INFO "%s busno %d client_addr 0x%x client_name %s \n", __FUNCTION__, \
+ bus_no, client_addr, client_name);
+
+ sensor_i2c_board_info.addr = client_addr;
+ sensor_i2c_board_info.platform_data = pdata;
+ //sensor_i2c_board_info.type = client_name;
+ strcpy(sensor_i2c_board_info.type, client_name);
+
+ adapter = i2c_get_adapter(bus_no);/*in bus NR*/
+
+ if (NULL == adapter) {
+ printk("can not get i2c adapter, client address error\n");
+ return NULL;
+ }
+
+ //mutex_lock(&mutex_client);
+ sensor_client = i2c_new_device(adapter, &sensor_i2c_board_info);
+
+
+ if (sensor_client == NULL) {
+ printk("allocate i2c client failed\n");
+ //mutex_unlock(&mutex_client);
+ return NULL;
+ }
+ i2c_put_adapter(adapter);
+ //mutex_unlock(&mutex_client);
+
+ return sensor_client;
+}
+EXPORT_SYMBOL(sensor_i2c_register_device2);
+
+void sensor_i2c_unregister_device(struct i2c_client *client)
+{
+ if (client != NULL)
+ {
+ i2c_unregister_device(client);
+ }
+}
+EXPORT_SYMBOL(sensor_i2c_unregister_device);
+
diff --git a/ANDROID_3.4.5/drivers/input/sensor/sensor.h b/ANDROID_3.4.5/drivers/input/sensor/sensor.h new file mode 100755 index 00000000..9a51433d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/sensor.h @@ -0,0 +1,91 @@ +#ifndef __SENSOR_H__
+#define __SENSOR_H__
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h> +#include <linux/proc_fs.h> +#include <linux/input.h>
+#include <linux/delay.h> +
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+
+//#define GSENSOR_I2C_NAME "unused"
+//#define GSENSOR_I2C_ADDR 0xff
+
+
+#define GSENSOR_PROC_NAME "gsensor_config"
+#define GSENSOR_INPUT_NAME "g-sensor"
+#define GSENSOR_DEV_NODE "sensor_ctrl"
+
+#define SENSOR_PROC_NAME "lsensor_config"
+#define SENSOR_INPUT_NAME "l-sensor"
+#define SENSOR_DEV_NODE "lsensor_ctrl"
+
+#undef dbg +#define dbg(fmt, args...) if (l_sensorconfig.isdbg) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args)
+ +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) +
+enum gsensor_id
+{
+ MMA7660_DRVID = 0,
+ MC3230_DRVID ,
+ DMARD08_DRVID ,
+ DMARD06_DRVID ,
+ DMARD10_DRVID ,
+ MXC622X_DRVID ,
+ MMA8452Q_DRVID ,
+ STK8312_DRVID ,
+ KIONIX_DRVID,
+ DMARD09_DRVID ,
+ //add new gsensor id here, must be in order
+};
+
+#define ISL29023_DRVID 0
+
+struct wmt_gsensor_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
+
+}; +
+///////////////////////// ioctrl cmd ////////////////////////
+#define WMTGSENSOR_IOCTL_MAGIC 0x09
+#define WMT_IOCTL_SENSOR_CAL_OFFSET _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x01, int) //offset calibration
+#define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short)
+#define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short)
+#define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int)
+#define WMT_IOCTL_SENOR_GET_RESOLUTION _IOR(WMTGSENSOR_IOCTL_MAGIC, 0x05, short)
+
+#define WMT_LSENSOR_IOCTL_MAGIC 0x10
+#define LIGHT_IOCTL_SET_ENABLE _IOW(WMT_LSENSOR_IOCTL_MAGIC, 0x01, short)
+
+/* Function prototypes */
+extern struct i2c_client *sensor_i2c_register_device (int bus_no, int client_addr, const char *client_name);
+extern struct i2c_client *sensor_i2c_register_device2(int bus_no, int client_addr, const char *client_name,void *pdata);
+extern void sensor_i2c_unregister_device(struct i2c_client *client);
+
+
+#endif
diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile b/ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile new file mode 100755 index 00000000..19a79f84 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk3310/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_stk3310 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := stk3310.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c b/ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c new file mode 100755 index 00000000..4e9fde10 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk3310/stk3310.c @@ -0,0 +1,644 @@ +/* + * stk3310.c - stk3310 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia <mdigioia@intersil.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/hwmon.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/pm_runtime.h> +#include <linux/input-polldev.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +//#include <linux/earlysuspend.h> +#include <linux/platform_device.h> +#include "../sensor.h" +#define SENSOR_I2C_NAME "stk3310" +#define SENSOR_I2C_ADDR 0x48 + +#undef dbg +#define dbg(fmt, args...) +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(stk3310); + +#define MODULE_NAME "stk3310" + + +struct stk_device { + struct input_polled_dev* input_poll_devl; + struct input_polled_dev* input_poll_devp; + struct i2c_client* client; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + +}; + +static struct stk_device* l_sensorconfig = NULL; +static int l_enable = 1; // 0:don't report data +static int p_enable = 1; // 0:don't report data + +static struct i2c_client *this_client = NULL; + +static DEFINE_MUTEX(mutex); + +static int isl_get_lux_datal(struct i2c_client* client) +{ + __u16 resH, resL; + resL = i2c_smbus_read_byte_data(client, 0x14); + resH = i2c_smbus_read_byte_data(client, 0x13); + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + return -1; + } + return (resH <<8 | resL) ;//* idev->range / idev->resolution; +} + + +static int isl_get_lux_datap(struct i2c_client* client) +{ + __u16 resH, resL; + resL = i2c_smbus_read_byte_data(client, 0x12); + resH = i2c_smbus_read_byte_data(client, 0x11); + if ((resL < 0) || (resH < 0)) + { + errlog("Error to read lux_data!\n"); + return -1; + } + //return (resH <<8 | resL) ;//* idev->range / idev->resolution; + if(resH>0) + return 0; + else + return 6; +} + +//#define PXM 0 +static int isl_set_default_config(struct i2c_client *client) +{ + int ret=0; + unsigned char regval; +//#if PXM + ret = i2c_smbus_write_byte_data(client, 0, (1 << 1)); + if(p_enable) + { + regval = i2c_smbus_read_byte_data(l_sensorconfig->client, 0); + regval |= (1 << 0); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + //ret = i2c_smbus_write_byte_data(client, 0, (1 << 0)); +//#else +//#endif + if (ret < 0) + return -EINVAL; + return 0; +} + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int stk3310_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + int device; + + device= i2c_smbus_read_byte_data(client, 0x3e); + if(0x13==device) + { + printk(KERN_ALERT "stk3310 detected OK\n"); + return 0; + } + else + return -1; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +static void isl_input_lux_poll_l(struct input_polled_dev *dev) +{ + struct stk_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devl->input; + struct i2c_client* client = idev->client; + if (l_enable != 0) + { + mutex_lock(&mutex); + //printk(KERN_ALERT "by flashchen val is %x",val); + input_report_abs(input, ABS_MISC, isl_get_lux_datal(client)); + input_sync(input); + mutex_unlock(&mutex); + } +} + +static void isl_input_lux_poll_p(struct input_polled_dev *dev) +{ + struct stk_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devp->input; + struct i2c_client* client = idev->client; + if (p_enable != 0) + { + mutex_lock(&mutex); + //printk(KERN_ALERT "by flashchen val is %x",val); + input_report_abs(input, ABS_MISC, isl_get_lux_datap(client)); + input_sync(input); + mutex_unlock(&mutex); + } +} + +static struct i2c_device_id stk3310_id[] = { + {"stk3310", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, stk3310_id); + + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmadl_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_datal(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + + +static ssize_t mmadp_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + mutex_lock(&mutex); + lux_data = isl_get_lux_datap(l_sensorconfig->client); + mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmadl_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("stk3310_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static long +mmadp_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + unsigned char regval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + p_enable = enable; + if(p_enable) + { + regval = i2c_smbus_read_byte_data(l_sensorconfig->client, 0); + regval |= (1 << 0); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + else + { + regval = i2c_smbus_read_byte_data(l_sensorconfig->client, 0); + regval &= ~(1 << 0); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("stk3310_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmadl_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadl_read, + .unlocked_ioctl = mmadl_ioctl, +}; + +static struct miscdevice mmadl_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmadl_fops, +}; + +static struct file_operations mmadp_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadp_read, + .unlocked_ioctl = mmadp_ioctl, +}; + +static struct miscdevice mmadp_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "psensor_ctrl", + .fops = &mmadp_fops, +}; +#if 0 +static void stk3310_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void stk3310_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} +#endif + +static int +stk3310_probe(struct i2c_client *client/*, const struct i2c_device_id *id*/) +{ + int res=0; + + struct stk_device* idev = kzalloc(sizeof(struct stk_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + +/* last mod is ALS continuous */ + //pm_runtime_enable(&client->dev); + idev->input_poll_devl = input_allocate_polled_device(); + if(!idev->input_poll_devl) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->input_poll_devp = input_allocate_polled_device(); + if(!idev->input_poll_devp) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + + idev->input_poll_devl->private = idev; + idev->input_poll_devl->poll = isl_input_lux_poll_l; + idev->input_poll_devl->poll_interval = 100;//50; + idev->input_poll_devl->input->open = isl_input_open; + idev->input_poll_devl->input->close = isl_input_close; + idev->input_poll_devl->input->name = "lsensor_lux"; + idev->input_poll_devl->input->id.bustype = BUS_I2C; + idev->input_poll_devl->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devl->input, idev); + input_set_capability(idev->input_poll_devl->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devl->input, ABS_MISC, 0, 16000, 0, 0); + + idev->input_poll_devp->private = idev; + idev->input_poll_devp->poll = isl_input_lux_poll_p; + idev->input_poll_devp->poll_interval = 100;//50; + idev->input_poll_devp->input->open = isl_input_open; + idev->input_poll_devp->input->close = isl_input_close; + idev->input_poll_devp->input->name = "psensor_lux"; + idev->input_poll_devp->input->id.bustype = BUS_I2C; + idev->input_poll_devp->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devp->input, idev); + input_set_capability(idev->input_poll_devp->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devp->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + res = isl_set_default_config(client); + res = misc_register(&mmadl_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerl; + } + res = misc_register(&mmadp_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerp; + } + res = input_register_polled_device(idev->input_poll_devl); + if(res < 0) + goto err_input_register_devicel; + res = input_register_polled_device(idev->input_poll_devp); + if(res < 0) + goto err_input_register_devicep; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = stk3310_early_suspend; + idev->earlysuspend.resume = stk3310_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("stk3310 probe succeed!\n"); + return 0; +err_input_register_devicep: + input_free_polled_device(idev->input_poll_devp); +err_input_register_devicel: + input_free_polled_device(idev->input_poll_devl); +err_misc_registerp: + misc_deregister(&mmadp_device); +err_misc_registerl: + misc_deregister(&mmadl_device); +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + return res; +} + +static int stk3310_remove(struct i2c_client *client) +{ + struct stk_device* idev = i2c_get_clientdata(client); + + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmadl_device); + misc_deregister(&mmadp_device); + input_unregister_polled_device(idev->input_poll_devl); + input_unregister_polled_device(idev->input_poll_devp); + input_free_polled_device(idev->input_poll_devl); + input_free_polled_device(idev->input_poll_devp); + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s stk3310 remove call, \n", __func__); + return 0; +} + +//****************add platform_device & platform_driver for suspend &resume 2013-7-2 +static int ls_probe(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_remove(struct platform_device *pdev){ + //printk("<<<%s\n", __FUNCTION__); + return 0; +} +static int ls_suspend(struct platform_device *pdev, pm_message_t state){ + printk("<<<%s\n", __FUNCTION__); + + return 0; +} + +static int ls_resume(struct platform_device *pdev){ + //return 0; + int ret = 0; + int count = 0; + + struct i2c_client *client = l_sensorconfig->client; + printk("<<<%s\n", __FUNCTION__); + +RETRY: + mutex_lock(&mutex); + + ret = isl_set_default_config(client); + + mutex_unlock(&mutex); + if (ret < 0){ + printk("%s isl_set_default_config fail!\n", __FUNCTION__); + count++; + if (count < 5){ + mdelay(2); + goto RETRY; + } + else + return ret; + } + return 0; + +} +static void lsdev_release(struct device *dev) +{ + return; +} +static struct platform_device lsdev = { + .name = "lsdevice", + .id = -1, + .dev = { + .release = lsdev_release, + }, +}; +static struct platform_driver lsdrv = { + .probe = ls_probe, + .remove = ls_remove, + .suspend = ls_suspend, + .resume = ls_resume, + .driver = { + .name = "lsdevice", + }, +}; +//******************************************************************** + + +static int __init sensor_stk3310_init(void) +{ + int ret = 0; + printk(KERN_INFO MODULE_NAME ": %s stk3310 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even stk3310_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&stk3310_driver); + if (!(this_client = sensor_i2c_register_device(2, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (stk3310_detect(this_client)) + { + errlog("Can't find light sensor stk3310!\n"); + goto detect_fail; + } + if(stk3310_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } + + ret = platform_device_register(&lsdev); + if (ret){ + printk("<<<platform_device_register fail!\n"); + return ret; + } + ret = platform_driver_register(&lsdrv); + if (ret){ + printk("<<<platform_driver_register fail!\n"); + platform_device_unregister(&lsdev); + return ret; + } + return 0; + +detect_fail: + sensor_i2c_unregister_device(this_client); + return -1; +} + +static void __exit sensor_stk3310_exit(void) +{ + printk(KERN_INFO MODULE_NAME ": %s stk3310 exit call \n", __func__); + stk3310_remove(this_client); + sensor_i2c_unregister_device(this_client); + platform_driver_unregister(&lsdrv); + platform_device_unregister(&lsdev); + //i2c_del_driver(&stk3310_driver); +} + +module_init(sensor_stk3310_init); +module_exit(sensor_stk3310_exit); + +MODULE_AUTHOR("flash"); +MODULE_ALIAS("stk3310 ALS"); +MODULE_DESCRIPTION("Stk3310 Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/Makefile new file mode 100755 index 00000000..ba1a46b1 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_gsensor_stk8312 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := stk831x.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8312.h b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8312.h new file mode 100755 index 00000000..c4b25cdc --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8312.h @@ -0,0 +1,51 @@ +/*
+ * Definitions for Sensortek stk8312 accelerometer
+ */
+#ifndef _STK831X_H_
+#define _STK831X_H_
+
+#include <linux/ioctl.h>
+#define STK831X_I2C_NAME "stk831x"
+#define ACC_IDEVICE_NAME "sensor_ctrl"
+#define STKDIR 0x3D
+#define STK_LSB_1G 21
+/* registers for stk8312 registers */
+
+#define STK831X_XOUT 0x00 /* x-axis acceleration*/
+#define STK831X_YOUT 0x01 /* y-axis acceleration*/
+#define STK831X_ZOUT 0x02 /* z-axis acceleration*/
+#define STK831X_TILT 0x03 /* Tilt Status */
+#define STK831X_SRST 0x04 /* Sampling Rate Status */
+#define STK831X_SPCNT 0x05 /* Sleep Count */
+#define STK831X_INTSU 0x06 /* Interrupt setup*/
+#define STK831X_MODE 0x07
+#define STK831X_SR 0x08 /* Sample rate */
+#define STK831X_PDET 0x09 /* Tap Detection */
+#define STK831X_DEVID 0x0B /* Device ID */
+#define STK831X_OFSX 0x0C /* X-Axis offset */
+#define STK831X_OFSY 0x0D /* Y-Axis offset */
+#define STK831X_OFSZ 0x0E /* Z-Axis offset */
+#define STK831X_PLAT 0x0F /* Tap Latency */
+#define STK831X_PWIN 0x10 /* Tap Window */
+#define STK831X_FTH 0x11 /* Free-Fall Threshold */
+#define STK831X_FTM 0x12 /* Free-Fall Time */
+#define STK831X_STH 0x13 /* Shake Threshold */
+#define STK831X_CTRL 0x14 /* Control Register */
+#define STK831X_RESET 0x20 /*software reset*/
+
+/* IOCTLs*/
+#define STK_IOCTL_WRITE _IOW(STKDIR, 0x01, char[8])
+#define STK_IOCTL_READ _IOWR(STKDIR, 0x02, char[8])
+#define STK_IOCTL_SET_ENABLE _IOW(STKDIR, 0x03, char)
+#define STK_IOCTL_GET_ENABLE _IOR(STKDIR, 0x04, char)
+#define STK_IOCTL_SET_DELAY _IOW(STKDIR, 0x05, char)
+#define STK_IOCTL_GET_DELAY _IOR(STKDIR, 0x06, char)
+#define STK_IOCTL_SET_OFFSET _IOW(STKDIR, 0x07, char[3])
+#define STK_IOCTL_GET_OFFSET _IOR(STKDIR, 0x08, char[3])
+#define STK_IOCTL_GET_ACCELERATION _IOR(STKDIR, 0x09, int[3])
+#define STK_IOCTL_SET_RANGE _IOW(STKDIR, 0x10, char)
+#define STK_IOCTL_GET_RANGE _IOR(STKDIR, 0x11, char)
+#define STK_IOCTL_SET_CALI _IOW(STKDIR, 0x12, char)
+
+
+#endif
diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h new file mode 100755 index 00000000..66536ac7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk8313.h @@ -0,0 +1,52 @@ +/*
+ * Definitions for Sensortek stk8313 accelerometer
+ */
+#ifndef _STK831X_H_
+#define _STK831X_H_
+
+#include <linux/ioctl.h>
+#define STK831X_I2C_NAME "stk831x"
+#define ACC_IDEVICE_NAME "accelerometer"
+#define STKDIR 0x3D
+#define STK_LSB_1G 256
+/* register for stk8313 registers */
+
+#define STK831X_XOUT 0x00
+#define STK831X_YOUT 0x02
+#define STK831X_ZOUT 0x04
+#define STK831X_TILT 0x06 /* Tilt Status */
+#define STK831X_SRST 0x07 /* Sampling Rate Status */
+#define STK831X_SPCNT 0x08 /* Sleep Count */
+#define STK831X_INTSU 0x09 /* Interrupt setup*/
+#define STK831X_MODE 0x0A
+#define STK831X_SR 0x0B /* Sample rate */
+#define STK831X_PDET 0x0C /* Tap Detection */
+#define STK831X_DEVID 0x0E /* Device ID */
+#define STK831X_OFSX 0x0F /* X-Axis offset */
+#define STK831X_OFSY 0x10 /* Y-Axis offset */
+#define STK831X_OFSZ 0x11 /* Z-Axis offset */
+#define STK831X_PLAT 0x12 /* Tap Latency */
+#define STK831X_PWIN 0x13 /* Tap Window */
+#define STK831X_FTH 0x14 /* Fre e-Fall Threshold */
+#define STK831X_FTM 0x15 /* Free-Fall Time */
+#define STK831X_STH 0x16 /* Shake Threshold */
+#define STK831X_ISTMP 0x17 /* Interrupt Setup */
+#define STK831X_INTMAP 0x18 /*Interrupt Map*/
+#define STK831X_RESET 0x20 /*software reset*/
+
+/* IOCTLs*/
+#define STK_IOCTL_WRITE _IOW(STKDIR, 0x01, char[8])
+#define STK_IOCTL_READ _IOWR(STKDIR, 0x02, char[8])
+#define STK_IOCTL_SET_ENABLE _IOW(STKDIR, 0x03, char)
+#define STK_IOCTL_GET_ENABLE _IOR(STKDIR, 0x04, char)
+#define STK_IOCTL_SET_DELAY _IOW(STKDIR, 0x05, char)
+#define STK_IOCTL_GET_DELAY _IOR(STKDIR, 0x06, char)
+#define STK_IOCTL_SET_OFFSET _IOW(STKDIR, 0x07, char[3])
+#define STK_IOCTL_GET_OFFSET _IOR(STKDIR, 0x08, char[3])
+#define STK_IOCTL_GET_ACCELERATION _IOR(STKDIR, 0x09, int[3])
+#define STK_IOCTL_SET_RANGE _IOW(STKDIR, 0x10, char)
+#define STK_IOCTL_GET_RANGE _IOR(STKDIR, 0x11, char)
+#define STK_IOCTL_SET_CALI _IOW(STKDIR, 0x12, char)
+
+
+#endif
\ No newline at end of file diff --git a/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c new file mode 100755 index 00000000..68952f9c --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/stk8312_gsensor/stk831x.c @@ -0,0 +1,3590 @@ +/*
+ * stk831x.c - Linux kernel modules for sensortek stk8311/stk8312/stk8313 accelerometer
+ *
+ * Copyright (C) 2011~2013 Lex Hsieh / sensortek <lex_hsieh@sensortek.com.tw>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <asm/uaccess.h>
+#include <linux/input.h>
+#include <asm/gpio.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/version.h>
+#include <linux/pm_runtime.h>
+#include <linux/fs.h>
+#include <linux/workqueue.h>
+#include <linux/fcntl.h>
+#include <linux/syscalls.h>
+
+
+#include "../sensor.h"
+
+
+//#define STK_ALLWINNER_PLATFORM
+#define STK_ACC_DRIVER_VERSION "1.6.1"
+/*choose polling or interrupt mode*/
+#define STK_ACC_POLLING_MODE 1
+#if (!STK_ACC_POLLING_MODE)
+ #define ADDITIONAL_GPIO_CFG 1
+ #define STK_INT_PIN 39
+#endif
+//#define STK_PERMISSION_THREAD
+#define STK_RESUME_RE_INIT
+//#define STK_DEBUG_PRINT
+//#define STK_DEBUG_RAWDATA
+//#define STK_LOWPASS
+#define STK_FIR_LEN 4
+
+///////////////////////////////////////
+#define CONFIG_SENSORS_STK8312////////
+/////////////////////////////////////
+#define STK_ZG_FILTER
+#ifdef CONFIG_SENSORS_STK8312
+ #define STK_ZG_COUNT 1
+#elif defined (CONFIG_SENSORS_STK8313)
+ #define STK_ZG_COUNT 4
+#endif
+
+#define STK_TUNE
+#ifdef CONFIG_SENSORS_STK8312
+ #define STK_TUNE_XYOFFSET 3
+ #define STK_TUNE_ZOFFSET 6
+ #define STK_TUNE_NOISE 5
+#elif defined (CONFIG_SENSORS_STK8313)
+ #define STK_TUNE_XYOFFSET 35
+ #define STK_TUNE_ZOFFSET 75
+ #define STK_TUNE_NOISE 20
+#endif
+#define STK_TUNE_NUM 125
+#define STK_TUNE_DELAY 125
+//Flourtise - Kevin
+#define STK_WMT_PLATFORM
+#ifdef STK_WMT_PLATFORM
+ //#define STK8312_DRVID 7
+ ///////////////////////// ioctrl cmd ////////////////////////^M
+ #define WMTGSENSOR_IOCTL_MAGIC 0x09
+ #define WMT_IOCTL_SENSOR_CAL_OFFSET _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x01, int) //offset calibration^M
+ #define ECS_IOCTL_APP_SET_AFLAG _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x02, short)
+ #define ECS_IOCTL_APP_SET_DELAY _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x03, short)
+ #define WMT_IOCTL_SENSOR_GET_DRVID _IOW(WMTGSENSOR_IOCTL_MAGIC, 0x04, unsigned int)
+ #define WMT_IOCTL_SENOR_GET_RESOLUTION _IOR(WMTGSENSOR_IOCTL_MAGIC, 0x05, short)
+
+#endif
+//Flourise - Kevin
+#ifndef STK_WMT_PLATFORM
+ #ifdef CONFIG_SENSORS_STK8313
+ #include <linux/stk8313.h>
+ #elif defined CONFIG_SENSORS_STK8312
+ #include <linux/stk8312.h>
+ #else
+ #error "What's your stk accelerometer?"
+ #endif
+#else
+ #ifdef CONFIG_SENSORS_STK8313
+ #include "stk8313.h"
+ #elif defined CONFIG_SENSORS_STK8312
+ #include "stk8312.h"
+ #else
+ #error "What's your stk accelerometer?"
+ #endif
+#endif /* #ifndef STK_ALLWINNER_PLATFORM */
+
+SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode);
+
+static struct i2c_client *this_client = NULL;
+
+//add 2013-6-24
+#define GSENSOR_NAME "stk8312"
+static struct class* l_dev_class = NULL;
+struct stk8312_config
+{
+ int op;
+ int int_gpio; //0-3
+ int xyz_axis[3][2]; // (axis,direction)
+ int rxyz_axis[3][2];
+ int irq;
+ struct proc_dir_entry* sensor_proc;
+ int sensorlevel;
+ int shake_enable; // 1--enable shake, 0--disable shake
+ int manual_rotation; // 0--landance, 90--vertical
+ struct input_dev *input_dev;
+ //struct work_struct work;
+ struct delayed_work work; // for polling
+ struct workqueue_struct *queue;
+ int isdbg; // 0-- no debug log, 1--show debug log
+ int sensor_samp; // 1,2,4,8,16,32,64,120
+ int sensor_enable; // 0 --> disable sensor, 1 --> enable sensor
+ int test_pass;
+ spinlock_t spinlock;
+ int pollcnt; // the counts of polling
+ int offset[3];
+};
+
+static struct stk8312_config l_sensorconfig = {
+ .op = 0,
+ .int_gpio = 3,
+ .xyz_axis = {
+ {ABS_X, -1},
+ {ABS_Y, 1},
+ {ABS_Z, -1},
+ },
+ .irq = 6,
+ .int_gpio = 3,
+ .sensor_proc = NULL,
+ .sensorlevel = 0,
+ .shake_enable = 0, // default enable shake
+ .isdbg = 0,
+ .sensor_samp = 10, // 4sample/second
+ .sensor_enable = 1, // enable sensor
+ .test_pass = 0, // for test program
+ .pollcnt = 0, // Don't report the x,y,z when the driver is loaded until 2~3 seconds
+ .offset = {0,0,0},
+};
+//******************************************
+
+#if defined(STK_LOWPASS)
+#define MAX_FIR_LEN 32
+struct data_filter {
+ s16 raw[MAX_FIR_LEN][3];
+ int sum[3];
+ int num;
+ int idx;
+};
+#endif
+
+struct stk831x_data
+{
+ struct input_dev *input_dev;
+ struct work_struct stk_work;
+ int irq;
+ int raw_data[3];
+ atomic_t enabled;
+ unsigned char delay;
+ struct mutex write_lock;
+ bool first_enable;
+ bool re_enable;
+ char recv_reg;
+#if STK_ACC_POLLING_MODE
+ struct hrtimer acc_timer;
+ struct work_struct stk_acc_work;
+ struct workqueue_struct *stk_acc_wq;
+ ktime_t acc_poll_delay;
+#endif //#if STK_ACC_POLLING_MODE
+ atomic_t cali_status;
+#if defined(STK_LOWPASS)
+ atomic_t firlength;
+ atomic_t fir_en;
+ struct data_filter fir;
+#endif
+};
+
+#define STK831X_HOLD_ODR
+#define STK831X_INIT_ODR 1//2 //2:100Hz, 3:50Hz, 4:25Hz
+#define STK831X_SAMPLE_TIME_MIN_NO 2
+#define STK831X_SAMPLE_TIME_NO 5
+const static int STK831X_SAMPLE_TIME[STK831X_SAMPLE_TIME_NO] = {2500, 5000, 10000, 20000, 40000};
+static struct stk831x_data *stk831x_data_ptr;
+static int event_since_en = 0;
+static int event_since_en_limit = 20;
+#if (!STK_ACC_POLLING_MODE)
+static struct workqueue_struct *stk_mems_work_queue = NULL;
+#endif //#if STK_ACC_POLLING_MODE
+
+#define STK_DEBUG_CALI
+#define STK_SAMPLE_NO 10
+#define STK_ACC_CALI_VER0 0x3D
+#define STK_ACC_CALI_VER1 0x01
+#define STK_ACC_CALI_FILE "/data/misc/stkacccali.conf"
+#define STK_ACC_CALI_FILE_SIZE 10
+
+#define STK_K_SUCCESS_TUNE 0x04
+#define STK_K_SUCCESS_FT2 0x03
+#define STK_K_SUCCESS_FT1 0x02
+#define STK_K_SUCCESS_FILE 0x01
+#define STK_K_NO_CALI 0xFF
+#define STK_K_RUNNING 0xFE
+#define STK_K_FAIL_LRG_DIFF 0xFD
+#define STK_K_FAIL_OPEN_FILE 0xFC
+#define STK_K_FAIL_W_FILE 0xFB
+#define STK_K_FAIL_R_BACK 0xFA
+#define STK_K_FAIL_R_BACK_COMP 0xF9
+#define STK_K_FAIL_I2C 0xF8
+#define STK_K_FAIL_K_PARA 0xF7
+#define STK_K_FAIL_OTP_OUT_RG 0xF6
+#define STK_K_FAIL_ENG_I2C 0xF5
+#define STK_K_FAIL_FT1_USD 0xF4
+#define STK_K_FAIL_FT2_USD 0xF3
+#define STK_K_FAIL_WRITE_NOFST 0xF2
+#define STK_K_FAIL_OTP_5T 0xF1
+#define STK_K_FAIL_PLACEMENT 0xF0
+
+
+#define POSITIVE_Z_UP 0
+#define NEGATIVE_Z_UP 1
+#define POSITIVE_X_UP 2
+#define NEGATIVE_X_UP 3
+#define POSITIVE_Y_UP 4
+#define NEGATIVE_Y_UP 5
+static unsigned char stk831x_placement = POSITIVE_Z_UP;
+#ifdef STK_TUNE
+static char stk_tune_offset_record[3] = {0};
+static int stk_tune_offset[3] = {0};
+static int stk_tune_sum[3] = {0};
+static int stk_tune_max[3] = {0};
+static int stk_tune_min[3] = {0};
+static int stk_tune_index = 0;
+static int stk_tune_done = 0;
+#endif
+
+static int stk_store_in_ic( struct stk831x_data *stk, char otp_offset[], char FT_index, uint32_t delay_ms);
+static int32_t stk_get_file_content(char * r_buf, int8_t buf_size);
+static int stk_store_in_file(char offset[], char mode);
+static int STK831x_ReadByteOTP(char rReg, char *value);
+static int STK831x_SetEnable(struct stk831x_data *stk, char en);
+static int STK831x_SetCali(struct stk831x_data *stk, char sstate);
+static int32_t stk_get_ic_content(struct stk831x_data *stk);
+static int STK831x_SetOffset(char buf[]);
+static void stk_handle_first_en(struct stk831x_data *stk);
+static int STK831x_GetDelay(struct stk831x_data *stk, uint32_t* gdelay_ns);
+static int STK831x_SetDelay(struct stk831x_data *stk, uint32_t sdelay_ns);
+
+#ifdef STK_ALLWINNER_PLATFORM
+static int gsensor_direct_x = 0;
+static int gsensor_direct_y = 0;
+static int gsensor_direct_z = 0;
+static int gsensor_xy_revert = 0;
+
+enum {
+ DEBUG_INIT = 1U << 0,
+ DEBUG_CONTROL_INFO = 1U << 1,
+ DEBUG_DATA_INFO = 1U << 2,
+ DEBUG_SUSPEND = 1U << 3,
+};
+static u32 debug_mask = 0;
+#define dprintk(level_mask, fmt, arg...) if (unlikely(debug_mask & level_mask)) \
+ printk(KERN_DEBUG fmt , ## arg)
+
+module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
+#endif /* #ifdef STK_ALLWINNER_PLATFORM */
+
+#ifdef STK_ALLWINNER_PLATFORM
+/* Addresses to scan */
+static union
+{
+ unsigned short dirty_addr_buf[2];
+ const unsigned short normal_i2c[2];
+}u_i2c_addr = {{0x00},};
+static __u32 twi_id = 1;
+#endif /* #ifdef STK_ALLWINNER_PLATFORM */
+
+/**
+ * gsensor_fetch_sysconfig_para - get config info from sysconfig.fex file.
+ * return value:
+ * = 0; success;
+ * < 0; err
+ */
+#ifdef STK_ALLWINNER_A20_A31
+static int gsensor_fetch_sysconfig_para(void)
+{
+ int ret = -1;
+ int device_used = -1;
+ script_item_u val;
+ script_item_value_type_e type;
+
+ dprintk(DEBUG_INIT, "========%s===================\n", __func__);
+
+ type = script_get_item("gsensor_para", "gsensor_used", &val);
+
+ if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {
+ pr_err("%s: type err device_used = %d. \n", __func__, val.val);
+ goto script_get_err;
+ }
+ device_used = val.val;
+
+ if (1 == device_used) {
+ type = script_get_item("gsensor_para", "gsensor_twi_id", &val);
+ if(SCIRPT_ITEM_VALUE_TYPE_INT != type){
+ pr_err("%s: type err twi_id = %d. \n", __func__, val.val);
+ goto script_get_err;
+ }
+ twi_id = val.val;
+
+ dprintk(DEBUG_INIT, "%s: twi_id is %d. \n", __func__, twi_id);
+
+ if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_direct_x", &val)){
+ pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__);
+ goto script_get_err;
+ }
+ gsensor_direct_x = val.val;
+
+ if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_direct_y", &val)){
+ pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__);
+ goto script_get_err;
+ }
+ gsensor_direct_y = val.val;
+ if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_direct_z", &val)){
+ pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__);
+ goto script_get_err;
+ }
+ gsensor_direct_z = val.val;
+
+ if(SCIRPT_ITEM_VALUE_TYPE_INT != script_get_item("gsensor_para", "gsensor_xy_revert", &val)){
+ pr_err("%s: line: %d: script_get_item err. \n", __FILE__, __LINE__);
+ goto script_get_err;
+ }
+ gsensor_xy_revert = val.val;
+
+ ret = 0;
+
+ } else {
+ pr_err("%s: gsensor_unused. \n", __func__);
+ ret = -1;
+ }
+
+ return ret;
+
+script_get_err:
+ pr_notice("=========script_get_err============\n");
+ return ret;
+}
+#endif /* #ifdef STK_ALLWINNER_A20_A31 */
+
+#ifdef STK_ALLWINNER_A13
+static int gsensor_fetch_sysconfig_para(void)
+{
+ int ret = -1;
+ int device_used = -1;
+
+ printk("========%s===================\n", __func__);
+
+ if(SCRIPT_PARSER_OK != (ret = script_parser_fetch("gsensor_para", "gsensor_used", &device_used, 1))){
+ pr_err("%s: script_parser_fetch err.ret = %d. \n", __func__, ret);
+ goto script_parser_fetch_err;
+ }
+ if(1 == device_used){
+ if(SCRIPT_PARSER_OK != script_parser_fetch("gsensor_para", "gsensor_twi_id", &twi_id, 1)){
+ pr_err("%s: script_parser_fetch err. \n",__func__);
+ goto script_parser_fetch_err;
+ }
+ printk("%s: twi_id is %d. \n", __func__, twi_id);
+
+ stk8313_pin_hd = gpio_request_ex("gsensor_para",NULL);
+ if (stk8313_pin_hd==-1) {
+ printk("stk8313_pin_hd pin request error!\n");
+ }
+ ret = 0;
+
+ }else{
+ pr_err("%s: gsensor_unused. \n", __func__);
+ ret = -1;
+ }
+
+ return ret;
+
+ script_parser_fetch_err:
+ pr_notice("=========script_parser_fetch_err============\n");
+ return ret;
+}
+#endif /* #ifdef STK_ALLWINNER_A13 */
+
+
+
+static int STK_i2c_Rx(char *rxData, int length)
+{
+ uint8_t retry;
+ struct i2c_msg msgs[] =
+ {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = rxData,
+ },
+ {
+ .addr = this_client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = rxData,
+ },
+ };
+
+ for (retry = 0; retry <= 3; retry++)
+ {
+ if (i2c_transfer(this_client->adapter, msgs, 2) > 0)
+ break;
+ else
+ mdelay(10);
+ }
+
+ if (retry > 3)
+ {
+ printk(KERN_ERR "%s: retry over 3\n", __func__);
+ return -EIO;
+ }
+ else
+ return 0;
+}
+
+static int STK_i2c_Tx(char *txData, int length)
+{
+ int retry;
+ struct i2c_msg msg[] =
+ {
+ {
+ .addr = this_client->addr,
+ .flags = 0,
+ .len = length,
+ .buf = txData,
+ },
+ };
+
+ for (retry = 0; retry <= 3; retry++)
+ {
+ if (i2c_transfer(this_client->adapter, msg, 1) > 0)
+ break;
+ else
+ mdelay(10);
+ }
+
+ if(*txData >= 0x21 && *txData <= 0x3E)
+ {
+ for (retry = 0; retry <= 3; retry++)
+ {
+ if (i2c_transfer(this_client->adapter, msg, 1) > 0)
+ break;
+ else
+ mdelay(10);
+ }
+ }
+
+ if (retry > 3)
+ {
+ printk(KERN_ERR "%s: i2c error, retry over 3\n", __func__);
+ return -EIO;
+ }
+ else
+ return 0;
+}
+
+
+static int STK831X_SetVD(struct stk831x_data *stk)
+{
+ int result;
+ char buffer[2] = "";
+ char reg24;
+
+ msleep(2);
+ result = STK831x_ReadByteOTP(0x70, ®24);
+ if(result < 0)
+ {
+ printk(KERN_ERR "%s: read back error, result=%d\n", __func__, result);
+ return result;
+ }
+
+ if(reg24 != 0)
+ {
+ buffer[0] = 0x24;
+ buffer[1] = reg24;
+ //printk(KERN_INFO "%s:write 0x%x to 0x24\n", __func__, buffer[1]);
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ }
+ else
+ {
+ //printk(KERN_INFO "%s: reg24=0, do nothing\n", __func__);
+ return 0;
+ }
+
+ buffer[0] = 0x24;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ if(buffer[0] != reg24)
+ {
+ printk(KERN_ERR "%s: error, reg24=0x%x, read=0x%x\n", __func__, reg24, buffer[0]);
+ return -1;
+ }
+ //printk(KERN_INFO "%s: successfully", __func__);
+ return 0;
+}
+
+#ifdef STK_TUNE
+static void STK831x_ResetPara(void)
+{
+ int ii;
+ for(ii=0;ii<3;ii++)
+ {
+ stk_tune_sum[ii] = 0;
+ stk_tune_min[ii] = 4096;
+ stk_tune_max[ii] = -4096;
+ }
+ return;
+}
+
+static void STK831x_Tune(struct stk831x_data *stk, int acc[])
+{
+ int ii;
+ char offset[3];
+ char mode_reg;
+ int result;
+ char buffer[2] = "";
+
+ if (stk_tune_done==0)
+ {
+ if( event_since_en >= STK_TUNE_DELAY)
+ {
+ if ((abs(acc[0]) <= STK_TUNE_XYOFFSET) && (abs(acc[1]) <= STK_TUNE_XYOFFSET)
+ && (abs(abs(acc[2])-STK_LSB_1G) <= STK_TUNE_ZOFFSET))
+ stk_tune_index++;
+ else
+ stk_tune_index = 0;
+
+ if (stk_tune_index==0)
+ STK831x_ResetPara();
+ else
+ {
+ for(ii=0;ii<3;ii++)
+ {
+ stk_tune_sum[ii] += acc[ii];
+ if(acc[ii] > stk_tune_max[ii])
+ stk_tune_max[ii] = acc[ii];
+ if(acc[ii] < stk_tune_min[ii])
+ stk_tune_min[ii] = acc[ii];
+ }
+ }
+
+ if(stk_tune_index == STK_TUNE_NUM)
+ {
+ for(ii=0;ii<3;ii++)
+ {
+ if((stk_tune_max[ii] - stk_tune_min[ii]) > STK_TUNE_NOISE)
+ {
+ stk_tune_index = 0;
+ STK831x_ResetPara();
+ return;
+ }
+ }
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return;
+ }
+ mode_reg = buffer[0];
+ buffer[1] = mode_reg & 0xF8;
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return;
+ }
+
+ stk_tune_offset[0] = stk_tune_sum[0]/STK_TUNE_NUM;
+ stk_tune_offset[1] = stk_tune_sum[1]/STK_TUNE_NUM;
+ if (acc[2] > 0)
+ stk_tune_offset[2] = stk_tune_sum[2]/STK_TUNE_NUM - STK_LSB_1G;
+ else
+ stk_tune_offset[2] = stk_tune_sum[2]/STK_TUNE_NUM - (-STK_LSB_1G);
+
+ offset[0] = (char) (-stk_tune_offset[0]);
+ offset[1] = (char) (-stk_tune_offset[1]);
+ offset[2] = (char) (-stk_tune_offset[2]);
+ STK831x_SetOffset(offset);
+ stk_tune_offset_record[0] = offset[0];
+ stk_tune_offset_record[1] = offset[1];
+ stk_tune_offset_record[2] = offset[2];
+
+ buffer[1] = mode_reg | 0x1;
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return;
+ }
+
+ STK831X_SetVD(stk);
+ stk_store_in_file(offset, STK_K_SUCCESS_TUNE);
+ stk_tune_done = 1;
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_TUNE);
+ event_since_en = 0;
+ printk(KERN_INFO "%s:TUNE done, %d,%d,%d\n", __func__, offset[0], offset[1],offset[2]);
+ }
+ }
+ }
+ /*
+ else
+ {
+ if(atomic_read(&stk->enabled))
+ {
+ acc[0] -= stk_tune_offset[0];
+ acc[1] -= stk_tune_offset[1];
+ acc[2] -= stk_tune_offset[2];
+ }
+ }
+ */
+ // printk(KERN_INFO "%s:TUNE %4d,%4d,%4d [%d,%d,%d] %d\n", __func__, acc[0], acc[1], acc[2], stk_tune_offset[0], stk_tune_offset[1],stk_tune_offset[2],stk_tune_done);
+ return;
+}
+#endif
+
+#ifdef CONFIG_SENSORS_STK8312
+static int STK831x_CheckReading(int acc[], bool clear)
+{
+ static int check_result = 0;
+
+ if(acc[0] == 127 || acc[0] == -128 || acc[1] == 127 || acc[1] == -128 ||
+ acc[2] == 127 || acc[2] == -128)
+ {
+ printk(KERN_INFO "%s: acc:%o,%o,%o\n", __func__, acc[0], acc[1], acc[2]);
+ check_result++;
+ }
+ if(clear)
+ {
+ if(check_result == 3)
+ {
+ event_since_en_limit = 10000;
+ printk(KERN_INFO "%s: incorrect reading\n", __func__);
+ check_result = 0;
+ return 1;
+ }
+ check_result = 0;
+ }
+ return 0;
+}
+static inline int STK831x_ReadSensorData(struct stk831x_data *stk)
+{
+ int result;
+ char buffer[3] = {0};
+ int acc_xyz[3] = {0};
+#ifdef STK_ZG_FILTER
+ s16 zero_fir = 0;
+#endif
+#ifdef STK_LOWPASS
+ int idx, firlength = atomic_read(&stk->firlength);
+#endif
+ int k_status = atomic_read(&stk->cali_status);
+ memset(buffer, 0, 3);
+
+ buffer[0] = STK831X_XOUT;
+ result = STK_i2c_Rx(buffer, 3);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:i2c transfer error\n", __func__);
+ return result;
+ }
+
+ if (buffer[0] & 0x80)
+ acc_xyz[0] = buffer[0] - 256;
+ else
+ acc_xyz[0] = buffer[0];
+ if (buffer[1] & 0x80)
+ acc_xyz[1] = buffer[1] - 256;
+ else
+ acc_xyz[1] = buffer[1];
+ if (buffer[2] & 0x80)
+ acc_xyz[2] = buffer[2] - 256;
+ else
+ acc_xyz[2] = buffer[2];
+
+#ifdef STK_DEBUG_RAWDATA
+ printk(KERN_INFO "%s:RAW %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+
+ if(event_since_en == 16 || event_since_en == 17)
+ STK831x_CheckReading(acc_xyz, false);
+ else if(event_since_en == 18)
+ STK831x_CheckReading(acc_xyz, true);
+
+ if(k_status == STK_K_RUNNING)
+ {
+ stk->raw_data[0] = acc_xyz[0];
+ stk->raw_data[1] = acc_xyz[1];
+ stk->raw_data[2] = acc_xyz[2];
+ return 0;
+ }
+
+#ifdef STK_LOWPASS //not define 2013-7-12
+ if(atomic_read(&stk->fir_en))
+ {
+ if(stk->fir.num < firlength)
+ {
+ stk->fir.raw[stk->fir.num][0] = acc_xyz[0];
+ stk->fir.raw[stk->fir.num][1] = acc_xyz[1];
+ stk->fir.raw[stk->fir.num][2] = acc_xyz[2];
+ stk->fir.sum[0] += acc_xyz[0];
+ stk->fir.sum[1] += acc_xyz[1];
+ stk->fir.sum[2] += acc_xyz[2];
+ stk->fir.num++;
+ stk->fir.idx++;
+ }
+ else
+ {
+ idx = stk->fir.idx % firlength;
+ stk->fir.sum[0] -= stk->fir.raw[idx][0];
+ stk->fir.sum[1] -= stk->fir.raw[idx][1];
+ stk->fir.sum[2] -= stk->fir.raw[idx][2];
+ stk->fir.raw[idx][0] = acc_xyz[0];
+ stk->fir.raw[idx][1] = acc_xyz[1];
+ stk->fir.raw[idx][2] = acc_xyz[2];
+ stk->fir.sum[0] += acc_xyz[0];
+ stk->fir.sum[1] += acc_xyz[1];
+ stk->fir.sum[2] += acc_xyz[2];
+ stk->fir.idx++;
+ acc_xyz[0] = stk->fir.sum[0]/firlength;
+ acc_xyz[1] = stk->fir.sum[1]/firlength;
+ acc_xyz[2] = stk->fir.sum[2]/firlength;
+ }
+ }
+#ifdef STK_DEBUG_RAWDATA
+ printk(KERN_INFO "%s:After FIR %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+
+#endif /* #ifdef STK_LOWPASS */
+
+
+
+#ifdef STK_TUNE //define
+ if((k_status&0xF0) != 0)
+ STK831x_Tune(stk, acc_xyz);
+#endif
+
+#ifdef STK_ZG_FILTER //define
+ if( abs(acc_xyz[0]) <= STK_ZG_COUNT) // 1
+ acc_xyz[0] = (acc_xyz[0]*zero_fir);
+ if( abs(acc_xyz[1]) <= STK_ZG_COUNT)
+ acc_xyz[1] = (acc_xyz[1]*zero_fir);
+ if( abs(acc_xyz[2]) <= STK_ZG_COUNT)
+ acc_xyz[2] = (acc_xyz[2]*zero_fir);
+#endif /* #ifdef STK_ZG_FILTER */
+
+ stk->raw_data[0] = acc_xyz[0];
+ stk->raw_data[1] = acc_xyz[1];
+ stk->raw_data[2] = acc_xyz[2];
+
+ return 0;
+}
+
+#elif defined CONFIG_SENSORS_STK8313
+static int STK831x_CheckReading(int acc[], bool clear)
+{
+ static int check_result = 0;
+
+ if(acc[0] == 2047 || acc[0] == -2048 || acc[1] == 2047 || acc[1] == -2048 ||
+ acc[2] == 2047 || acc[2] == -2048)
+ {
+ printk(KERN_INFO "%s: acc:%o,%o,%o\n", __func__, acc[0], acc[1], acc[2]);
+ check_result++;
+ }
+ if(clear)
+ {
+ if(check_result == 3)
+ {
+ event_since_en_limit = 10000;
+ printk(KERN_INFO "%s: incorrect reading\n", __func__);
+ check_result = 0;
+ return 1;
+ }
+ check_result = 0;
+ }
+ return 0;
+}
+static int STK831x_ReadSensorData(struct stk831x_data *stk)
+{
+ int result;
+ char buffer[6] = "";
+ int acc_xyz[3] = {0};
+#ifdef STK_ZG_FILTER
+ s16 zero_fir = 0;
+#endif
+#ifdef STK_LOWPASS
+ int idx, firlength = atomic_read(&stk->firlength);
+#endif
+ int k_status = atomic_read(&stk->cali_status);
+
+ memset(buffer, 0, 6);
+ buffer[0] = STK831X_XOUT;
+ result = STK_i2c_Rx(buffer, 6);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:i2c transfer error\n", __func__);
+ return result;
+ }
+
+ if (buffer[0] & 0x80)
+ acc_xyz[0] = ((int)buffer[0]<<4) + (buffer[1]>>4) - 4096;
+ else
+ acc_xyz[0] = ((int)buffer[0]<<4) + (buffer[1]>>4);
+ if (buffer[2] & 0x80)
+ acc_xyz[1] = ((int)buffer[2]<<4) + (buffer[3]>>4) - 4096;
+ else
+ acc_xyz[1] = ((int)buffer[2]<<4) + (buffer[3]>>4);
+ if (buffer[4] & 0x80)
+ acc_xyz[2] = ((int)buffer[4]<<4) + (buffer[5]>>4) - 4096;
+ else
+ acc_xyz[2] = ((int)buffer[4]<<4) + (buffer[5]>>4);
+
+#ifdef STK_DEBUG_RAWDATA
+ printk(KERN_INFO "%s:RAW %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+
+ if(event_since_en == 16 || event_since_en == 17)
+ STK831x_CheckReading(acc_xyz, false);
+ else if(event_since_en == 18)
+ STK831x_CheckReading(acc_xyz, true);
+ if(k_status == STK_K_RUNNING)
+ {
+ stk->raw_data[0] = acc_xyz[0];
+ stk->raw_data[1] = acc_xyz[1];
+ stk->raw_data[2] = acc_xyz[2];
+ return 0;
+ }
+
+#ifdef STK_LOWPASS
+ if(atomic_read(&stk->fir_en))
+ {
+ if(stk->fir.num < firlength)
+ {
+ stk->fir.raw[stk->fir.num][0] = acc_xyz[0];
+ stk->fir.raw[stk->fir.num][1] = acc_xyz[1];
+ stk->fir.raw[stk->fir.num][2] = acc_xyz[2];
+ stk->fir.sum[0] += acc_xyz[0];
+ stk->fir.sum[1] += acc_xyz[1];
+ stk->fir.sum[2] += acc_xyz[2];
+ stk->fir.num++;
+ stk->fir.idx++;
+ }
+ else
+ {
+ idx = stk->fir.idx % firlength;
+ stk->fir.sum[0] -= stk->fir.raw[idx][0];
+ stk->fir.sum[1] -= stk->fir.raw[idx][1];
+ stk->fir.sum[2] -= stk->fir.raw[idx][2];
+ stk->fir.raw[idx][0] = acc_xyz[0];
+ stk->fir.raw[idx][1] = acc_xyz[1];
+ stk->fir.raw[idx][2] = acc_xyz[2];
+ stk->fir.sum[0] += acc_xyz[0];
+ stk->fir.sum[1] += acc_xyz[1];
+ stk->fir.sum[2] += acc_xyz[2];
+ stk->fir.idx++;
+ acc_xyz[0] = stk->fir.sum[0]/firlength;
+ acc_xyz[1] = stk->fir.sum[1]/firlength;
+ acc_xyz[2] = stk->fir.sum[2]/firlength;
+ }
+ }
+#ifdef STK_DEBUG_RAWDATA
+ printk(KERN_INFO "%s:After FIR %4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+
+#endif /* #ifdef STK_LOWPASS */
+
+
+#ifdef STK_TUNE
+ if((k_status&0xF0) != 0)
+ STK831x_Tune(stk, acc_xyz);
+#endif
+
+#ifdef STK_ZG_FILTER
+ if( abs(acc_xyz[0]) <= STK_ZG_COUNT)
+ acc_xyz[0] = (acc_xyz[0]*zero_fir);
+ if( abs(acc_xyz[1]) <= STK_ZG_COUNT)
+ acc_xyz[1] = (acc_xyz[1]*zero_fir);
+ if( abs(acc_xyz[2]) <= STK_ZG_COUNT)
+ acc_xyz[2] = (acc_xyz[2]*zero_fir);
+#endif /* #ifdef STK_ZG_FILTER */
+
+ stk->raw_data[0] = acc_xyz[0];
+ stk->raw_data[1] = acc_xyz[1];
+ stk->raw_data[2] = acc_xyz[2];
+
+ return 0;
+}
+#endif
+
+static int STK831x_ReportValue(struct stk831x_data *stk)
+{
+ //int tmp = 0;
+ int rxyz[3] = {0};
+#if 1//comment 2013-8-15
+ if(event_since_en < 1200)
+ {
+ event_since_en++;
+ if(event_since_en < 12)
+ return 0;
+ }
+#endif
+//add by gandy
+ //gsensor_direct_x = 0;
+#if 0
+ if (gsensor_direct_x == 1)
+ stk->raw_data[0] = -stk->raw_data[0];
+
+ //gsensor_direct_y = 1;
+ if (gsensor_direct_y == 1)
+ stk->raw_data[1] = -stk->raw_data[1];
+
+ gsensor_direct_z = 1;
+ if (gsensor_direct_z == 1)
+ stk->raw_data[2] = -stk->raw_data[2];
+
+ if (gsensor_xy_revert == 1)
+ {
+ tmp = stk->raw_data[0];
+ stk->raw_data[0] = stk->raw_data[1];
+ stk->raw_data[1] = tmp;
+ }
+#endif
+//end add
+ //add coord
+ //printk("x,y,z(%d,%d,%d)\n", stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+ rxyz[0] = stk->raw_data[0];
+ rxyz[1] = stk->raw_data[1];
+ rxyz[2] = stk->raw_data[2];
+ stk->raw_data[0] = rxyz[l_sensorconfig.xyz_axis[0][0]]*l_sensorconfig.xyz_axis[0][1];
+ stk->raw_data[1] = rxyz[l_sensorconfig.xyz_axis[1][0]]*l_sensorconfig.xyz_axis[1][1];
+ stk->raw_data[2] = rxyz[l_sensorconfig.xyz_axis[2][0]]*l_sensorconfig.xyz_axis[2][1];
+
+
+#if 0
+ stk->raw_data[0] = stk->raw_data[0]*9800*100/2133; //add for stk8132 21.34
+ stk->raw_data[1] = stk->raw_data[1]*9800*100/2133;
+ stk->raw_data[2] = stk->raw_data[2]*9800*100/2133;
+#endif
+
+
+#ifdef STK_DEBUG_PRINT
+ printk(KERN_INFO "%s:%4d,%4d,%4d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+ input_report_abs(stk->input_dev, ABS_X, stk->raw_data[0]);
+ input_report_abs(stk->input_dev, ABS_Y, stk->raw_data[1]);
+ input_report_abs(stk->input_dev, ABS_Z, stk->raw_data[2]);
+
+ //printk(" after x,y,z(%d,%d,%d)\n", stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+ input_sync(stk->input_dev);
+ return 0;
+}
+
+static int STK831x_SetOffset(char buf[])
+{
+ int result;
+ char buffer[4] = "";
+
+ buffer[0] = STK831X_OFSX;
+ buffer[1] = buf[0];
+ buffer[2] = buf[1];
+ buffer[3] = buf[2];
+ result = STK_i2c_Tx(buffer, 4);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ return 0;
+}
+
+static int STK831x_GetOffset(char buf[])
+{
+ int result;
+ char buffer[3] = "";
+
+ buffer[0] = STK831X_OFSX;
+ result = STK_i2c_Rx(buffer, 3);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ buf[0] = buffer[0];
+ buf[1] = buffer[1];
+ buf[2] = buffer[2];
+ return 0;
+}
+
+static int STK831x_SetEnable(struct stk831x_data *stk, char en)
+{
+ int result;
+ char buffer[2] = "";
+ int new_enabled = (en)?1:0;
+ int k_status = atomic_read(&stk->cali_status);
+
+ if(new_enabled == atomic_read(&stk->enabled))
+ return 0;
+ printk(KERN_INFO "%s:%x\n", __func__, en);
+
+ //mutex_lock(&stk->write_lock);
+ if(stk->first_enable && k_status != STK_K_RUNNING)
+ stk_handle_first_en(stk);
+
+ mutex_lock(&stk->write_lock);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto e_err_i2c;
+ }
+ if(en)
+ {
+ buffer[1] = (buffer[0] & 0xF8) | 0x01;
+ event_since_en = 0;
+#ifdef STK_TUNE
+ if((k_status&0xF0) != 0 && stk_tune_done == 0)
+ {
+ stk_tune_index = 0;
+ STK831x_ResetPara();
+ }
+#endif
+ }
+ else
+ buffer[1] = (buffer[0] & 0xF8);
+
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto e_err_i2c;
+ }
+ mutex_unlock(&stk->write_lock);
+
+ if(stk->first_enable && k_status != STK_K_RUNNING)
+ {
+ stk->first_enable = false;
+ msleep(2);
+ result = stk_get_ic_content(stk);
+ }
+ if(en)
+ {
+ STK831X_SetVD(stk);
+#if STK_ACC_POLLING_MODE
+ hrtimer_start(&stk->acc_timer, stk->acc_poll_delay, HRTIMER_MODE_REL);
+#else
+ enable_irq((unsigned int)stk->irq);
+#endif //#if STK_ACC_POLLING_MODE
+ }
+ else
+ {
+#if STK_ACC_POLLING_MODE
+ hrtimer_cancel(&stk->acc_timer);
+ cancel_work_sync(&stk->stk_acc_work);
+#else
+ disable_irq((unsigned int)stk->irq);
+#endif //#if STK_ACC_POLLING_MODE
+ }
+ //mutex_unlock(&stk->write_lock);
+ atomic_set(&stk->enabled, new_enabled);
+ return 0;
+
+e_err_i2c:
+ mutex_unlock(&stk->write_lock);
+ return result;
+}
+
+static int STK831x_GetEnable(struct stk831x_data *stk, char* gState)
+{
+ *gState = atomic_read(&stk->enabled);
+ return 0;
+}
+
+static int STK831x_SetDelay(struct stk831x_data *stk, uint32_t sdelay_ns)
+{
+ unsigned char sr_no;
+ int result;
+ char buffer[2] = "";
+ uint32_t sdelay_us = sdelay_ns / 1000;
+
+ for(sr_no=(STK831X_SAMPLE_TIME_NO-1);sr_no>0;sr_no--)
+ {
+ if(sdelay_us >= STK831X_SAMPLE_TIME[sr_no])
+ break;
+ }
+ if(sr_no < STK831X_SAMPLE_TIME_MIN_NO)
+ sr_no = STK831X_SAMPLE_TIME_MIN_NO;
+
+#ifdef STK831X_HOLD_ODR
+ sr_no = STK831X_INIT_ODR;
+#endif
+
+#ifdef STK_DEBUG_PRINT
+#ifdef STK831X_HOLD_ODR
+ printk(KERN_INFO "%s:sdelay_us=%d, Hold delay = %d\n", __func__, sdelay_us, STK831X_SAMPLE_TIME[STK831X_INIT_ODR]);
+#else
+ printk(KERN_INFO "%s:sdelay_us=%d\n", __func__, sdelay_us);
+#endif
+#endif
+ mutex_lock(&stk->write_lock);
+ if(stk->delay == sr_no)
+ {
+ mutex_unlock(&stk->write_lock);
+ return 0;
+ }
+ buffer[0] = STK831X_SR;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto d_err_i2c;
+ }
+
+ buffer[1] = (buffer[0] & 0xF8) | ((sr_no & 0x07));
+ buffer[0] = STK831X_SR;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto d_err_i2c;
+ }
+ stk->delay = sr_no;
+#if STK_ACC_POLLING_MODE
+ stk->acc_poll_delay = ns_to_ktime(STK831X_SAMPLE_TIME[sr_no]*USEC_PER_MSEC);
+#endif
+
+#if defined(STK_LOWPASS)
+ stk->fir.num = 0;
+ stk->fir.idx = 0;
+ stk->fir.sum[0] = 0;
+ stk->fir.sum[1] = 0;
+ stk->fir.sum[2] = 0;
+#endif
+ mutex_unlock(&stk->write_lock);
+
+ return 0;
+d_err_i2c:
+ mutex_unlock(&stk->write_lock);
+ return result;
+}
+
+static int STK831x_GetDelay(struct stk831x_data *stk, uint32_t *gdelay_ns)
+{
+ int result;
+ char buffer[2] = "";
+
+ mutex_lock(&stk->write_lock);
+ buffer[0] = STK831X_SR;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ mutex_unlock(&stk->write_lock);
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ mutex_unlock(&stk->write_lock);
+ *gdelay_ns = (uint32_t) STK831X_SAMPLE_TIME[(int)buffer[0]] * 1000;
+ return 0;
+}
+
+
+static int STK831x_SetRange(char srange)
+{
+ int result;
+ char buffer[2] = "";
+#ifdef STK_DEBUG_PRINT
+ printk(KERN_INFO "%s:range=0x%x\n", __func__, srange);
+#endif
+
+ if(srange >= 3)
+ {
+ printk(KERN_ERR "%s:parameter out of range\n", __func__);
+ return -1;
+ }
+
+ buffer[0] = STK831X_STH;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+
+ buffer[1] = (buffer[0] & 0x3F) | srange<<6;
+ buffer[0] = STK831X_STH;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ return 0;
+}
+
+static int STK831x_GetRange(char* grange)
+{
+ int result;
+ char buffer = 0;
+
+ buffer = STK831X_STH;
+ result = STK_i2c_Rx(&buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+ *grange = buffer >> 6;
+ return 0;
+}
+
+static int STK831x_ReadByteOTP(char rReg, char *value)
+{
+ int redo = 0;
+ int result;
+ char buffer[2] = "";
+ *value = 0;
+
+ buffer[0] = 0x3D;
+ buffer[1] = rReg;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto eng_i2c_r_err;
+ }
+ buffer[0] = 0x3F;
+ buffer[1] = 0x02;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto eng_i2c_r_err;
+ }
+
+ do {
+ msleep(2);
+ buffer[0] = 0x3F;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto eng_i2c_r_err;
+ }
+ if(buffer[0]& 0x80)
+ {
+ break;
+ }
+ redo++;
+ }while(redo < 10);
+
+ if(redo == 10)
+ {
+ printk(KERN_ERR "%s:OTP read repeat read 10 times! Failed!\n", __func__);
+ return -STK_K_FAIL_OTP_5T;
+ }
+ buffer[0] = 0x3E;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ goto eng_i2c_r_err;
+ }
+ *value = buffer[0];
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s: read 0x%x=0x%x\n", __func__, rReg, *value);
+#endif
+ return 0;
+
+eng_i2c_r_err:
+ return -STK_K_FAIL_ENG_I2C;
+}
+
+static int STK831x_WriteByteOTP(char wReg, char value)
+{
+ int finish_w_check = 0;
+ int result;
+ char buffer[2] = "";
+ char read_back, value_xor = value;
+ int re_write = 0;
+
+ do
+ {
+ finish_w_check = 0;
+ buffer[0] = 0x3D;
+ buffer[1] = wReg;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result);
+ goto eng_i2c_w_err;
+ }
+ buffer[0] = 0x3E;
+ buffer[1] = value_xor;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result);
+ goto eng_i2c_w_err;
+ }
+ buffer[0] = 0x3F;
+ buffer[1] = 0x01;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result);
+ goto eng_i2c_w_err;
+ }
+
+ do
+ {
+ msleep(1);
+ buffer[0] = 0x3F;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, err=0x%x\n", __func__, result);
+ goto eng_i2c_w_err;
+ }
+ if(buffer[0]& 0x80)
+ {
+ result = STK831x_ReadByteOTP(wReg, &read_back);
+ if(result < 0)
+ {
+ printk(KERN_ERR "%s: read back error, result=%d\n", __func__, result);
+ goto eng_i2c_w_err;
+ }
+
+ if(read_back == value)
+ {
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s: write 0x%x=0x%x successfully\n", __func__, wReg, value);
+#endif
+ re_write = 0xFF;
+ break;
+ }
+ else
+ {
+ printk(KERN_ERR "%s: write 0x%x=0x%x, read 0x%x=0x%x, try again\n", __func__, wReg, value_xor, wReg, read_back);
+ value_xor = read_back ^ value;
+ re_write++;
+ break;
+ }
+ }
+ finish_w_check++;
+ } while (finish_w_check < 5);
+ } while(re_write < 10);
+
+ if(re_write == 10)
+ {
+ printk(KERN_ERR "%s: write 0x%x fail, read=0x%x, write=0x%x, target=0x%x\n", __func__, wReg, read_back, value_xor, value);
+ return -STK_K_FAIL_OTP_5T;
+ }
+
+ return 0;
+
+eng_i2c_w_err:
+ return -STK_K_FAIL_ENG_I2C;
+}
+
+static int STK831x_WriteOffsetOTP(struct stk831x_data *stk, int FT, char offsetData[])
+{
+ char regR[6], reg_comp[3];
+ char mode;
+ int result;
+ char buffer[2] = "";
+ int ft_pre_trim = 0;
+
+ if(FT==1)
+ {
+ result = STK831x_ReadByteOTP(0x7F, ®R[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+
+ if(regR[0]&0x10)
+ {
+ printk(KERN_ERR "%s: 0x7F=0x%x\n", __func__, regR[0]);
+ return -STK_K_FAIL_FT1_USD;
+ }
+ }
+ else if (FT == 2)
+ {
+ result = STK831x_ReadByteOTP(0x7F, ®R[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+
+ if(regR[0]&0x20)
+ {
+ printk(KERN_ERR "%s: 0x7F=0x%x\n", __func__, regR[0]);
+ return -STK_K_FAIL_FT2_USD;
+ }
+ }
+//Check End
+
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ mode = buffer[0];
+ buffer[1] = (mode | 0x01);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ msleep(2);
+
+
+ if(FT == 1)
+ {
+ result = STK831x_ReadByteOTP(0x40, ®_comp[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_ReadByteOTP(0x41, ®_comp[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_ReadByteOTP(0x42, ®_comp[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+ }
+ else if (FT == 2)
+ {
+ result = STK831x_ReadByteOTP(0x50, ®_comp[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_ReadByteOTP(0x51, ®_comp[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_ReadByteOTP(0x52, ®_comp[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+ }
+
+ result = STK831x_ReadByteOTP(0x30, ®R[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_ReadByteOTP(0x31, ®R[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_ReadByteOTP(0x32, ®R[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+
+ if(reg_comp[0] == regR[0] && reg_comp[1] == regR[1] && reg_comp[2] == regR[2])
+ {
+ printk(KERN_INFO "%s: ft pre-trimmed\n", __func__);
+ ft_pre_trim = 1;
+ }
+
+ if(!ft_pre_trim)
+ {
+ if(FT == 1)
+ {
+ result = STK831x_WriteByteOTP(0x40, regR[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x41, regR[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x42, regR[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+ }
+ else if (FT == 2)
+ {
+ result = STK831x_WriteByteOTP(0x50, regR[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x51, regR[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x52, regR[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+ }
+ }
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s:OTP step1 Success!\n", __func__);
+#endif
+ buffer[0] = 0x2A;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ else
+ {
+ regR[0] = buffer[0];
+ }
+ buffer[0] = 0x2B;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ else
+ {
+ regR[1] = buffer[0];
+ }
+ buffer[0] = 0x2E;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ else
+ {
+ regR[2] = buffer[0];
+ }
+ buffer[0] = 0x2F;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ else
+ {
+ regR[3] = buffer[0];
+ }
+ buffer[0] = 0x32;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ else
+ {
+ regR[4] = buffer[0];
+ }
+ buffer[0] = 0x33;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto common_i2c_error;
+ }
+ else
+ {
+ regR[5] = buffer[0];
+ }
+
+ regR[1] = offsetData[0];
+ regR[3] = offsetData[2];
+ regR[5] = offsetData[1];
+ if(FT==1)
+ {
+ result = STK831x_WriteByteOTP(0x44, regR[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x46, regR[3]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x48, regR[5]);
+ if(result < 0)
+ goto eng_i2c_err;
+
+ if(!ft_pre_trim)
+ {
+ result = STK831x_WriteByteOTP(0x43, regR[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x45, regR[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x47, regR[4]);
+ if(result < 0)
+ goto eng_i2c_err;
+ }
+ }
+ else if (FT == 2)
+ {
+ result = STK831x_WriteByteOTP(0x54, regR[1]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x56, regR[3]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x58, regR[5]);
+ if(result < 0)
+ goto eng_i2c_err;
+
+ if(!ft_pre_trim)
+ {
+ result = STK831x_WriteByteOTP(0x53, regR[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x55, regR[2]);
+ if(result < 0)
+ goto eng_i2c_err;
+ result = STK831x_WriteByteOTP(0x57, regR[4]);
+ if(result < 0)
+ goto eng_i2c_err;
+ }
+ }
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s:OTP step2 Success!\n", __func__);
+#endif
+ result = STK831x_ReadByteOTP(0x7F, ®R[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+
+ if(FT==1)
+ regR[0] = regR[0]|0x10;
+ else if(FT==2)
+ regR[0] = regR[0]|0x20;
+
+ result = STK831x_WriteByteOTP(0x7F, regR[0]);
+ if(result < 0)
+ goto eng_i2c_err;
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s:OTP step3 Success!\n", __func__);
+#endif
+ return 0;
+
+eng_i2c_err:
+ printk(KERN_ERR "%s: read/write eng i2c error, result=0x%x\n", __func__, result);
+ return result;
+
+common_i2c_error:
+ printk(KERN_ERR "%s: read/write common i2c error, result=0x%x\n", __func__, result);
+ return result;
+}
+
+static int STK831X_VerifyCali(struct stk831x_data *stk, unsigned char en_dis, uint32_t delay_ms)
+{
+ unsigned char axis, state;
+ int acc_ave[3] = {0, 0, 0};
+ const unsigned char verify_sample_no = 3;
+#ifdef CONFIG_SENSORS_STK8313
+ const unsigned char verify_diff = 25;
+#elif defined CONFIG_SENSORS_STK8312
+ const unsigned char verify_diff = 2;
+#endif
+ int result;
+ char buffer[2] = "";
+ int ret = 0;
+
+ if(en_dis)
+ {
+ STK831x_SetDelay(stk, 10000000);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return -STK_K_FAIL_I2C;
+ }
+ buffer[1] = (buffer[0] & 0xF8) | 0x01;
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return -STK_K_FAIL_I2C;
+ }
+ STK831X_SetVD(stk);
+ msleep(delay_ms*15);
+ }
+
+ for(state=0;state<verify_sample_no;state++)
+ {
+ STK831x_ReadSensorData(stk);
+ for(axis=0;axis<3;axis++)
+ acc_ave[axis] += stk->raw_data[axis];
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s: acc=%d,%d,%d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+ msleep(delay_ms);
+ }
+
+ for(axis=0;axis<3;axis++)
+ acc_ave[axis] /= verify_sample_no;
+
+ switch(stk831x_placement)
+ {
+ case POSITIVE_X_UP:
+ acc_ave[0] -= STK_LSB_1G;
+ break;
+ case NEGATIVE_X_UP:
+ acc_ave[0] += STK_LSB_1G;
+ break;
+ case POSITIVE_Y_UP:
+ acc_ave[1] -= STK_LSB_1G;
+ break;
+ case NEGATIVE_Y_UP:
+ acc_ave[1] += STK_LSB_1G;
+ break;
+ case POSITIVE_Z_UP:
+ acc_ave[2] -= STK_LSB_1G;
+ break;
+ case NEGATIVE_Z_UP:
+ acc_ave[2] += STK_LSB_1G;
+ break;
+ default:
+ printk("%s: invalid stk831x_placement=%d\n", __func__, stk831x_placement);
+ ret = -STK_K_FAIL_PLACEMENT;
+ break;
+ }
+ if(abs(acc_ave[0]) > verify_diff || abs(acc_ave[1]) > verify_diff || abs(acc_ave[2]) > verify_diff)
+ {
+ printk(KERN_INFO "%s:Check data x:%d, y:%d, z:%d\n", __func__,acc_ave[0],acc_ave[1],acc_ave[2]);
+ printk(KERN_ERR "%s:Check Fail, Calibration Fail\n", __func__);
+ ret = -STK_K_FAIL_LRG_DIFF;
+ }
+#ifdef STK_DEBUG_CALI
+ else
+ printk(KERN_INFO "%s:Check data pass\n", __func__);
+#endif
+ if(en_dis)
+ {
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return -STK_K_FAIL_I2C;
+ }
+ buffer[1] = (buffer[0] & 0xF8);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed, result=0x%x\n", __func__, result);
+ return -STK_K_FAIL_I2C;
+ }
+ }
+
+ return ret;
+}
+
+
+static int STK831x_SetCali(struct stk831x_data *stk, char sstate)
+{
+ char org_enable;
+ int acc_ave[3] = {0, 0, 0};
+ int state, axis;
+ int new_offset[3];
+ char char_offset[3] = {0};
+ int result;
+ char buffer[2] = "";
+ char reg_offset[3] = {0};
+ char store_location = sstate;
+ uint32_t gdelay_ns, real_delay_ms;
+ char offset[3];
+
+ atomic_set(&stk->cali_status, STK_K_RUNNING);
+ //sstate=1, STORE_OFFSET_IN_FILE
+ //sstate=2, STORE_OFFSET_IN_IC
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s:store_location=%d\n", __func__, store_location);
+#endif
+ if((store_location != 3 && store_location != 2 && store_location != 1) || (stk831x_placement < 0 || stk831x_placement > 5) )
+ {
+ printk(KERN_ERR "%s, invalid parameters\n", __func__);
+ atomic_set(&stk->cali_status, STK_K_FAIL_K_PARA);
+ return -STK_K_FAIL_K_PARA;
+ }
+ STK831x_GetDelay(stk, &gdelay_ns);
+ STK831x_GetEnable(stk, &org_enable);
+ if(org_enable)
+ STK831x_SetEnable(stk, 0);
+ STK831x_SetDelay(stk, 10000000);
+ msleep(1);
+ STK831x_GetDelay(stk, &real_delay_ms);
+ real_delay_ms = (real_delay_ms + (NSEC_PER_MSEC / 2)) / NSEC_PER_MSEC;
+ printk(KERN_INFO "%s: delay =%d ms\n", __func__, real_delay_ms);
+
+ STK831x_SetOffset(reg_offset);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+ buffer[1] = (buffer[0] & 0xF8) | 0x01;
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+
+ STK831X_SetVD(stk);
+ if(store_location >= 2)
+ {
+ buffer[0] = 0x2B;
+ buffer[1] = 0x0;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+ buffer[0] = 0x2F;
+ buffer[1] = 0x0;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+ buffer[0] = 0x33;
+ buffer[1] = 0x0;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+ }
+
+ msleep(real_delay_ms*20);
+ for(state=0;state<STK_SAMPLE_NO;state++)
+ {
+ STK831x_ReadSensorData(stk);
+ for(axis=0;axis<3;axis++)
+ acc_ave[axis] += stk->raw_data[axis];
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s: acc=%d,%d,%d\n", __func__, stk->raw_data[0], stk->raw_data[1], stk->raw_data[2]);
+#endif
+ msleep(real_delay_ms);
+ }
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+ buffer[1] = (buffer[0] & 0xF8);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto err_i2c_rw;
+ }
+
+ for(axis=0;axis<3;axis++)
+ {
+ if(acc_ave[axis] >= 0)
+ acc_ave[axis] = (acc_ave[axis] + STK_SAMPLE_NO / 2) / STK_SAMPLE_NO;
+ else
+ acc_ave[axis] = (acc_ave[axis] - STK_SAMPLE_NO / 2) / STK_SAMPLE_NO;
+
+ }
+ if(acc_ave[2] <= -1)
+ stk831x_placement = NEGATIVE_Z_UP;
+ else if((acc_ave[2] >= 1))
+ stk831x_placement = POSITIVE_Z_UP;
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s:stk831x_placement=%d\n", __func__, stk831x_placement);
+#endif
+
+ switch(stk831x_placement)
+ {
+ case POSITIVE_X_UP:
+ acc_ave[0] -= STK_LSB_1G;
+ break;
+ case NEGATIVE_X_UP:
+ acc_ave[0] += STK_LSB_1G;
+ break;
+ case POSITIVE_Y_UP:
+ acc_ave[1] -= STK_LSB_1G;
+ break;
+ case NEGATIVE_Y_UP:
+ acc_ave[1] += STK_LSB_1G;
+ break;
+ case POSITIVE_Z_UP:
+ acc_ave[2] -= STK_LSB_1G;
+ break;
+ case NEGATIVE_Z_UP:
+ acc_ave[2] += STK_LSB_1G;
+ break;
+ default:
+ printk("%s: invalid stk831x_placement=%d\n", __func__, stk831x_placement);
+ atomic_set(&stk->cali_status, STK_K_FAIL_PLACEMENT);
+ return -STK_K_FAIL_K_PARA;
+ break;
+ }
+
+ for(axis=0;axis<3;axis++)
+ {
+ acc_ave[axis] = -acc_ave[axis];
+ new_offset[axis] = acc_ave[axis];
+ char_offset[axis] = new_offset[axis];
+ }
+#ifdef STK_DEBUG_CALI
+ printk(KERN_INFO "%s: New offset:%d,%d,%d\n", __func__, new_offset[0], new_offset[1], new_offset[2]);
+#endif
+ if(store_location == 1)
+ {
+ STK831x_SetOffset(char_offset);
+ msleep(1);
+ STK831x_GetOffset(reg_offset);
+ for(axis=0;axis<3;axis++)
+ {
+ if(char_offset[axis] != reg_offset[axis])
+ {
+ printk(KERN_ERR "%s: set offset to register fail!, char_offset[%d]=%d,reg_offset[%d]=%d\n",
+ __func__, axis,char_offset[axis], axis, reg_offset[axis]);
+ atomic_set(&stk->cali_status, STK_K_FAIL_WRITE_NOFST);
+ return -STK_K_FAIL_WRITE_NOFST;
+ }
+ }
+
+
+ result = STK831X_VerifyCali(stk, 1, real_delay_ms);
+ if(result)
+ {
+ printk(KERN_ERR "%s: calibration check fail, result=0x%x\n", __func__, result);
+ atomic_set(&stk->cali_status, -result);
+ }
+ else
+ {
+ result = stk_store_in_file(char_offset, STK_K_SUCCESS_FILE);
+ if(result)
+ {
+ printk(KERN_INFO "%s:write calibration failed\n", __func__);
+ atomic_set(&stk->cali_status, -result);
+ }
+ else
+ {
+ printk(KERN_INFO "%s successfully\n", __func__);
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_FILE);
+ }
+
+ }
+ }
+ else if(store_location >= 2)
+ {
+ for(axis=0; axis<3; axis++)
+ {
+#ifdef CONFIG_SENSORS_STK8313
+ new_offset[axis]>>=2;
+#endif
+ char_offset[axis] = (char)new_offset[axis];
+ if( (char_offset[axis]>>7)==0)
+ {
+ if(char_offset[axis] >= 0x20 )
+ {
+ printk(KERN_ERR "%s: offset[%d]=0x%x is too large, limit to 0x1f\n",
+ __func__, axis, char_offset[axis] );
+ char_offset[axis] = 0x1F;
+ //atomic_set(&stk->cali_status, STK_K_FAIL_OTP_OUT_RG);
+ //return -STK_K_FAIL_OTP_OUT_RG;
+ }
+ }
+ else
+ {
+ if(char_offset[axis] <= 0xDF)
+ {
+ printk(KERN_ERR "%s: offset[%d]=0x%x is too large, limit to 0x20\n",
+ __func__, axis, char_offset[axis]);
+ char_offset[axis] = 0x20;
+ //atomic_set(&stk->cali_status, STK_K_FAIL_OTP_OUT_RG);
+ //return -STK_K_FAIL_OTP_OUT_RG;
+ }
+ else
+ char_offset[axis] = char_offset[axis] & 0x3f;
+ }
+ }
+
+ printk(KERN_INFO "%s: OTP offset:0x%x,0x%x,0x%x\n", __func__, char_offset[0], char_offset[1], char_offset[2]);
+ if(store_location == 2)
+ {
+ result = stk_store_in_ic( stk, char_offset, 1, real_delay_ms);
+ if(result == 0)
+ {
+ printk(KERN_INFO "%s successfully\n", __func__);
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_FT1);
+ }
+ else
+ {
+ printk(KERN_ERR "%s fail, result=%d\n", __func__, result);
+ }
+ }
+ else if(store_location == 3)
+ {
+ result = stk_store_in_ic( stk, char_offset, 2, real_delay_ms);
+ if(result == 0)
+ {
+ printk(KERN_INFO "%s successfully\n", __func__);
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_FT2);
+ }
+ else
+ {
+ printk(KERN_ERR "%s fail, result=%d\n", __func__, result);
+ }
+ }
+ offset[0] = offset[1] = offset[2] = 0;
+ stk_store_in_file(offset, store_location);
+ }
+#ifdef STK_TUNE
+ stk_tune_offset_record[0] = 0;
+ stk_tune_offset_record[1] = 0;
+ stk_tune_offset_record[2] = 0;
+ stk_tune_done = 1;
+#endif
+ stk->first_enable = false;
+ STK831x_SetDelay(stk, gdelay_ns);
+
+ if(org_enable)
+ STK831x_SetEnable(stk, 1);
+ return 0;
+
+err_i2c_rw:
+ stk->first_enable = false;
+ if(org_enable)
+ STK831x_SetEnable(stk, 1);
+ printk(KERN_ERR "%s: i2c read/write error, err=0x%x\n", __func__, result);
+ atomic_set(&stk->cali_status, STK_K_FAIL_I2C);
+ return result;
+}
+
+
+static int STK831x_GetCali(struct stk831x_data *stk)
+{
+ char r_buf[STK_ACC_CALI_FILE_SIZE] = {0};
+ char offset[3], mode;
+ int cnt, result;
+ char regR[6];
+
+#ifdef STK_TUNE
+ printk(KERN_INFO "%s: stk_tune_done=%d, stk_tune_index=%d, stk_tune_offset=%d,%d,%d\n", __func__,
+ stk_tune_done, stk_tune_index, stk_tune_offset_record[0], stk_tune_offset_record[1],
+ stk_tune_offset_record[2]);
+#endif
+ if ((stk_get_file_content(r_buf, STK_ACC_CALI_FILE_SIZE)) == 0)
+ {
+ if(r_buf[0] == STK_ACC_CALI_VER0 && r_buf[1] == STK_ACC_CALI_VER1)
+ {
+ offset[0] = r_buf[2];
+ offset[1] = r_buf[3];
+ offset[2] = r_buf[4];
+ mode = r_buf[5];
+ printk(KERN_INFO "%s:file offset:%#02x,%#02x,%#02x,%#02x\n",
+ __func__, offset[0], offset[1], offset[2], mode);
+ }
+ else
+ {
+ printk(KERN_ERR "%s: cali version number error! r_buf=0x%x,0x%x,0x%x,0x%x,0x%x\n",
+ __func__, r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4]);
+ }
+ }
+ else
+ printk(KERN_INFO "%s: No file offset\n", __func__);
+
+ for(cnt=0x43;cnt<0x49;cnt++)
+ {
+ result = STK831x_ReadByteOTP(cnt, &(regR[cnt-0x43]));
+ if(result < 0)
+ printk(KERN_ERR "%s: STK831x_ReadByteOTP failed, ret=%d\n", __func__, result);
+ }
+ printk(KERN_INFO "%s: OTP 0x43-0x49:%#02x,%#02x,%#02x,%#02x,%#02x,%#02x\n", __func__, regR[0],
+ regR[1], regR[2],regR[3], regR[4], regR[5]);
+
+ for(cnt=0x53;cnt<0x59;cnt++)
+ {
+ result = STK831x_ReadByteOTP(cnt, &(regR[cnt-0x53]));
+ if(result < 0)
+ printk(KERN_ERR "%s: STK831x_ReadByteOTP failed, ret=%d\n", __func__, result);
+ }
+ printk(KERN_INFO "%s: OTP 0x53-0x59:%#02x,%#02x,%#02x,%#02x,%#02x,%#02x\n", __func__, regR[0],
+ regR[1], regR[2],regR[3], regR[4], regR[5]);
+
+ return 0;
+}
+
+static int STK831x_Init(struct stk831x_data *stk, struct i2c_client *client)
+{
+ int result;
+ char buffer[2] = "";
+
+#ifdef CONFIG_SENSORS_STK8312
+ printk(KERN_INFO "%s: Initialize stk8312\n", __func__);
+#elif defined CONFIG_SENSORS_STK8313
+ printk(KERN_INFO "%s: Initialize stk8313\n", __func__);
+#endif
+
+ buffer[0] = STK831X_RESET;
+ buffer[1] = 0x00;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+
+ /* int pin is active high, psuh-pull */
+ buffer[0] = STK831X_MODE;
+ buffer[1] = 0xC0;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+
+ /* 50 Hz ODR */
+ stk->delay = STK831X_INIT_ODR;
+ buffer[0] = STK831X_SR;
+ buffer[1] = stk->delay /*+ STK831X_SAMPLE_TIME_BASE*//*2*/; //debug for rotate slowly 2013-8-15
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return result;
+ }
+
+#if (!STK_ACC_POLLING_MODE)
+ /* enable GINT, int after every measurement */
+ buffer[0] = STK831X_INTSU;
+ buffer[1] = 0x10;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:interrupt init failed\n", __func__);
+ return result;
+ }
+#endif
+ /* +- 6g mode */
+ buffer[0] = STK831X_STH;
+#ifdef CONFIG_SENSORS_STK8312
+ buffer[1] = 0x42;
+#elif defined CONFIG_SENSORS_STK8313
+ buffer[1] = 0x82;
+#endif
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ printk(KERN_ERR "%s:set range failed\n", __func__);
+ return result;
+ }
+
+ atomic_set(&stk->enabled, 0);
+ event_since_en = 0;
+
+#ifdef STK_LOWPASS
+ memset(&stk->fir, 0x00, sizeof(stk->fir));
+ atomic_set(&stk->firlength, STK_FIR_LEN);
+ atomic_set(&stk->fir_en, 1);
+#endif
+
+#ifdef STK_TUNE
+ stk_tune_offset[0] = 0;
+ stk_tune_offset[1] = 0;
+ stk_tune_offset[2] = 0;
+ stk_tune_done = 0;
+#endif
+ return 0;
+}
+
+static void stk_handle_first_en(struct stk831x_data *stk)
+{
+ char r_buf[STK_ACC_CALI_FILE_SIZE] = {0};
+ char offset[3];
+ char mode;
+
+ if ((stk_get_file_content(r_buf, STK_ACC_CALI_FILE_SIZE)) == 0)
+ {
+ if(r_buf[0] == STK_ACC_CALI_VER0 && r_buf[1] == STK_ACC_CALI_VER1)
+ {
+ offset[0] = r_buf[2];
+ offset[1] = r_buf[3];
+ offset[2] = r_buf[4];
+ mode = r_buf[5];
+ STK831x_SetOffset(offset);
+#ifdef STK_TUNE
+ stk_tune_offset_record[0] = offset[0];
+ stk_tune_offset_record[1] = offset[1];
+ stk_tune_offset_record[2] = offset[2];
+#endif
+ printk(KERN_INFO "%s: set offset:%d,%d,%d, mode=%d\n", __func__, offset[0], offset[1], offset[2], mode);
+ atomic_set(&stk->cali_status, mode);
+ }
+ else
+ {
+ printk(KERN_ERR "%s: cali version number error! r_buf=0x%x,0x%x,0x%x,0x%x,0x%x\n",
+ __func__, r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4]);
+ //return -EINVAL;
+ }
+ }
+#ifdef STK_TUNE
+ else if(stk_tune_offset_record[0]!=0 || stk_tune_offset_record[1]!=0 || stk_tune_offset_record[2]!=0)
+ {
+ STK831x_SetOffset(stk_tune_offset_record);
+ stk_tune_done = 1;
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_TUNE);
+ printk(KERN_INFO "%s: set offset:%d,%d,%d\n", __func__, stk_tune_offset_record[0],
+ stk_tune_offset_record[1],stk_tune_offset_record[2]);
+ }
+#endif
+ else
+ {
+ offset[0] = offset[1] = offset[2] = 0;
+ stk_store_in_file(offset, STK_K_NO_CALI);
+ atomic_set(&stk->cali_status, STK_K_NO_CALI);
+ }
+ printk(KERN_INFO "%s: finish, cali_status = 0x%x\n", __func__, atomic_read(&stk->cali_status));
+ return;
+}
+
+static int32_t stk_get_ic_content(struct stk831x_data *stk)
+{
+ int result;
+ char regR;
+
+ result = STK831x_ReadByteOTP(0x7F, ®R);
+ if(result < 0)
+ {
+ printk(KERN_ERR "%s: read/write eng i2c error, result=0x%x\n", __func__, result);
+ return result;
+ }
+
+ if(regR&0x20)
+ {
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_FT2);
+ printk(KERN_INFO "%s: OTP 2 used\n", __func__);
+ return 2;
+ }
+ if(regR&0x10)
+ {
+ atomic_set(&stk->cali_status, STK_K_SUCCESS_FT1);
+ printk(KERN_INFO "%s: OTP 1 used\n", __func__);
+ return 1;
+ }
+ return 0;
+}
+
+static int stk_store_in_ic( struct stk831x_data *stk, char otp_offset[], char FT_index, uint32_t delay_ms)
+{
+ int result;
+ char buffer[2] = "";
+
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+ buffer[1] = (buffer[0] & 0xF8) | 0x01;
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+ STK831X_SetVD(stk);
+
+ buffer[0] = 0x2B;
+ buffer[1] = otp_offset[0];
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+ buffer[0] = 0x2F;
+ buffer[1] = otp_offset[2];
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+ buffer[0] = 0x33;
+ buffer[1] = otp_offset[1];
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+
+
+#ifdef STK_DEBUG_CALI
+ //printk(KERN_INFO "%s:Check All OTP Data after write 0x2B 0x2F 0x33\n", __func__);
+ //STK831x_ReadAllOTP();
+#endif
+
+ msleep(delay_ms*15);
+ result = STK831X_VerifyCali(stk, 0, 0);
+ if(result)
+ {
+ printk(KERN_ERR "%s: calibration check1 fail, FT_index=%d\n", __func__, FT_index);
+ goto ic_err_misc;
+ }
+#ifdef STK_DEBUG_CALI
+ //printk(KERN_INFO "\n%s:Check All OTP Data before write OTP\n", __func__);
+
+#endif
+ //Write OTP
+ printk(KERN_INFO "\n%s:Write offset data to FT%d OTP\n", __func__, FT_index);
+ result = STK831x_WriteOffsetOTP(stk, FT_index, otp_offset);
+ if(result < 0)
+ {
+ printk(KERN_INFO "%s: write OTP%d fail\n", __func__, FT_index);
+ goto ic_err_misc;
+ }
+
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Rx(buffer, 1);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+ buffer[1] = (buffer[0] & 0xF8);
+ buffer[0] = STK831X_MODE;
+ result = STK_i2c_Tx(buffer, 2);
+ if (result < 0)
+ {
+ goto ic_err_i2c_rw;
+ }
+
+ msleep(1);
+ STK831x_Init(stk, this_client);
+#ifdef STK_DEBUG_CALI
+ //printk(KERN_INFO "\n%s:Check All OTP Data after write OTP and reset\n", __func__);
+#endif
+
+ result = STK831X_VerifyCali(stk, 1, delay_ms);
+ if(result)
+ {
+ printk(KERN_ERR "%s: calibration check2 fail\n", __func__);
+ goto ic_err_misc;
+ }
+ return 0;
+
+ic_err_misc:
+ STK831x_Init(stk, this_client);
+ msleep(1);
+ atomic_set(&stk->cali_status, -result);
+ return result;
+
+ic_err_i2c_rw:
+ printk(KERN_ERR "%s: i2c read/write error, err=0x%x\n", __func__, result);
+ msleep(1);
+ STK831x_Init(stk, this_client);
+ atomic_set(&stk->cali_status, STK_K_FAIL_I2C);
+ return result;
+}
+
+static int32_t stk_get_file_content(char * r_buf, int8_t buf_size)
+{
+ struct file *cali_file;
+ mm_segment_t fs;
+ ssize_t ret;
+
+ cali_file = filp_open(STK_ACC_CALI_FILE, O_RDONLY,0);
+ if(IS_ERR(cali_file))
+ {
+ printk(KERN_ERR "%s: filp_open error, no offset file!\n", __func__);
+ return -ENOENT;
+ }
+ else
+ {
+ fs = get_fs();
+ set_fs(get_ds());
+ ret = cali_file->f_op->read(cali_file,r_buf, STK_ACC_CALI_FILE_SIZE,&cali_file->f_pos);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s: read error, ret=%d\n", __func__, ret);
+ filp_close(cali_file,NULL);
+ return -EIO;
+ }
+ set_fs(fs);
+ }
+
+ filp_close(cali_file,NULL);
+ return 0;
+}
+
+#ifdef STK_PERMISSION_THREAD
+static struct task_struct *STKPermissionThread = NULL;
+
+static int stk_permission_thread(void *data)
+{
+ int ret = 0;
+ int retry = 0;
+ mm_segment_t fs = get_fs();
+ set_fs(KERNEL_DS);
+ msleep(20000);
+ do{
+ msleep(5000);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input0/driver/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input1/driver/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input2/driver/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input3/driver/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input4/driver/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input0/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input1/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input2/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input3/cali" , 0666);
+ ret = sys_fchmodat(AT_FDCWD, "/sys/class/input/input4/cali" , 0666);
+ ret = sys_chmod(STK_ACC_CALI_FILE , 0666);
+ ret = sys_fchmodat(AT_FDCWD, STK_ACC_CALI_FILE , 0666);
+ //if(ret < 0)
+ // printk("fail to execute sys_fchmodat, ret = %d\n", ret);
+ if(retry++ > 10)
+ break;
+ }while(ret == -ENOENT);
+ set_fs(fs);
+ printk(KERN_INFO "%s exit, retry=%d\n", __func__, retry);
+ return 0;
+}
+#endif /* #ifdef STK_PERMISSION_THREAD */
+
+static int stk_store_in_file(char offset[], char mode)
+{
+ struct file *cali_file;
+ char r_buf[STK_ACC_CALI_FILE_SIZE] = {0};
+ char w_buf[STK_ACC_CALI_FILE_SIZE] = {0};
+ mm_segment_t fs;
+ ssize_t ret;
+ int8_t i;
+
+ w_buf[0] = STK_ACC_CALI_VER0;
+ w_buf[1] = STK_ACC_CALI_VER1;
+ w_buf[2] = offset[0];
+ w_buf[3] = offset[1];
+ w_buf[4] = offset[2];
+ w_buf[5] = mode;
+
+ cali_file = filp_open(STK_ACC_CALI_FILE, O_CREAT | O_RDWR,0666);
+
+ if(IS_ERR(cali_file))
+ {
+ printk(KERN_ERR "%s: filp_open error!\n", __func__);
+ return -STK_K_FAIL_OPEN_FILE;
+ }
+ else
+ {
+ fs = get_fs();
+ set_fs(get_ds());
+
+ ret = cali_file->f_op->write(cali_file,w_buf,STK_ACC_CALI_FILE_SIZE,&cali_file->f_pos);
+ if(ret != STK_ACC_CALI_FILE_SIZE)
+ {
+ printk(KERN_ERR "%s: write error!\n", __func__);
+ filp_close(cali_file,NULL);
+ return -STK_K_FAIL_W_FILE;
+ }
+ cali_file->f_pos=0x00;
+ ret = cali_file->f_op->read(cali_file,r_buf, STK_ACC_CALI_FILE_SIZE,&cali_file->f_pos);
+ if(ret < 0)
+ {
+ printk(KERN_ERR "%s: read error!\n", __func__);
+ filp_close(cali_file,NULL);
+ return -STK_K_FAIL_R_BACK;
+ }
+ set_fs(fs);
+
+ //printk(KERN_INFO "%s: read ret=%d!\n", __func__, ret);
+ for(i=0;i<STK_ACC_CALI_FILE_SIZE;i++)
+ {
+ if(r_buf[i] != w_buf[i])
+ {
+ printk(KERN_ERR "%s: read back error, r_buf[%x](0x%x) != w_buf[%x](0x%x)\n",
+ __func__, i, r_buf[i], i, w_buf[i]);
+ filp_close(cali_file,NULL);
+ return -STK_K_FAIL_R_BACK_COMP;
+ }
+ }
+ }
+ filp_close(cali_file,NULL);
+
+#ifdef STK_PERMISSION_THREAD
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_chmod(STK_ACC_CALI_FILE , 0666);
+ ret = sys_fchmodat(AT_FDCWD, STK_ACC_CALI_FILE , 0666);
+ set_fs(fs);
+#endif
+ //printk(KERN_INFO "%s successfully\n", __func__);
+ return 0;
+}
+
+static int stk_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ ret = nonseekable_open(inode, file);
+ if(ret < 0)
+ return ret;
+ file->private_data = stk831x_data_ptr;
+ return 0;
+}
+
+static int stk_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,36))
+static long stk_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#else
+static int stk_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+#endif
+{
+ void __user *argp = (void __user *)arg;
+ int retval = 0;
+ char state = 0, restore_state = 0;
+ char rwbuf[8] = "";
+ uint32_t delay_ns;
+ char char3_buffer[3];
+ int result;
+ int int3_buffer[3];
+ struct stk831x_data *stk = file->private_data;
+ unsigned int uval = -1;
+/* printk(KERN_INFO "%s: cmd = 0x%x\n", __func__, cmd); */
+
+ if(cmd == ECS_IOCTL_APP_SET_DELAY || cmd == STK_IOCTL_SET_DELAY || cmd == STK_IOCTL_SET_OFFSET || cmd == STK_IOCTL_SET_RANGE || cmd == STK_IOCTL_WRITE || cmd == STK_IOCTL_SET_CALI)
+ {
+ STK831x_GetEnable(stk, &restore_state);
+ if(restore_state)
+ STK831x_SetEnable(stk, 0);
+ }
+
+ switch (cmd)
+ {
+ case STK_IOCTL_SET_OFFSET:
+ if(copy_from_user(&char3_buffer, argp, sizeof(char3_buffer)))
+ return -EFAULT;
+ break;
+ case ECS_IOCTL_APP_SET_DELAY:
+ case STK_IOCTL_SET_DELAY:
+ if(copy_from_user(&delay_ns, argp, sizeof(uint32_t)))
+ return -EFAULT;
+ break;
+ case STK_IOCTL_WRITE:
+ case STK_IOCTL_READ:
+ if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
+ return -EFAULT;
+ break;
+ case ECS_IOCTL_APP_SET_AFLAG:
+ case STK_IOCTL_SET_ENABLE:
+ case STK_IOCTL_SET_RANGE:
+ case STK_IOCTL_SET_CALI:
+ if(copy_from_user(&state, argp, sizeof(char)))
+ return -EFAULT;
+ break;
+ case WMT_IOCTL_SENSOR_GET_DRVID:
+
+ uval = STK8312_DRVID;
+ if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ printk("<<<<<<<driver_id:%d\n",uval);
+ break;
+ case WMT_IOCTL_SENOR_GET_RESOLUTION:
+ uval = (8<<8) | 12; // 8bit:12g 0xxx xx
+
+ if (copy_to_user((unsigned int *)arg, &uval, sizeof(unsigned int)))
+ {
+ return -EFAULT;
+ }
+ printk("<<<<<<<resolution:0x%x\n",uval);
+ default:
+ break;
+ }
+
+ switch (cmd)
+ {
+ case STK_IOCTL_WRITE:
+ if (rwbuf[0] < 2)
+ return -EINVAL;
+ result = STK_i2c_Tx(&rwbuf[1], rwbuf[0]);
+ if (result < 0)
+ return result;
+ break;
+ case STK_IOCTL_SET_OFFSET:
+ STK831x_SetOffset(char3_buffer);
+ break;
+ case ECS_IOCTL_APP_SET_DELAY:
+ case STK_IOCTL_SET_DELAY:
+ STK831x_SetDelay(stk, delay_ns);
+ break;
+ case STK_IOCTL_READ:
+ if (rwbuf[0] < 1)
+ return -EINVAL;
+ result = STK_i2c_Rx(&rwbuf[1], rwbuf[0]);
+ if (result < 0)
+ return result;
+ break;
+ case STK_IOCTL_GET_DELAY:
+ STK831x_GetDelay(stk, &delay_ns);
+ break;
+ case STK_IOCTL_GET_OFFSET:
+ STK831x_GetOffset(char3_buffer);
+ break;
+ case STK_IOCTL_GET_ACCELERATION:
+ STK831x_ReadSensorData(stk);
+ int3_buffer[0] = stk->raw_data[0];
+ int3_buffer[1] = stk->raw_data[1];
+ int3_buffer[2] = stk->raw_data[2];
+ break;
+ case ECS_IOCTL_APP_SET_AFLAG:
+ case STK_IOCTL_SET_ENABLE:
+ STK831x_SetEnable(stk, state);
+ break;
+ case STK_IOCTL_GET_ENABLE:
+ STK831x_GetEnable(stk, &state);
+ break;
+ case STK_IOCTL_SET_RANGE:
+ STK831x_SetRange(state);
+ break;
+ case STK_IOCTL_GET_RANGE:
+ STK831x_GetRange(&state);
+ break;
+ case STK_IOCTL_SET_CALI:
+ STK831x_SetCali(stk, state);
+ break;
+ default:
+ //retval = -ENOTTY;
+ break;
+ }
+
+ if(cmd == ECS_IOCTL_APP_SET_DELAY || cmd == STK_IOCTL_SET_DELAY || cmd == STK_IOCTL_SET_OFFSET || cmd == STK_IOCTL_SET_RANGE || cmd == STK_IOCTL_WRITE || cmd == STK_IOCTL_SET_CALI)
+ {
+ if(restore_state)
+ STK831x_SetEnable(stk, restore_state);
+ }
+ switch (cmd)
+ {
+ case STK_IOCTL_GET_ACCELERATION:
+ if(copy_to_user(argp, &int3_buffer, sizeof(int3_buffer)))
+ return -EFAULT;
+ break;
+ case STK_IOCTL_READ:
+ if(copy_to_user(argp, &rwbuf, sizeof(rwbuf)))
+ return -EFAULT;
+ break;
+ case STK_IOCTL_GET_DELAY:
+ if(copy_to_user(argp, &delay_ns, sizeof(delay_ns)))
+ return -EFAULT;
+ break;
+ case STK_IOCTL_GET_OFFSET:
+ if(copy_to_user(argp, &char3_buffer, sizeof(char3_buffer)))
+ return -EFAULT;
+ break;
+ case STK_IOCTL_GET_RANGE:
+ case STK_IOCTL_GET_ENABLE:
+ if(copy_to_user(argp, &state, sizeof(char)))
+ return -EFAULT;
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+
+static struct file_operations stk_fops = {
+ .owner = THIS_MODULE,
+ .open = stk_open,
+ .release = stk_release,
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,6,36))
+ .unlocked_ioctl = stk_ioctl,
+#else
+ .ioctl = stk_ioctl,
+#endif
+};
+
+static struct miscdevice stk_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+#ifndef STK_WMT_PLATFORM
+ .name = "stk831x",
+#else
+ .name = "sensor_ctrl",
+#endif
+ .fops = &stk_fops,
+};
+
+
+#if STK_ACC_POLLING_MODE
+static enum hrtimer_restart stk_acc_timer_func(struct hrtimer *timer)
+{
+ struct stk831x_data *stk = container_of(timer, struct stk831x_data, acc_timer);
+ queue_work(stk->stk_acc_wq, &stk->stk_acc_work);
+ hrtimer_forward_now(&stk->acc_timer, stk->acc_poll_delay);
+ return HRTIMER_RESTART;
+}
+
+static void stk_acc_poll_work_func(struct work_struct *work)
+{
+ struct stk831x_data *stk = container_of(work, struct stk831x_data, stk_acc_work);
+ STK831x_ReadSensorData(stk);
+ STK831x_ReportValue(stk);
+ return;
+}
+
+#else
+
+static irqreturn_t stk_mems_irq_handler(int irq, void *data)
+{
+ struct stk831x_data *pData = data;
+ disable_irq_nosync(pData->irq);
+ queue_work(stk_mems_work_queue,&pData->stk_work);
+ return IRQ_HANDLED;
+}
+
+
+static void stk_mems_wq_function(struct work_struct *work)
+{
+ struct stk831x_data *stk = container_of(work, struct stk831x_data, stk_work);
+ STK831x_ReadSensorData(stk);
+ STK831x_ReportValue(stk);
+ enable_irq(stk->irq);
+}
+
+static int stk831x_irq_setup(struct i2c_client *client, struct stk831x_data *stk_int)
+{
+ int error;
+ int irq= -1;
+#if ADDITIONAL_GPIO_CFG
+ if (gpio_request(STK_INT_PIN, "EINT"))
+ {
+ printk(KERN_ERR "%s:gpio_request() failed\n",__func__);
+ return -1;
+ }
+ gpio_direction_input(STK_INT_PIN);
+
+ irq = gpio_to_irq(STK_INT_PIN);
+ if ( irq < 0 )
+ {
+ printk(KERN_ERR "%s:gpio_to_irq() failed\n",__func__);
+ return -1;
+ }
+ client->irq = irq;
+ stk_int->irq = irq;
+#endif //#if ADDITIONAL_GPIO_CFG
+ printk(KERN_INFO "%s: irq # = %d\n", __func__, irq);
+ if(irq < 0)
+ printk(KERN_ERR "%s: irq number was not specified!\n", __func__);
+ error = request_irq(client->irq, stk_mems_irq_handler, IRQF_TRIGGER_RISING , "stk-mems", stk_int);
+ if (error < 0)
+ {
+ printk(KERN_ERR "%s: request_irq(%d) failed for (%d)\n", __func__, client->irq, error);
+ return -1;
+ }
+ disable_irq(irq);
+ return irq;
+}
+
+#endif //#if STK_ACC_POLLING_MODE
+
+static ssize_t stk831x_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&stk->enabled));
+}
+
+static ssize_t stk831x_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+
+ error = strict_strtoul(buf, 10, &data);
+ if (error)
+ {
+ printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+ if ((data == 0)||(data==1))
+ STK831x_SetEnable(stk,data);
+ else
+ printk(KERN_ERR "%s: invalud argument, data=%ld\n", __func__, data);
+ return count;
+}
+
+static ssize_t stk831x_value_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ int ddata[3];
+
+ printk(KERN_INFO "driver version:%s\n",STK_ACC_DRIVER_VERSION);
+ STK831x_ReadSensorData(stk);
+ ddata[0]= stk->raw_data[0];
+ ddata[1]= stk->raw_data[1];
+ ddata[2]= stk->raw_data[2];
+ return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", ddata[0], ddata[1], ddata[2]);
+}
+
+static ssize_t stk831x_delay_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ uint32_t gdelay_ns;
+
+ STK831x_GetDelay(stk, &gdelay_ns);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", gdelay_ns/1000000);
+}
+
+static ssize_t stk831x_delay_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ char restore_state = 0;
+
+ error = strict_strtoul(buf, 10, &data);
+ if (error)
+ {
+ printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+
+ STK831x_GetEnable(stk, &restore_state);
+ if(restore_state)
+ STK831x_SetEnable(stk, 0);
+
+ STK831x_SetDelay(stk, data*1000000); // ms to ns
+
+ if(restore_state)
+ STK831x_SetEnable(stk, restore_state);
+ return count;
+}
+
+static ssize_t stk831x_cali_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ int status = atomic_read(&stk->cali_status);
+
+ if(status != STK_K_RUNNING)
+ STK831x_GetCali(stk);
+ return scnprintf(buf, PAGE_SIZE, "%02x\n", status);
+}
+
+static ssize_t stk831x_cali_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long data;
+ int error;
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ error = strict_strtoul(buf, 10, &data);
+ if (error)
+ {
+ printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+ STK831x_SetCali(stk, data);
+ return count;
+}
+
+static ssize_t stk831x_send_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int error, i;
+ char *token[2];
+ int w_reg[2];
+ char buffer[2] = "";
+
+ for (i = 0; i < 2; i++)
+ token[i] = strsep((char **)&buf, " ");
+ if((error = strict_strtoul(token[0], 16, (unsigned long *)&(w_reg[0]))) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+ if((error = strict_strtoul(token[1], 16, (unsigned long *)&(w_reg[1]))) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+ printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, w_reg[0], w_reg[1]);
+ buffer[0] = w_reg[0];
+ buffer[1] = w_reg[1];
+ error = STK_i2c_Tx(buffer, 2);
+ if (error < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return error;
+ }
+ return count;
+}
+
+static ssize_t stk831x_recv_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ return scnprintf(buf, PAGE_SIZE, "%02x\n", stk->recv_reg);
+}
+
+static ssize_t stk831x_recv_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char buffer[2] = "";
+ unsigned long data;
+ int error;
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+
+ error = strict_strtoul(buf, 16, &data);
+ if (error)
+ {
+ printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+
+ buffer[0] = data;
+ error = STK_i2c_Rx(buffer, 2);
+ if (error < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return error;
+ }
+ stk->recv_reg = buffer[0];
+ printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, (int)data , (int)buffer[0]);
+ return count;
+}
+
+static ssize_t stk831x_allreg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int error;
+ char buffer[16] = "";
+ char show_buffer[14] = "";
+ int aa,bb, no, show_no = 0;
+
+ for(bb=0;bb<4;bb++)
+ {
+ buffer[0] = bb * 0x10;
+ error = STK_i2c_Rx(buffer, 16);
+ if (error < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return error;
+ }
+ for(aa=0;aa<16;aa++)
+ {
+ no = bb*0x10+aa;
+ printk(KERN_INFO "stk reg[0x%x]=0x%x\n", no, buffer[aa]);
+ switch(no)
+ {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ case 0x4:
+ case 0x5:
+ case STK831X_INTSU:
+ case STK831X_MODE:
+ case STK831X_SR:
+ case STK831X_OFSX:
+ case STK831X_OFSY:
+ case STK831X_OFSZ:
+ case STK831X_STH:
+ case 0x24:
+ show_buffer[show_no] = buffer[aa];
+ show_no++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return scnprintf(buf, PAGE_SIZE, "0x0=%02x,0x1=%02x,0x2=%02x,0x3=%02x,0x4=%02x,0x5=%02x,INTSU=%02x,MODE=%02x,SR=%02x,OFSX=%02x,OFSY=%02x,OFSZ=%02x,STH=%02x,0x24=%02x\n",
+ show_buffer[0], show_buffer[1], show_buffer[2], show_buffer[3], show_buffer[4],
+ show_buffer[5], show_buffer[6], show_buffer[7], show_buffer[8], show_buffer[9],
+ show_buffer[10], show_buffer[11], show_buffer[12], show_buffer[13]);
+}
+
+static ssize_t stk831x_sendo_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int error, i;
+ char *token[2];
+ int w_reg[2];
+ char buffer[2] = "";
+
+ for (i = 0; i < 2; i++)
+ token[i] = strsep((char **)&buf, " ");
+ if((error = strict_strtoul(token[0], 16, (unsigned long *)&(w_reg[0]))) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+ if((error = strict_strtoul(token[1], 16, (unsigned long *)&(w_reg[1]))) < 0)
+ {
+ printk(KERN_ERR "%s:strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+ printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, w_reg[0], w_reg[1]);
+
+ buffer[0] = w_reg[0];
+ buffer[1] = w_reg[1];
+ error = STK831x_WriteByteOTP(buffer[0], buffer[1]);
+ if (error < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return error;
+ }
+ return count;
+}
+
+
+static ssize_t stk831x_recvo_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ char buffer[2] = "";
+ unsigned long data;
+ int error;
+
+ error = strict_strtoul(buf, 16, &data);
+ if (error)
+ {
+ printk(KERN_ERR "%s: strict_strtoul failed, error=0x%x\n", __func__, error);
+ return error;
+ }
+
+ buffer[0] = data;
+ error = STK831x_ReadByteOTP(buffer[0], &buffer[1]);
+ if (error < 0)
+ {
+ printk(KERN_ERR "%s:failed\n", __func__);
+ return error;
+ }
+ printk(KERN_INFO "%s: reg[0x%x]=0x%x\n", __func__, buffer[0] , buffer[1]);
+ return count;
+}
+
+static ssize_t stk831x_firlen_show(struct device *dev,
+struct device_attribute *attr, char *buf)
+{
+#ifdef STK_LOWPASS
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ int len = atomic_read(&stk->firlength);
+
+ if(atomic_read(&stk->firlength))
+ {
+ printk(KERN_INFO "len = %2d, idx = %2d\n", stk->fir.num, stk->fir.idx);
+ printk(KERN_INFO "sum = [%5d %5d %5d]\n", stk->fir.sum[0], stk->fir.sum[1], stk->fir.sum[2]);
+ printk(KERN_INFO "avg = [%5d %5d %5d]\n", stk->fir.sum[0]/len, stk->fir.sum[1]/len, stk->fir.sum[2]/len);
+ }
+ return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&stk->firlength));
+#else
+ return snprintf(buf, PAGE_SIZE, "not support\n");
+#endif
+}
+
+static ssize_t stk831x_firlen_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+#ifdef STK_LOWPASS
+ struct stk831x_data *stk = i2c_get_clientdata(this_client);
+ int error;
+ unsigned long data;
+
+ error = strict_strtoul(buf, 10, &data);
+ if (error)
+ {
+ printk(KERN_ERR "%s: strict_strtoul failed, error=%d\n", __func__, error);
+ return error;
+ }
+
+ if(data > MAX_FIR_LEN)
+ {
+ printk(KERN_ERR "%s: firlen exceed maximum filter length\n", __func__);
+ }
+ else if (data < 1)
+ {
+ atomic_set(&stk->firlength, 1);
+ atomic_set(&stk->fir_en, 0);
+ memset(&stk->fir, 0x00, sizeof(stk->fir));
+ }
+ else
+ {
+ atomic_set(&stk->firlength, data);
+ memset(&stk->fir, 0x00, sizeof(stk->fir));
+ atomic_set(&stk->fir_en, 1);
+ }
+#else
+ printk(KERN_ERR "%s: firlen is not supported\n", __func__);
+#endif
+ return count;
+}
+
+
+static DEVICE_ATTR(enable, 0644, stk831x_enable_show, stk831x_enable_store);
+static DEVICE_ATTR(value, 0444, stk831x_value_show, NULL);
+static DEVICE_ATTR(delay, 0644, stk831x_delay_show, stk831x_delay_store);
+static DEVICE_ATTR(cali, 0644, stk831x_cali_show, stk831x_cali_store);
+static DEVICE_ATTR(send, 0200, NULL, stk831x_send_store);
+static DEVICE_ATTR(recv, 0644, stk831x_recv_show, stk831x_recv_store);
+static DEVICE_ATTR(allreg, 0444, stk831x_allreg_show, NULL);
+static DEVICE_ATTR(sendo, 0200, NULL, stk831x_sendo_store);
+static DEVICE_ATTR(recvo, 0200, NULL, stk831x_recvo_store);
+static DEVICE_ATTR(firlen, 0644, stk831x_firlen_show, stk831x_firlen_store);
+
+static struct attribute *stk831x_attributes[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_value.attr,
+ &dev_attr_delay.attr,
+ &dev_attr_cali.attr,
+ &dev_attr_send.attr,
+ &dev_attr_recv.attr,
+ &dev_attr_allreg.attr,
+ &dev_attr_sendo.attr,
+ &dev_attr_recvo.attr,
+ &dev_attr_firlen.attr,
+ NULL
+};
+
+static struct attribute_group stk831x_attribute_group = {
+#ifndef STK_ALLWINNER_PLATFORM
+ .name = "driver",
+#endif
+ .attrs = stk831x_attributes,
+};
+static int stk831x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int error;
+ struct stk831x_data *stk;
+
+ printk(KERN_INFO "stk831x_probe: driver version:%s\n",STK_ACC_DRIVER_VERSION);
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ {
+ printk(KERN_ERR "%s:i2c_check_functionality error\n", __func__);
+ error = -ENODEV;
+ goto exit_i2c_check_functionality_error;
+ }
+
+ stk = kzalloc(sizeof(struct stk831x_data),GFP_KERNEL);
+ if (!stk)
+ {
+ printk(KERN_ERR "%s:memory allocation error\n", __func__);
+ error = -ENOMEM;
+ goto exit_kzalloc_error;
+ }
+ stk831x_data_ptr = stk;
+ mutex_init(&stk->write_lock);
+
+#if (STK_ACC_POLLING_MODE)
+ stk->stk_acc_wq = create_singlethread_workqueue("stk_acc_wq");
+ INIT_WORK(&stk->stk_acc_work, stk_acc_poll_work_func);
+ hrtimer_init(&stk->acc_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+// stk->acc_poll_delay = ns_to_ktime(40 * NSEC_PER_MSEC);
+ stk->acc_poll_delay = ns_to_ktime(STK831X_SAMPLE_TIME[STK831X_INIT_ODR]*USEC_PER_MSEC);
+ stk->acc_timer.function = stk_acc_timer_func;
+#else
+ stk_mems_work_queue = create_workqueue("stk_mems_wq");
+ if(stk_mems_work_queue)
+ INIT_WORK(&stk->stk_work, stk_mems_wq_function);
+ else
+ {
+ printk(KERN_ERR "%s:create_workqueue error\n", __func__);
+ error = -EPERM;
+ goto exit_create_workqueue_error;
+ }
+
+ error = stk831x_irq_setup(client, stk);
+ if(!error)
+ {
+ goto exit_irq_setup_error;
+ }
+#endif //#if STK_ACC_POLLING_MODE
+
+ i2c_set_clientdata(client, stk);
+ this_client = client;
+
+ error = STK831x_Init(stk, client);
+ if (error)
+ {
+ printk(KERN_ERR "%s:stk831x initialization failed\n", __func__);
+ goto exit_stk_init_error;
+ }
+ atomic_set(&stk->cali_status, STK_K_NO_CALI);
+ stk->first_enable = true;
+ stk->re_enable = false;
+ event_since_en_limit = 20;
+
+ stk->input_dev = input_allocate_device();
+ if (!stk->input_dev)
+ {
+ error = -ENOMEM;
+ printk(KERN_ERR "%s:input_allocate_device failed\n", __func__);
+ goto exit_input_dev_alloc_error;
+ }
+#ifndef STK_WMT_PLATFORM
+ stk->input_dev->name = ACC_IDEVICE_NAME;
+#else
+ stk->input_dev->name = "g-sensor";
+#endif
+ set_bit(EV_ABS, stk->input_dev->evbit);
+
+ input_set_abs_params(stk->input_dev, ABS_X, -65532, 65532, 0, 0);
+ input_set_abs_params(stk->input_dev, ABS_Y, -65532, 65532, 0, 0);
+ input_set_abs_params(stk->input_dev, ABS_Z, -65532, 65532, 0, 0);
+
+
+ error = input_register_device(stk->input_dev);
+ if (error)
+ {
+ printk(KERN_ERR "%s:Unable to register input device: %s\n", __func__, stk->input_dev->name);
+ goto exit_input_register_device_error;
+ }
+
+ error = misc_register(&stk_device);
+ if (error)
+ {
+ printk(KERN_ERR "%s: misc_register failed\n", __func__);
+ goto exit_misc_device_register_error;
+ }
+ error = sysfs_create_group(&stk_device.this_device->kobj, &stk831x_attribute_group);
+ if (error)
+ {
+ printk(KERN_ERR "%s: sysfs_create_group failed\n", __func__);
+ goto exit_sysfs_create_group_error;
+ }
+
+ printk(KERN_INFO "%s successfully\n", __func__);
+ return 0;
+exit_sysfs_create_group_error:
+ //sysfs_remove_group(&stk->input_dev->dev.kobj, &stk831x_attribute_group);
+ sysfs_remove_group(&stk_device.this_device->kobj, &stk831x_attribute_group);
+exit_misc_device_register_error:
+ misc_deregister(&stk_device);
+exit_input_register_device_error:
+ input_unregister_device(stk->input_dev);
+exit_input_dev_alloc_error:
+exit_stk_init_error:
+#if (STK_ACC_POLLING_MODE)
+ hrtimer_try_to_cancel(&stk->acc_timer);
+ destroy_workqueue(stk->stk_acc_wq);
+#else
+ free_irq(client->irq, stk);
+#if ADDITIONAL_GPIO_CFG
+exit_irq_setup_error:
+ gpio_free( STK_INT_PIN );
+#endif //#if ADDITIONAL_GPIO_CFG
+ destroy_workqueue(stk_mems_work_queue);
+exit_create_workqueue_error:
+#endif //#if (!STK_ACC_POLLING_MODE)
+ mutex_destroy(&stk->write_lock);
+ kfree(stk);
+ stk = NULL;
+exit_kzalloc_error:
+exit_i2c_check_functionality_error:
+ return error;
+}
+
+static int stk831x_remove(struct i2c_client *client)
+{
+ struct stk831x_data *stk = i2c_get_clientdata(client);
+
+ //sysfs_remove_group(&stk->input_dev->dev.kobj, &stk831x_attribute_group);
+ sysfs_remove_group(&stk_device.this_device->kobj, &stk831x_attribute_group);
+ misc_deregister(&stk_device);
+ input_unregister_device(stk->input_dev);
+ cancel_work_sync(&stk->stk_work);
+#if (STK_ACC_POLLING_MODE)
+ hrtimer_try_to_cancel(&stk->acc_timer);
+ destroy_workqueue(stk->stk_acc_wq);
+#else
+ free_irq(client->irq, stk);
+#if ADDITIONAL_GPIO_CFG
+ gpio_free( STK_INT_PIN );
+#endif //#if ADDITIONAL_GPIO_CFG
+ if (stk_mems_work_queue)
+ destroy_workqueue(stk_mems_work_queue);
+#endif //#if (!STK_ACC_POLLING_MODE)
+ mutex_destroy(&stk->write_lock);
+ kfree(stk);
+ stk = NULL;
+ return 0;
+}
+
+static const struct i2c_device_id stk831x[] = {
+ { STK831X_I2C_NAME, 0 },
+ { }
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int stk831x_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct stk831x_data *stk = i2c_get_clientdata(client);
+ printk(KERN_INFO "%s\n", __func__);
+ if(atomic_read(&stk->enabled))
+ {
+ STK831x_SetEnable(stk, 0);
+ stk->re_enable = true;
+ }
+ return 0;
+}
+
+
+static int stk831x_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct stk831x_data *stk = i2c_get_clientdata(client);
+#ifdef STK_RESUME_RE_INIT
+ int error;
+#endif
+
+ printk(KERN_INFO "%s\n", __func__);
+#ifdef STK_RESUME_RE_INIT
+ error = STK831x_Init(stk, this_client);
+ if (error)
+ {
+ printk(KERN_ERR "%s:stk831x initialization failed\n", __func__);
+ return error;
+ }
+ stk->first_enable = true;
+#endif
+ if(stk->re_enable)
+ {
+ stk->re_enable = false;
+ STK831x_SetEnable(stk, 1);
+ }
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+
+#ifdef CONFIG_PM_RUNTIME
+static int stk831x_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct stk831x_data *stk = i2c_get_clientdata(client);
+ printk(KERN_INFO "%s\n", __func__);
+ if(atomic_read(&stk->enabled))
+ {
+ STK831x_SetEnable(stk, 0);
+ stk->re_enable = true;
+ }
+ return 0;
+}
+
+
+static int stk831x_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct stk831x_data *stk = i2c_get_clientdata(client);
+ printk(KERN_INFO "%s\n", __func__);
+ stk->first_enable = true;
+ if(stk->re_enable)
+ {
+ stk->re_enable = false;
+ STK831x_SetEnable(stk, 1);
+ }
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops stk831x_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(stk831x_suspend, stk831x_resume)
+ SET_RUNTIME_PM_OPS(stk831x_runtime_suspend, stk831x_runtime_resume, NULL)
+};
+
+static void stk831x_shutdown(struct i2c_client *client)
+{
+ struct stk831x_data *stk = NULL;
+
+ stk = i2c_get_clientdata(client);
+ hrtimer_cancel(&stk->acc_timer);
+ cancel_work_sync(&stk->stk_acc_work);
+}
+
+static struct i2c_driver stk831x_driver = {
+ .probe = stk831x_probe,
+ .remove = stk831x_remove,
+ .id_table = stk831x,
+ .shutdown = stk831x_shutdown,
+// .suspend = stk831x_suspend,
+// .resume = stk831x_resume,
+ .driver = {
+ .name = STK831X_I2C_NAME,
+ .pm = &stk831x_pm_ops,
+ },
+};
+
+
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+static int get_axisset(void* param)
+{
+ char varbuf[64];
+ int n;
+ int varlen;
+ //int tmpoff[3] = {0};
+ memset(varbuf, 0, sizeof(varbuf));
+ varlen = sizeof(varbuf);
+ if (wmt_getsyspara("wmt.io.stk8312sensor", varbuf, &varlen)) {
+ errlog("Can't get gsensor config in u-boot!!!!\n");
+ return -1;
+ } else {
+ n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &l_sensorconfig.op,
+ &(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]),
+ &(l_sensorconfig.offset[0]),
+ &(l_sensorconfig.offset[1]),
+ &(l_sensorconfig.offset[2]));
+ if (n != 10) {
+ printk(KERN_ERR "gsensor format is error in u-boot!!!\n");
+ return -1;
+ }
+
+ printk("get the sensor config: %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+ l_sensorconfig.op,
+ 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],
+ l_sensorconfig.offset[0],
+ l_sensorconfig.offset[1],
+ l_sensorconfig.offset[2]
+ );
+ }
+ return 0;
+}
+
+static int is_stk8312(void)
+{
+ struct i2c_client *client = NULL;
+ int ret = 0;
+ char wbuf[1] = {0x0b};
+ char rbuf[1] = {0x0};
+ //int devid = 0;
+ client = this_client;
+ if (!client)
+ {
+ return 0;
+ }
+#if 0
+
+ devid = i2c_smbus_read_byte_data(client, 0x0b); //fail!!!
+#endif
+
+ ret = i2c_master_send(client, wbuf, 1);
+ ret = i2c_master_recv(client, rbuf, 1);
+ printk("<<<%s devid 0x%x\n", __FUNCTION__ ,rbuf[0]);
+#if 0 //also ok!!
+ struct i2c_msg msg[2] = {
+ {.addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = wbuf,
+ },
+ { .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = rbuf,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+
+ printk("ret %d, id 0x%x\n", ret, rbuf[0]);
+#endif
+ if (rbuf[0] == 0x58)
+ return 1;
+ else
+ return 0;
+
+
+}
+
+static int __init stk831x_init(void)
+{
+ int ret = 0;
+ printk(KERN_EMERG"%d:%s",__LINE__,__func__);
+
+ ret = get_axisset(NULL);
+ if (ret < 0)
+ {
+ printk("<<<<<%s user choose to no sensor chip!\n", __func__);
+ return ret;
+ }
+
+ if (!(this_client = sensor_i2c_register_device(0, STKDIR, STK831X_I2C_NAME)))
+ {
+ printk(KERN_EMERG"Can't register gsensor i2c device!\n");
+ return -1;
+ }
+ ret = is_stk8312();
+ if (!ret)
+ {
+ printk("%s not find stk8312\n", __FUNCTION__);
+ sensor_i2c_unregister_device(this_client);
+ return -1;
+
+ }
+
+
+ l_dev_class = class_create(THIS_MODULE, GSENSOR_NAME);
+ //for S40 module to judge whether insmod is ok
+ if (IS_ERR(l_dev_class)){
+ ret = PTR_ERR(l_dev_class);
+ printk(KERN_ERR "Can't class_create gsensor device !!\n");
+ return ret;
+ }
+
+ ret = i2c_add_driver(&stk831x_driver);
+ if (ret!=0)
+ {
+ printk(KERN_EMERG"======stk831x init fail, ret=0x%x======\n", ret);
+ i2c_del_driver(&stk831x_driver);
+ return ret;
+ }
+#ifdef STK_PERMISSION_THREAD
+ STKPermissionThread = kthread_run(
+ ,"stk","Permissionthread");
+ if(IS_ERR(STKPermissionThread))
+ STKPermissionThread = NULL;
+#endif // STK_PERMISSION_THREAD
+ printk(KERN_EMERG"%d:%s",__LINE__,__func__);
+
+ return ret;
+}
+
+static void __exit stk831x_exit(void)
+{
+ //sensor_i2c_unregister_device(this_client);
+ i2c_del_driver(&stk831x_driver);
+ class_destroy(l_dev_class);
+#ifdef STK_PERMISSION_THREAD
+ if(STKPermissionThread)
+ STKPermissionThread = NULL;
+#endif // STK_PERMISSION_THREAD
+ sensor_i2c_unregister_device(this_client);
+}
+
+module_init(stk831x_init);
+module_exit(stk831x_exit);
+
+MODULE_AUTHOR("Lex Hsieh / Sensortek");
+MODULE_DESCRIPTION("stk831x 3-Axis accelerometer driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(STK_ACC_DRIVER_VERSION);
diff --git a/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile new file mode 100755 index 00000000..1f89e698 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/Makefile @@ -0,0 +1,34 @@ +KERNELDIR=../../../../ +#KERNELDIR=/home/hangyan/android8850/kernel/ANDROID_3.0.8 +CROSS = arm_1103_le- +CC= $(CROSS)gcc +LD= $(CROSS)ld +STRIP = $(CROSS)strip + +DEBUG = n + +# Add your debugging flag (or not) to EXTRA_CFLAGS +ifeq ($(DEBUG),y) +# DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines +DEBFLAGS = -O0 -g -DSCULL_DEBUG # "-O" is needed to expand inlines + +else + DEBFLAGS = -O2 -Wall +endif + +EXTRA_CFLAGS += $(DEBFLAGS) + + +MY_MODULE_NAME=s_wmt_lsensor_us5182 + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := us5182.o + +default: + $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules + $(STRIP) --strip-debug $(MY_MODULE_NAME).ko + rm -rf *.o *~ core .depend .*.cmd *.mod.c .tmp_versions + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers + diff --git a/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c new file mode 100755 index 00000000..b251fb83 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.c @@ -0,0 +1,1098 @@ +/* + * us5182.c - us5182 ALS & Proximity Driver + * + * By Intersil Corp + * Michael DiGioia + * + * Based on isl29011.c + * by Mike DiGioia <mdigioia@intersil.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/hwmon.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/pm_runtime.h> +#include <linux/input-polldev.h> +#include <linux/miscdevice.h> +#include <asm/uaccess.h> +//#include <linux/earlysuspend.h> +#include <linux/types.h> +#include "../sensor.h" +#include "us5182.h" +/* Insmod parameters */ +//I2C_CLIENT_INSMOD_1(us5182); + +#define MODULE_NAME "us5182" + +#undef dbg +#define dbg(fmt, args...) + +#undef errlog +#undef klog +#define errlog(fmt, args...) printk(KERN_ERR "[%s]: " fmt, __FUNCTION__, ## args) +#define klog(fmt, args...) printk(KERN_ALERT "[%s]: " fmt, __FUNCTION__, ## args) + +struct us_device { + struct input_polled_dev* input_poll_devl; + struct input_polled_dev* input_poll_devp; + struct i2c_client* client; + struct class* class; + struct device *lsdev; + dev_t devno; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend earlysuspend; +#endif + u8 enable_id; + +}; +static int psh_l8th = 90; +static int psh_h8th = 0; + +static int psl_l8th = 50; +static int psl_h8th = 0; + +static struct i2c_client *this_client = NULL; +/*=====Global variable===============================*/ +static u8 error_flag, debounces; +static int previous_value, this_value; +static struct i2c_client *gclient = NULL; +/*===================================================*/ +static u8 reg_cache[us5182_NUM_CACHABLE_REGS]; + +static struct us_device* l_sensorconfig = NULL; +static int l_enable = 0; // 0:don't report data +static int p_enable = 0; // 0:don't report data + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +static int no_adc_map = 1; + +static DEFINE_MUTEX(mutex); + +static int us5182_i2c_read(struct i2c_client *client,u8 reg) +{ +#if 0 + int val; + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) + printk("%s %d i2c transfer error\n", __func__, __LINE__); + return val; +#endif +//in default our i2c controller, will not send repeatStart signal in read process.(stop-start) +//well this sensor must have the repeatStart signal to work normally +//so we have to pass I2C_M_NOSTART flag to controller 2013-7-5 + char rdData[2] = {0}; + + struct i2c_msg msgs[2] = + { + {.addr = client->addr, .flags = 0|I2C_M_NOSTART, .len = 1, .buf = rdData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = 1, .buf = rdData,}, + }; + rdData[0] = reg; + + if (i2c_transfer(client->adapter, msgs, 2) < 0) { + printk( "%s: transfer failed.", __func__); + return -EIO; + } + + return rdData[0]; +} + +static int get_als_resolution(struct i2c_client *client) +{ + return (us5182_i2c_read(client,REGS_CR01) & 0x18) >> 3; +} + + +static int isl_get_lux_datal(struct i2c_client* client) +{ + + int lsb, msb, bitdepth; + + mutex_lock(&mutex); + lsb = us5182_i2c_read(client, REGS_LSB_SENSOR);// + + if (lsb < 0) { + mutex_unlock(&mutex); + return lsb; + } + + msb = us5182_i2c_read(client, REGS_MSB_SENSOR);// + mutex_unlock(&mutex); + + if (msb < 0) + return msb; + + bitdepth = get_als_resolution(client);//????? + switch(bitdepth){ + case 0: + lsb &= 0xF0; // 12bit?? + lsb >>= 4; //add + return ((msb << 4) | lsb); + break; + case 1: + lsb &= 0xFC; //?? 14bit + lsb >>= 2; + return ((msb << 6) | lsb); + break; + } + + return ((msb << 8) | lsb); +} + + +static int get_ps_resolution(struct i2c_client *client) +{ + u8 data; + + data = (us5182_i2c_read(client,REGS_CR02) & 0x18) >> 3; + + return data; +} + +static int isl_get_lux_datap(struct i2c_client* client) +{ + + int lsb, msb, bitdepth; + + mutex_lock(&mutex); + lsb = us5182_i2c_read(client, REGS_LSB_SENSOR_PS); + + if (lsb < 0) { + mutex_unlock(&mutex); + return lsb; + } + + msb = us5182_i2c_read(client, REGS_MSB_SENSOR_PS); + mutex_unlock(&mutex); + + if (msb < 0) + return msb; + + bitdepth = get_ps_resolution(client); + switch(bitdepth){ + case 0: + lsb &= 0xF0; // 12bit ?? + lsb >>= 4; + return ((msb << 4) | lsb); + break; + case 1: + lsb &= 0xFC; // 14bit ?? + lsb >>= 2; + return ((msb << 6) | lsb); + break; + } + + return ((msb << 8) | lsb); //we use 16bit now +} + + + +/* Return 0 if detection is successful, -ENODEV otherwise */ +static int us5182_detect(struct i2c_client *client/*, int kind, + struct i2c_board_info *info*/) +{ + + char rxData[2] = {0xb2, 0}; + int ret = 0; + +#if 1 + //rxData[0] = 0xb2; + + struct i2c_msg msgs[2] = { + + {.addr = client->addr, .flags = 0|I2C_M_NOSTART, .len = 1, .buf = rxData,}, + {.addr = client->addr, .flags = I2C_M_RD, .len = 1, .buf = rxData,} + }; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0){ + printk(KERN_ERR "%s i2c_transfer error!\n", __FUNCTION__); + return -EIO; + } + +#endif + + if(0x26 == rxData[0]) + { + printk(KERN_ALERT "us5182 detected OK\n"); + return 0; + } + else + return -1; +} + +int isl_input_open(struct input_dev* input) +{ + return 0; +} + +void isl_input_close(struct input_dev* input) +{ +} + +//Fixme plan to transfer the adc value to the config.xml lux 2013-5-10 +static __u16 uadc[8] = {2, 8, 100, 400, 900, 1000, 1500, 1900};//customize +static __u16 ulux[9] = {128, 200, 1300, 2000, 3000, 4000, 5000, 6000, 7000}; +static __u16 adc_to_lux(__u16 adc) +{ + static long long var = 0; + int i = 0; //length of array is 8,9 + for (i=0; i<8; i++) { + if ( adc < uadc[i]){ + break; + } + } + if ( i<9) + { + var++; + if (var%2) + return ulux[i]+0; + else + return ulux[i]-1; + } + return ulux[4]; +} + +static void isl_input_lux_poll_l(struct input_polled_dev *dev) +{ + struct us_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devl->input; + struct i2c_client* client = idev->client; + int ret_val = 0; + + if (client == NULL){ + printk("%s client NULL!\n", __FUNCTION__); + return; + } + + //printk("%s\n", __FUNCTION__); + if (l_enable != 0) + { + //mutex_lock(&mutex); //dead lock!! 2013-7-9!!! + //printk(KERN_ALERT "by flashchen val is %x",val); + ret_val = isl_get_lux_datal(client); //adc + if (ret_val < 0) + return; + if (!no_adc_map) + ret_val = adc_to_lux(ret_val); + + input_report_abs(input, ABS_MISC, ret_val); + //printk("%s %d\n", __FUNCTION__, ret_val); + input_sync(input); + //mutex_unlock(&mutex); + } +} + +static void isl_input_lux_poll_p(struct input_polled_dev *dev) +{ + struct us_device* idev = dev->private; + struct input_dev* input = idev->input_poll_devp->input; + struct i2c_client* client = idev->client; + + int tmp_val = 0, debounce = 0; + int ret_val = 0; + + //printk("%s\n", __FUNCTION__); + if (p_enable != 0) + { + //mutex_lock(&mutex); + //printk(KERN_ALERT "by flashchen val is %x",val); + + #if 0 //just read raw data out 2013-7-18 + for (debounce=0; debounce<10; debounce++){ + ret_val = isl_get_lux_datap(client); + if (ret_val < 0) + return; + + tmp_val += ret_val; + msleep(1); + } + tmp_val /= 10; + //add for near/far detection! + if (tmp_val > 0x00ff) + tmp_val = 6; + else + tmp_val = 0; + input_report_abs(input, ABS_MISC, tmp_val); + input_sync(input); + #endif + + tmp_val = us5182_i2c_read(client, REGS_CR00); + + if (tmp_val & CR0_PROX_MASK) //approach + input_report_abs(input, ABS_MISC, 0); + else + input_report_abs(input, ABS_MISC, 6); + + input_sync(input); + //printk("%s %d\n", __FUNCTION__, tmp_val); + //mutex_unlock(&mutex); + } +} + +#if 0 +static struct i2c_device_id us5182_id[] = { + {"us5182", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, us5182_id); +#endif // 2013-7-9 + +static int mmad_open(struct inode *inode, struct file *file) +{ + dbg("Open the l-sensor node...\n"); + return 0; +} + +static int mmad_release(struct inode *inode, struct file *file) +{ + dbg("Close the l-sensor node...\n"); + return 0; +} + +static ssize_t mmadl_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + //printk("%s try to mutex_lock \n", __FUNCTION__); + //mutex_lock(&mutex); + //printk("lock ok!\n"); + lux_data = isl_get_lux_datal(l_sensorconfig->client); + //mutex_unlock(&mutex); + if (lux_data < 0) + { + printk("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + //return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + + +static ssize_t mmadp_read(struct file *fl, char __user *buf, size_t cnt, loff_t *lf) +{ + int lux_data = 0; + + //mutex_lock(&mutex); + lux_data = isl_get_lux_datap(l_sensorconfig->client); + //mutex_unlock(&mutex); + if (lux_data < 0) + { + errlog("Failed to read lux data!\n"); + return -1; + } + printk(KERN_ALERT "lux_data is %x\n",lux_data); + //return 0; + copy_to_user(buf, &lux_data, sizeof(lux_data)); + return sizeof(lux_data); +} + +static long +mmadl_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + + //printk("l-sensor ioctr... cmd 0x%x arg %d\n", cmd, arg); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + l_enable = enable; + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("us5182_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static long +mmadp_ioctl(/*struct inode *inode,*/ struct file *file, unsigned int cmd, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + //char rwbuf[5]; + short enable; //amsr = -1; + unsigned int uval; + unsigned char regval; + + dbg("l-sensor ioctr...\n"); + //memset(rwbuf, 0, sizeof(rwbuf)); + switch (cmd) { + case LIGHT_IOCTL_SET_ENABLE: + // enable/disable sensor + if (copy_from_user(&enable, argp, sizeof(short))) + { + printk(KERN_ERR "Can't get enable flag!!!\n"); + return -EFAULT; + } + dbg("enable=%d\n",enable); + if ((enable >=0) && (enable <=1)) + { + dbg("driver: disable/enable(%d) gsensor.\n", enable); + + //l_sensorconfig.sensor_enable = enable; + dbg("Should to implement d/e the light sensor!\n"); + p_enable = enable; + #if 1 + if(p_enable) + { + regval = us5182_i2c_read(l_sensorconfig->client, 0); + regval &= ~(3 << 4); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + else + { + regval = us5182_i2c_read(l_sensorconfig->client, 0); + regval &= ~(3 << 4); + regval |= (1 << 4); + i2c_smbus_write_byte_data(l_sensorconfig->client, 0, regval); + } + #endif + + } else { + printk(KERN_ERR "Wrong enable argument in %s !!!\n", __FUNCTION__); + return -EINVAL; + } + break; + case WMT_IOCTL_SENSOR_GET_DRVID: +#define DRVID 0 + uval = DRVID ; + if (copy_to_user((unsigned int*)arg, &uval, sizeof(unsigned int))) + { + return -EFAULT; + } + dbg("us5182_driver_id:%d\n",uval); + default: + break; + } + + return 0; +} + + +static struct file_operations mmadl_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadl_read, + .unlocked_ioctl = mmadl_ioctl, +}; + +static struct miscdevice mmadl_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "lsensor_ctrl", + .fops = &mmadl_fops, +}; + +static struct file_operations mmadp_fops = { + .owner = THIS_MODULE, + .open = mmad_open, + .release = mmad_release, + .read = mmadp_read, + .unlocked_ioctl = mmadp_ioctl, +}; + +static struct miscdevice mmadp_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "psensor_ctrl", + .fops = &mmadp_fops, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void us5182_early_suspend(struct early_suspend *h) +{ + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, ISL_MOD_POWERDOWN); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} + +static void us5182_late_resume(struct early_suspend *h) +{ + struct i2c_client *client = l_sensorconfig->client; + + dbg("start\n"); + mutex_lock(&mutex); + //pm_runtime_get_sync(dev); + //isl_set_mod(client, last_mod); + //isl_set_default_config(client); + //pm_runtime_put_sync(dev); + mutex_unlock(&mutex); + dbg("exit\n"); +} +#endif + +int us5182_i2c_write(struct i2c_client *client, u8 reg,u8 mask, u8 shift, int val ) { + //struct us5182_data *data = i2c_get_clientdata(client); + int err; + u8 tmp; + mutex_lock(&mutex); + + tmp = reg_cache[reg]; + tmp &= ~mask; + tmp |= val << shift; + + err = i2c_smbus_write_byte_data(client, reg, tmp); + if (!err) + reg_cache[reg] = tmp; + + mutex_unlock(&mutex); + if (err >= 0) return 0; + + printk("%s %d i2c transfer error\n", __func__, __LINE__); + return err; +} + + +static int set_word_mode(struct i2c_client *client, int mode) +{ + // + return us5182_i2c_write(client, REGS_CR00, + CR0_WORD_MASK, CR0_WORD_SHIFT, mode); +} + + +static int set_oneshotmode(struct i2c_client *client, int mode) +{ + return us5182_i2c_write(client,REGS_CR00,CR0_ONESHOT_MASK, CR0_ONESHOT_SHIFT, mode); +} + + +static int set_opmode(struct i2c_client *client, int mode) +{ + return us5182_i2c_write(client,REGS_CR00,CR0_OPMODE_MASK, + CR0_OPMODE_SHIFT, mode); +} + +/* power_status */ +static int set_power_status(struct i2c_client *client, int status) +{ + if(status == CR0_SHUTDOWN_EN ) + return us5182_i2c_write(client,REGS_CR00,CR0_SHUTDOWN_MASK, + CR0_SHUTDOWN_SHIFT,CR0_SHUTDOWN_EN); + else + return us5182_i2c_write(client,REGS_CR00,CR0_SHUTDOWN_MASK, + CR0_SHUTDOWN_SHIFT, CR0_OPERATION); +} + + +static int us5182_init_client(struct i2c_client *client) +{ + + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int i = 0; + int v = -1; + if ( !i2c_check_functionality(adapter,I2C_FUNC_SMBUS_BYTE_DATA) ) { + printk(KERN_INFO "byte op is not permited.\n"); + return -EIO; + } + + /* read all the registers once to fill the cache. + * if one of the reads fails, we consider the init failed */ + + for (i = 0; i < ARRAY_SIZE(reg_cache); i++) { + v = us5182_i2c_read(client, i); + printk("reg 0x%x value 0x%x \n", i, v); + if (v < 0) + return -ENODEV; + reg_cache[i] = v; + } + + /*Set Default*/ + set_word_mode(client, 0);//word enable? //just byte one time + set_power_status(client,CR0_OPERATION); //power on? + set_opmode(client,CR0_OPMODE_ALSONLY); //CR0_OPMODE_ALSANDPS CR0_OPMODE_ALSONLY + set_oneshotmode(client, CR0_ONESHOT_DIS); + + us5182_i2c_write(client, REGS_CR03, CR3_LEDDR_MASK, CR3_LEDDR_SHIFT, CR3_LEDDR_50); + + //set als gain + us5182_i2c_write(client, REGS_CR01, CR1_ALS_GAIN_MASK, CR1_ALS_GAIN_SHIFT, CR1_ALS_GAIN_X8); + + //set ps threshold --> lth, hth + us5182_i2c_write(client, REGS_INT_LSB_TH_HI_PS, 0xff, 0, psh_l8th); // + us5182_i2c_write(client, REGS_INT_MSB_TH_HI_PS, 0xff, 0, psh_h8th); //0 default + + us5182_i2c_write(client, REGS_INT_LSB_TH_LO_PS, 0xff, 0, psl_l8th); // + us5182_i2c_write(client, REGS_INT_MSB_TH_LO_PS, 0xff, 0, psl_h8th); // 0 default + //set_resolution(client,us5182_RES_16); + //set_range(client,3); + //set_int_ht(client,0x3E8); //1000 lux + //set_int_lt(client,0x8); //8 lux + //dev_info(&data->client->dev, "us5182 ver. %s found.\n",DRIVER_VERSION); + + /*init global variable*/ + error_flag = 0; + previous_value = 0; + this_value = 0; + debounces = 2;//debounces 5 times + return 0; +} +//******add for sys debug devic_attribute +static ssize_t reg_show(struct device *dev, struct device_attribute *attr, char *buf) { + + int i = 0, val = 0; + printk("<<<<<<<<<reg dump\n"); + + for (i=0; i<=0x1f; i++) { + val = us5182_i2c_read(gclient, i); + printk("reg 0x%x: val 0x%x \n", i, val); + + } + printk("\n"); + printk("<<<<<<<<<<<<<<<<<<<<dump end\n"); + return 0; +} + +static ssize_t reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + + int reg = 0, val = 0; + int ret = 0; + int res = 0; + + printk("buf is %s\n", buf); + + ret = sscanf(buf, "%x:%x", ®, &val); + printk("reg:val is 0x%x:0x%x\n", reg, val); + + if (reg<0 || val<0) { + printk("param error!\n"); + return -1; + } + + res = us5182_i2c_read(gclient, reg); + i2c_smbus_write_byte_data(gclient, reg, val); + printk(KERN_ERR "reg 0x%x 0x%x -->0x%x\n", reg, res, val); + + return count; +} +//struct device_attribute dev_attr_reg = __ATTR(reg, 0644, reg_show, reg_store); +//DEVICE_ATTR(reg, 0644, reg_show, reg_store); + +static ssize_t adc_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + + int i; + int size = sizeof(uadc)/sizeof(uadc[0]); + printk("<<<%s\n", __FUNCTION__); + for (i=0; i<size; i++) + { + printk(" %5d ", uadc[i]); + //sprintf(buf, "%d " &uadc[i]); + } + printk("\n"); + + return sizeof(uadc); + //printk(" %s \n", buf); +} + +static ssize_t adc_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + __u32 tmp; + int index; + int n; + int size = sizeof(uadc)/sizeof(uadc[0]); + + printk("<<<%s\n", __FUNCTION__); + printk("<< %s >>>\n", buf); + n = sscanf(buf, "%d:%d", &index, &tmp); + printk("<<<<int n %d %d:%d \n", n, index, tmp); + if ( n==2 && index>=0 && index<size){ + + uadc[index] = tmp; + no_adc_map = 0; + } + else { + printk("<<<param error!\n"); + no_adc_map = 1; + } + return count; +} + +static struct device_attribute us5182_attr[] = +{ + __ATTR(reg, 0644, reg_show, reg_store), + __ATTR(adc, 0644, adc_show, adc_store), + __ATTR_NULL, +}; + +static int device_create_attribute(struct device *dev, struct device_attribute *attr) +{ + int err = 0, i; + for (i=0; NULL != attr[i].attr.name; i++) + { + err = device_create_file(dev, &attr[i]); //&attr[i].attr + if (err) + break; + } + if (err) + { + for (; i>=0; i--) + device_remove_file(dev, &attr[i]);//&attr[i].attr + } + return err; +} + +static void device_remove_attribute(struct device *dev, struct device_attribute *attr) +{ + int i; + for (i=0; attr[i].attr.name != NULL; i++) + device_remove_file(dev, &attr[i]); //&attr[i].attr +} +//add end +static int +us5182_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int res=0; + + struct us_device* idev = kzalloc(sizeof(struct us_device), GFP_KERNEL); + if(!idev) + return -ENOMEM; + + l_sensorconfig = idev; + + /*initial enable device id*/ + idev->enable_id = 0x00; + + gclient = client; + /* initialize the us5182 chip */ + res = us5182_init_client(client);// + + if (res != 0) + goto err_input_allocate_device; +/* last mod is ALS continuous */ + //pm_runtime_enable(&client->dev); + idev->input_poll_devl = input_allocate_polled_device(); + if(!idev->input_poll_devl) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->input_poll_devp = input_allocate_polled_device(); + if(!idev->input_poll_devp) + { + res = -ENOMEM; + goto err_input_allocate_device; + } + idev->client = client; + + idev->input_poll_devl->private = idev; + idev->input_poll_devl->poll = isl_input_lux_poll_l; + idev->input_poll_devl->poll_interval = 100;//50; + idev->input_poll_devl->input->open = isl_input_open; + idev->input_poll_devl->input->close = isl_input_close; + idev->input_poll_devl->input->name = "lsensor_lux"; + idev->input_poll_devl->input->id.bustype = BUS_I2C; + idev->input_poll_devl->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devl->input, idev); + input_set_capability(idev->input_poll_devl->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devl->input, ABS_MISC, 0, 16000, 0, 0); + + idev->input_poll_devp->private = idev; + idev->input_poll_devp->poll = isl_input_lux_poll_p; + idev->input_poll_devp->poll_interval = 10;//100; 50ms + idev->input_poll_devp->input->open = isl_input_open; + idev->input_poll_devp->input->close = isl_input_close; + idev->input_poll_devp->input->name = "psensor_lux"; + idev->input_poll_devp->input->id.bustype = BUS_I2C; + idev->input_poll_devp->input->dev.parent = &client->dev; + + input_set_drvdata(idev->input_poll_devp->input, idev); + input_set_capability(idev->input_poll_devp->input, EV_ABS, ABS_MISC); + input_set_abs_params(idev->input_poll_devp->input, ABS_MISC, 0, 16000, 0, 0); + i2c_set_clientdata(client, idev); + /* set default config after set_clientdata */ + //res = isl_set_default_config(client); + res = misc_register(&mmadl_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerl; + } + res = misc_register(&mmadp_device); + if (res) { + errlog("mmad_device register failed\n"); + goto err_misc_registerp; + } + res = input_register_polled_device(idev->input_poll_devl); + if(res < 0) + goto err_input_register_devicel; + res = input_register_polled_device(idev->input_poll_devp); + if(res < 0) + goto err_input_register_devicep; + // suspend/resume register +#ifdef CONFIG_HAS_EARLYSUSPEND + idev->earlysuspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + idev->earlysuspend.suspend = us5182_early_suspend; + idev->earlysuspend.resume = us5182_late_resume; + register_early_suspend(&(idev->earlysuspend)); +#endif + + dbg("us5182 probe succeed!\n"); + res = alloc_chrdev_region(&idev->devno, 0, 1, "us5182"); + if(res) + { + printk("can't allocate chrdev\n"); + return 0; + } + idev->class = class_create(THIS_MODULE, "us5182-lsensor"); + if (IS_ERR(idev->class)) { + printk("<<< %s class_create() error!\n", __FUNCTION__); + return 0; + } + idev->lsdev = device_create(idev->class, NULL, idev->devno, NULL, "us5182"); + if (IS_ERR(idev->lsdev)) { + printk("<<< %s device_create() error!\n", __FUNCTION__); + return 0; + } + res = device_create_attribute(idev->lsdev, us5182_attr); + return 0; +err_input_register_devicep: + input_free_polled_device(idev->input_poll_devp); +err_input_register_devicel: + input_free_polled_device(idev->input_poll_devl); +err_misc_registerp: + misc_deregister(&mmadp_device); +err_misc_registerl: + misc_deregister(&mmadl_device); +err_input_allocate_device: + //__pm_runtime_disable(&client->dev, false); + kfree(idev); + return res; +} + +static int us5182_remove(struct i2c_client *client) +{ + int i = 0; + struct us_device* idev = i2c_get_clientdata(client); +#if 1 + //device_remove_file(idev->lsdev, &dev_attr_reg); + device_remove_attribute(idev->lsdev, us5182_attr); + unregister_chrdev_region(idev->devno, 1); + device_destroy(idev->class, idev->devno); + class_destroy(idev->class); +#endif + printk("%s %d\n", __FUNCTION__, i++); // 0 + //unregister_early_suspend(&(idev->earlysuspend)); + misc_deregister(&mmadl_device); + printk("%s %d\n", __FUNCTION__, i++); + misc_deregister(&mmadp_device); + printk("%s %d\n", __FUNCTION__, i++); + input_unregister_polled_device(idev->input_poll_devl);//here block?? + printk("%s %d\n", __FUNCTION__, i++); + input_unregister_polled_device(idev->input_poll_devp); + printk("%s %d\n", __FUNCTION__, i++); + input_free_polled_device(idev->input_poll_devl); + printk("%s %d\n", __FUNCTION__, i++); + input_free_polled_device(idev->input_poll_devp); + printk("%s %d\n", __FUNCTION__, i++); + //__pm_runtime_disable(&client->dev, false); + + kfree(idev); + printk(KERN_INFO MODULE_NAME ": %s us5182 remove call, \n", __func__); + return 0; +} +static void us5182_shutdown(struct i2c_client *client) +{ + l_enable = 0; + p_enable = 0; +} + +static int us5182_suspend(struct i2c_client *client, pm_message_t message) +{ + return 0; +} +static int us5182_resume(struct i2c_client *client) +{ + int res = 0; + res = us5182_init_client(client);// + return 0; +} + +static const struct i2c_device_id us5182_id[] = { + { SENSOR_I2C_NAME , 0 }, + {}, +}; + + +static struct i2c_driver us5182_i2c_driver = +{ + .probe = us5182_probe, + .remove = us5182_remove, + .suspend = us5182_suspend, + .resume = us5182_resume, + .shutdown = us5182_shutdown, + .driver = { + .name = SENSOR_I2C_NAME, + .owner = THIS_MODULE, + }, + .id_table = us5182_id, +}; + +static int get_adc_val(void) +{ + int i=0, varlen=0, n=0; + __u32 buf[8] = {0}; + char varbuf[50] ={0}; + char *name = "wmt.io.lsensor"; + char *psth = "wmt.io.psensor"; + int thbuf[4] = {0}; + + varlen = sizeof(varbuf); + if (wmt_getsyspara(psth, varbuf, &varlen)) + { + printk("<<<<fail to wmt_syspara %s\n", "wmt.io.psensor"); + + } + else + { + n = sscanf(varbuf, "%d:%d:%d:%d", &thbuf[0], &thbuf[1], &thbuf[2], &thbuf[3]); + if (n == 4) + { + psh_h8th = thbuf[0]; + psh_l8th = thbuf[1]; + psl_h8th = thbuf[2]; + psl_l8th = thbuf[3]; + } + else + printk("wmt.io.psensor error!\n"); + } + if (wmt_getsyspara(name, varbuf, &varlen)) + { + printk("<<<<fail to wmt_syspara %s\n", "wmt.io.lsensor"); + no_adc_map = 1; + return -1; + } + n = sscanf(varbuf, "%d:%d:%d:%d:%d:%d:%d:%d", &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5], \ + &buf[6], &buf[7]); + //printk("<<< n %d \n", n); + if (n != 8) + { + printk("<<<<<%s uboot env wmt.io.lsensor param error!\n", __FUNCTION__); + return -1; + } + for (i=0; i<8; i++) + { + //printk("<<<< %5d ", buf[i]); + uadc[i] = buf[i]; + } + no_adc_map = 0; + //printk("\n"); + return 0; +} + +static int __init sensor_us5182_init(void) +{ + printk(KERN_INFO MODULE_NAME ": %s us5182 init call, \n", __func__); + /* + * Force device to initialize: i2c-15 0x44 + * If i2c_new_device is not called, even us5182_detect will not run + * TODO: rework to automatically initialize the device + */ + //i2c_new_device(i2c_get_adapter(15), &isl_info); + //return i2c_add_driver(&us5182_driver); + if (!(this_client = sensor_i2c_register_device(4, SENSOR_I2C_ADDR, SENSOR_I2C_NAME))) + { + printk(KERN_EMERG"Can't register gsensor i2c device!\n"); + return -1; + } + if (us5182_detect(this_client)) // + { + errlog("Can't find light sensor us5182!\n"); + goto detect_fail; + } + + get_adc_val(); +/* + if(us5182_probe(this_client)) + { + errlog("Erro for probe!\n"); + goto detect_fail; + } +*/ + if(i2c_add_driver(&us5182_i2c_driver) < 0) + { + errlog("Erro for i2c_add_driver()!\n"); + goto detect_fail; + } + return 0; + +detect_fail: + sensor_i2c_unregister_device(this_client); + return -1; +} + +static void __exit sensor_us5182_exit(void) +{ + printk(KERN_INFO MODULE_NAME ": %s us5182 exit call \n", __func__); + //us5182_remove(this_client); + i2c_del_driver(&us5182_i2c_driver); + sensor_i2c_unregister_device(this_client); + +} + +module_init(sensor_us5182_init); +module_exit(sensor_us5182_exit); + +MODULE_AUTHOR("rambo"); +MODULE_ALIAS("us5182 ALS"); +MODULE_DESCRIPTION("us5182 Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.h b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.h new file mode 100755 index 00000000..361d91e8 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/sensor/us5182_lpsensor/us5182.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2012 UPI finley_huang <finley_huang@upi-semi.com>. All Rights Reserved. + * us5182 Light Sensor Driver for Linux 2.6 + */ + +/* + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __us5182_H__ +#define __us5182_H__ + +#include <linux/types.h> + +#define SENSOR_I2C_NAME "us5182" +#define SENSOR_I2C_ADDR (0x72>>1) //0x72 //7bit 0x39 +/*us5182 Slave Addr*/ +#define LIGHT_ADDR 0x39 //0x72 //7bit 0x39 + +/*Interrupt PIN for S3C6410*/ +//#define IRQ_LIGHT_INT IRQ_EINT(6) //comment for compile error + +/*Register Set*/ +#define REGS_CR00 0x00 +#define REGS_CR01 0x01 +#define REGS_CR02 0x02 +#define REGS_CR03 0x03 +//ALS +#define REGS_INT_LSB_TH_LO 0x04 +#define REGS_INT_MSB_TH_LO 0x05 +#define REGS_INT_LSB_TH_HI 0x06 +#define REGS_INT_MSB_TH_HI 0x07 +//PS +#define REGS_INT_LSB_TH_LO_PS 0x08 +#define REGS_INT_MSB_TH_LO_PS 0x09 +#define REGS_INT_LSB_TH_HI_PS 0x0A +#define REGS_INT_MSB_TH_HI_PS 0x0B +//ALS data +#define REGS_LSB_SENSOR 0x0C +#define REGS_MSB_SENSOR 0x0D +//PS data +#define REGS_LSB_SENSOR_PS 0x0E +#define REGS_MSB_SENSOR_PS 0x0F + +#define REGS_CR10 0x10 +#define REGS_CR11 0x11 +#define REGS_CR16 0x16 +#define REGS_CR20 0x20 +#define REGS_CR21 0x21 +#define REGS_CR22 0x22 +#define REGS_CR29 0x29 +#define REGS_CR2A 0x2A +#define REGS_CR2B 0x2B +#define REGS_VERSION_ID 0x1F +#define REGS_CHIP_ID 0xB2 + +/*ShutDown_EN*/ +#define CR0_OPERATION 0x0 +#define CR0_SHUTDOWN_EN 0x1 + +#define CR0_SHUTDOWN_SHIFT (7) +#define CR0_SHUTDOWN_MASK (0x1 << CR0_SHUTDOWN_SHIFT) + +/*OneShot_EN*/ +#define CR0_ONESHOT_EN 0x01 +#define CR0_ONESHOT_DIS 0x00 +#define CR0_ONESHOT_SHIFT (6) +#define CR0_ONESHOT_MASK (0x1 << CR0_ONESHOT_SHIFT) + +/*Operation Mode*/ +#define CR0_OPMODE_ALSANDPS 0x0 +#define CR0_OPMODE_ALSONLY 0x1 +#define CR0_OPMODE_IRONLY 0x2 + +#define CR0_OPMODE_SHIFT (4) +#define CR0_OPMODE_MASK (0x3 << CR0_OPMODE_SHIFT) + +/*all int flag (PROX, INT_A, INT_P)*/ +#define CR0_ALL_INT_CLEAR 0x0 + +#define CR0_ALL_INT_SHIFT (1) +#define CR0_ALL_INT_MASK (0x7 << CR0_ALL_INT_SHIFT) + + +/*indicator of object proximity detection*/ +#define CR0_PROX_CLEAR 0x0 + +#define CR0_PROX_SHIFT (3) +#define CR0_PROX_MASK (0x1 << CR0_PROX_SHIFT) + +/*interrupt status of proximity sensor*/ +#define CR0_INTP_CLEAR 0x0 + +#define CR0_INTP_SHIFT (2) +#define CR0_INTP_MASK (0x1 << CR0_INTP_SHIFT) + +/*interrupt status of ambient sensor*/ +#define CR0_INTA_CLEAR 0x0 + +#define CR0_INTA_SHIFT (1) +#define CR0_INTA_MASK (0x1 << CR0_INTA_SHIFT) + +/*Word mode enable*/ +#define CR0_WORD_EN 0x1 + +#define CR0_WORD_SHIFT (0) +#define CR0_WORD_MASK (0x1 << CR0_WORD_SHIFT) + + +/*ALS fault queue depth for interrupt enent output*/ +#define CR1_ALS_FQ_1 0x0 +#define CR1_ALS_FQ_4 0x1 +#define CR1_ALS_FQ_8 0x2 +#define CR1_ALS_FQ_16 0x3 +#define CR1_ALS_FQ_24 0x4 +#define CR1_ALS_FQ_32 0x5 +#define CR1_ALS_FQ_48 0x6 +#define CR1_ALS_FQ_63 0x7 + +#define CR1_ALS_FQ_SHIFT (5) +#define CR1_ALS_FQ_MASK (0x7 << CR1_ALS_FQ_SHIFT) + +/*resolution for ALS*/ +#define CR1_ALS_RES_12BIT 0x0 +#define CR1_ALS_RES_14BIT 0x1 +#define CR1_ALS_RES_16BIT 0x2 +#define CR1_ALS_RES_16BIT_2 0x3 + +#define CR1_ALS_RES_SHIFT (3) +#define CR1_ALS_RES_MASK (0x3 << CR1_ALS_RES_SHIFT) + +/*sensing amplifier selection for ALS*/ +#define CR1_ALS_GAIN_X1 0x0 +#define CR1_ALS_GAIN_X2 0x1 +#define CR1_ALS_GAIN_X4 0x2 +#define CR1_ALS_GAIN_X8 0x3 +#define CR1_ALS_GAIN_X16 0x4 +#define CR1_ALS_GAIN_X32 0x5 +#define CR1_ALS_GAIN_X64 0x6 +#define CR1_ALS_GAIN_X128 0x7 + +#define CR1_ALS_GAIN_SHIFT (0) +#define CR1_ALS_GAIN_MASK (0x7 << CR1_ALS_GAIN_SHIFT) + + +/*PS fault queue depth for interrupt event output*/ +#define CR2_PS_FQ_1 0x0 +#define CR2_PS_FQ_4 0x1 +#define CR2_PS_FQ_8 0x2 +#define CR2_PS_FQ_15 0x3 + +#define CR2_PS_FQ_SHIFT (6) +#define CR2_PS_FQ_MASK (0x3 << CR2_PS_FQ_SHIFT) + +/*interrupt type setting */ +/*low active*/ +#define CR2_INT_LEVEL 0x0 +/*low pulse*/ +#define CR2_INT_PULSE 0x1 + +#define CR2_INT_SHIFT (5) +#define CR2_INT_MASK (0x1 << CR2_INT_SHIFT) + +/*resolution for PS*/ +#define CR2_PS_RES_12 0x0 +#define CR2_PS_RES_14 0x1 +#define CR2_PS_RES_16 0x2 +#define CR2_PS_RES_16_2 0x3 + +#define CR2_PS_RES_SHIFT (3) +#define CR2_PS_RES_MASK (0x3 << CR2_PS_RES_SHIFT) + +/*sensing amplifier selection for PS*/ +#define CR2_PS_GAIN_1 0x0 +#define CR2_PS_GAIN_2 0x1 +#define CR2_PS_GAIN_4 0x2 +#define CR2_PS_GAIN_8 0x3 +#define CR2_PS_GAIN_16 0x4 +#define CR2_PS_GAIN_32 0x5 +#define CR2_PS_GAIN_64 0x6 +#define CR2_PS_GAIN_128 0x7 + +#define CR2_PS_GAIN_SHIFT (0) +#define CR2_PS_GAIN_MASK (0x7 << CR2_PS_GAIN_SHIFT) + +/*wait-time slot selection*/ +#define CR3_WAIT_SEL_0 0x0 +#define CR3_WAIT_SEL_4 0x1 +#define CR3_WAIT_SEL_8 0x2 +#define CR3_WAIT_SEL_16 0x3 + +#define CR3_WAIT_SEL_SHIFT (6) +#define CR3_WAIT_SEL_MASK (0x3 << CR3_WAIT_SEL_SHIFT) + +/*IR-LED drive peak current setting*/ +#define CR3_LEDDR_12_5 0x0 +#define CR3_LEDDR_25 0x1 +#define CR3_LEDDR_50 0x2 +#define CR3_LEDDR_100 0x3 + +#define CR3_LEDDR_SHIFT (4) +#define CR3_LEDDR_MASK (0x3 << CR3_LEDDR_SHIFT) + +/*INT pin source selection*/ +#define CR3_INT_SEL_BATH 0x0 +#define CR3_INT_SEL_ALS 0x1 +#define CR3_INT_SEL_PS 0x2 +#define CR3_INT_SEL_PSAPP 0x3 + +#define CR3_INT_SEL_SHIFT (2) +#define CR3_INT_SEL_MASK (0x3 << CR3_INT_SEL_SHIFT) + +/*software reset for register and core*/ +#define CR3_SOFTRST_EN 0x1 + +#define CR3_SOFTRST_SHIFT (0) +#define CR3_SOFTRST_MASK (0x1 << CR3_SOFTRST_SHIFT) + +/*modulation frequency of LED driver*/ +#define CR10_FREQ_DIV2 0x0 +#define CR10_FREQ_DIV4 0x1 +#define CR10_FREQ_DIV8 0x2 +#define CR10_FREQ_DIV16 0x3 + +#define CR10_FREQ_SHIFT (1) +#define CR10_FREQ_MASK (0x3 << CR10_FREQ_SHIFT) + +/*50/60 Rejection enable*/ +#define CR10_REJ_5060_DIS 0x00 +#define CR10_REJ_5060_EN 0x01 + +#define CR10_REJ_5060_SHIFT (0) +#define CR10_REJ_5060_MASK (0x1 << CR10_REJ_5060_SHIFT) + +#define us5182_NUM_CACHABLE_REGS 0x12 + +/*enable sensor*/ +#define ID_LIGHT 0 +#define ID_PROXIMITY 1 + +#define DEVICE_LIGHT (1 << ID_LIGHT) +#define DEVICE_PROXIMITY (1 << ID_PROXIMITY) +#endif |