diff options
Diffstat (limited to 'drivers/input/sensor/dmard08_gsensor')
-rwxr-xr-x | drivers/input/sensor/dmard08_gsensor/Makefile | 34 | ||||
-rwxr-xr-x | drivers/input/sensor/dmard08_gsensor/cyclequeue.c | 68 | ||||
-rwxr-xr-x | drivers/input/sensor/dmard08_gsensor/cyclequeue.h | 18 | ||||
-rwxr-xr-x | drivers/input/sensor/dmard08_gsensor/dmard08.c | 1019 | ||||
-rwxr-xr-x | drivers/input/sensor/dmard08_gsensor/dmard08.h | 75 |
5 files changed, 1214 insertions, 0 deletions
diff --git a/drivers/input/sensor/dmard08_gsensor/Makefile b/drivers/input/sensor/dmard08_gsensor/Makefile new file mode 100755 index 00000000..82f27563 --- /dev/null +++ b/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/drivers/input/sensor/dmard08_gsensor/cyclequeue.c b/drivers/input/sensor/dmard08_gsensor/cyclequeue.c new file mode 100755 index 00000000..4d6b97cd --- /dev/null +++ b/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/drivers/input/sensor/dmard08_gsensor/cyclequeue.h b/drivers/input/sensor/dmard08_gsensor/cyclequeue.h new file mode 100755 index 00000000..52b9996f --- /dev/null +++ b/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/drivers/input/sensor/dmard08_gsensor/dmard08.c b/drivers/input/sensor/dmard08_gsensor/dmard08.c new file mode 100755 index 00000000..3cbe2ac7 --- /dev/null +++ b/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/drivers/input/sensor/dmard08_gsensor/dmard08.h b/drivers/input/sensor/dmard08_gsensor/dmard08.h new file mode 100755 index 00000000..e6a6c935 --- /dev/null +++ b/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 + |