diff options
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/touchscreen/semisens')
6 files changed, 1838 insertions, 0 deletions
diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile new file mode 100755 index 00000000..4539aa8d --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile @@ -0,0 +1,33 @@ +KERNELDIR=../../../../ +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_ts_semisens + +obj-m := $(MY_MODULE_NAME).o +$(MY_MODULE_NAME)-objs := sn310m-touch.o touch.o +#mach-sn310m-sample.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 *.order *.symvers modules.builtin + +clean: + rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers modules.builtin diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h new file mode 100755 index 00000000..fcf1e3c6 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h @@ -0,0 +1,201 @@ +/**************************************************************** + * + * sn310m-touch-pdata.c + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ + +#ifndef __TOUCH_PDATA_H +#define __TOUCH_PDATA_H + +#ifdef CONFIG_HAS_EARLYSUSPEND + #include <linux/earlysuspend.h> +#endif + +#include <linux/interrupt.h> + +#ifndef errlog +#define errlog(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__, __LINE__ ,## args) +#endif + + +//#define DEBUG_TOUCH + +#undef dbg +#ifdef DEBUG_TOUCH +#define dbg(fmt, args...) printk(KERN_ERR "[%s:%d]: " fmt, __FUNCTION__, __LINE__ ,## args) +#else +#define dbg(fmt, args...) +#endif + +#undef MSM_GPIO_TO_INT +#define MSM_GPIO_TO_INT(a) (a) + + + + +#define I2C_TOUCH_NAME "SN310M" +#define I2C_SEND_MAX_SIZE 512 // I2C Send/Receive data max size + +//-------------------------------------------- +// Button struct (1 = press, 0 = release) +//-------------------------------------------- +typedef struct button__t { + unsigned char bt0_press :1; // lsb + unsigned char bt1_press :1; + unsigned char bt2_press :1; + unsigned char bt3_press :1; + unsigned char bt4_press :1; + unsigned char bt5_press :1; + unsigned char bt6_press :1; + unsigned char bt7_press :1; // msb +} __attribute__ ((packed)) button_t; + +typedef union button__u { + unsigned char ubyte; + button_t bits; +} __attribute__ ((packed)) button_u; + +//-------------------------------------------- +// Touch Event type define +//-------------------------------------------- +#define TS_EVENT_UNKNOWN 0x00 +#define TS_EVENT_PRESS 0x01 +#define TS_EVENT_MOVE 0x02 +#define TS_EVENT_RELEASE 0x03 + +typedef struct finger__t { + unsigned int status; // true : ts data updated, false : no update data + unsigned int event; // ts event type + unsigned int id; // ts received id + unsigned int x; // ts data x + unsigned int y; // ts data y + unsigned int area; // ts finger area + unsigned int pressure; // ts finger pressure +} __attribute__ ((packed)) finger_t; + +struct touch { + int irq; + struct i2c_client *client; + struct touch_pdata *pdata; + struct input_dev *input; + char phys[32]; + + finger_t *finger; // finger data + struct mutex mutex; + + // sysfs control flags + unsigned char disabled; // interrupt status + unsigned char fw_version; + + unsigned char *fw_buf; + unsigned int fw_size; + int fw_status; + + // irq func used + struct workqueue_struct *work_queue; + struct work_struct work; + + // noise filter work + struct delayed_work filter_dwork; + +#if defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend power; +#endif +}; + +struct i2c_client; +struct input_dev; +struct device; + +#define IRQ_MODE_THREAD 0 +#define IRQ_MODE_NORMAL 1 +#define IRQ_MODE_POLLING 2 + +//-------------------------------------------- +// IRQ type & trigger action +//-------------------------------------------- +// +// IRQF_TRIGGER_RISING, IRQF_TRIGGER_FALLING, IRQF_TRIGGER_HIGH, IRQF_TRIGGER_LOW +// IRQF_DISABLED, IRQF_SHARED, IRQF_IRQPOLL, IRQF_ONESHOT, IRQF_NO_THREAD +// +//-------------------------------------------- +struct touch_pdata { + char *name; // input drv name + + int irq_gpio; // irq gpio define + int reset_gpio; // reset gpio define + int reset_level; // reset level setting (1 = High reset, 0 = Low reset) + + int irq_mode; // IRQ_MODE_THREAD, IRQ_MODE_NORMAL, IRQ_MODE_POLLING + int irq_flags; // irq flags setup : Therad irq mode(IRQF_TRIGGER_HIGH | IRQF_ONESHOT) + + int abs_max_x, abs_max_y; + int abs_min_x, abs_min_y; + + int area_max, area_min; + int press_max, press_min; + int id_max, id_min; + + int vendor, product, version; + + int max_fingers; + + int *keycode, keycnt; + int lcd_exchg; + + //-------------------------------------------- + // Control function + //-------------------------------------------- + void (*gpio_init) (void); // gpio early-init function + + irqreturn_t (*irq_func) (int irq, void *handle); + void (*touch_work) (struct touch *ts); + + void (*report) (struct touch *ts); + void (*key_report) (struct touch *ts, unsigned char button_data); + + int (*early_probe) (struct touch *ts); + int (*probe) (struct touch *ts); + void (*enable) (struct touch *ts); + void (*disable) (struct touch *ts); + int (*input_open) (struct input_dev *input); + void (*input_close) (struct input_dev *input); + + void (*event_clear) (struct touch *ts); + +#ifdef CONFIG_HAS_EARLYSUSPEND + void (*resume) (struct early_suspend *h); + void (*suspend) (struct early_suspend *h); +#endif + + /* by limst, added to control power for touch IC */ + int (*power) (int on); + + //-------------------------------------------- + // I2C control function + //-------------------------------------------- + int (*i2c_write) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*i2c_read) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + + //-------------------------------------------- + // Firmware update control function + //-------------------------------------------- + char *fw_filename; + int fw_filesize; + + int (*i2c_boot_write) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*i2c_boot_read) (struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + int (*fw_control) (struct touch *ts, unsigned int fw_status); + int (*flash_firmware) (struct device *dev, const char *fw_name); + + //-------------------------------------------- + // Calibration control function + //-------------------------------------------- + int (*calibration) (struct touch *ts); +}; + +#endif // __TOUCH_PDATA_H + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c new file mode 100755 index 00000000..81275baf --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c @@ -0,0 +1,332 @@ +/**************************************************************** + * + * sn310m-touch.c : I2C Touchscreen driver (platform data struct) + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#include <linux/device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/hrtimer.h> +#include <asm/unaligned.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> + +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + +//---------------------------------------------- +#include "sn310m-touch-pdata.h" +#include "sn310m-touch.h" +#include "touch.h" + + +//---------------------------------------------- +unsigned char sn310m_id_tracking(struct touch *ts, unsigned char find_id); + +//---------------------------------------------- +// Touch i2c control function +//---------------------------------------------- +int sn310m_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) +{ + struct i2c_msg msg[2]; + int ret = 0; + unsigned char i = 0; + unsigned char cmd_tmp[10] = {0, }; + + if((len == 0) || (data == NULL)) { + dev_err(&client->dev, "I2C read error: Null pointer or length == 0\n"); + return -1; + } + + memset(cmd_tmp, 0x00, sizeof(cmd_tmp)); + + if(cmd_len) { + for(i = 0; i < cmd_len; i++) { + cmd_tmp[i] = cmd[cmd_len -1 -i]; + } + } + + memset(msg, 0x00, sizeof(msg)); + msg[0].addr = client->addr; + msg[0].flags = client->flags & I2C_M_TEN; + msg[0].len = cmd_len; + msg[0].buf = cmd_tmp; + + msg[1].addr = client->addr; + msg[1].flags = client->flags & I2C_M_TEN; + msg[1].flags |= I2C_M_RD; + msg[1].len = len; + msg[1].buf = data; + + if((ret = i2c_transfer(client->adapter, msg, 2)) != 2) { + dev_err(&client->dev, "I2C read error: (%d) reg: 0x%X len: %d\n", ret, cmd_tmp[0], len); + return -EIO; + } + + return len; +} + +int sn310m_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len) +{ + int ret = 0; + unsigned char block_data[10] = {0, }; + unsigned char i = 0; + unsigned char cmd_tmp[10] = {0, }; + + if((cmd_len + len) >= sizeof(block_data)) { + dev_err(&client->dev, "I2C write error: wdata overflow reg: 0x%X len: %d\n", cmd[0], cmd_len + len); + return -1; + } + + memset(block_data, 0x00, sizeof(block_data)); + memset(cmd_tmp, 0x00, sizeof(cmd_tmp)); + + if(cmd_len) { + for(i = 0; i < cmd_len; i++) { + cmd_tmp[i] = cmd[cmd_len -1 -i]; + } + } + + if(cmd_len) + memcpy(&block_data[0], &cmd_tmp[0], cmd_len); + + if(len) + memcpy(&block_data[cmd_len], &data[0], len); + + if((ret = i2c_master_send(client, block_data, (cmd_len + len))) < 0) { + dev_err(&client->dev, "I2C write error: (%d) reg: 0x%X len: %d\n", ret, cmd[0], len); + return ret; + } + + return len; +} + +//---------------------------------------------- +// Touch initialize & finalize function +//---------------------------------------------- +int sn310m_input_open(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + dbg("%s\n", __func__); + + ts->pdata->enable(ts); + + return 0; +} + +void sn310m_enable(struct touch *ts) +{ + unsigned short cmd = REG_TS_STATUS; + unsigned int rdata = 0; + dbg("sn310m_enable++\n"); + if(ts->disabled) { + while(!gpio_get_value(ts->pdata->irq_gpio)) + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rdata, sizeof(rdata)); + wmt_gpio_set_irq_type(ts->pdata->irq_gpio, IRQ_TYPE_EDGE_FALLING); + wmt_gpio_unmask_irq(ts->pdata->irq_gpio); + dbg("enable_irq (%d)\n",ts->irq); + ts->disabled = false; + } + dbg("sn310m_enable--\n"); +} + +void sn310m_disable(struct touch *ts) +{ + dbg("sn310m_disable++\n"); + if(!ts->disabled) { + //disable_irq(ts->irq);//wmt_gpio_mask_irq(ts->pdata->irq_gpio);// + wmt_gpio_mask_irq(ts->pdata->irq_gpio); + dbg("disable_irq(ts->irq);\n"); + ts->disabled = true; + if(ts->pdata->event_clear){ + ts->pdata->event_clear(ts); + } + } + dbg("sn310m_disable--"); +} + +int sn310m_early_probe(struct touch *ts) +{ + // nothing to do... + + return 0; +} + +int sn310m_probe(struct touch *ts) +{ + unsigned short cmd = REG_FIRMWARE_VERSION; + unsigned short rdata = 0; + + if(ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&rdata, sizeof(rdata)) < 0) { + errlog("fail to get touch ic firmware version.\n"); + return -1; + } + + ts->fw_version = rdata; + + dbg("touch ic firmware version : %d \n", rdata); + + return 0; +} + +//---------------------------------------------- +// calibration function +//---------------------------------------------- +int sn310m_calibration(struct touch *ts) +{ + // nothing to do... + + return 0; +} + +#define SN310M_NATIVE_INTERFACE +#if defined(SN310M_NATIVE_INTERFACE) +#include <linux/syscalls.h> +extern int g_MiscInitialize; +#endif + +//---------------------------------------------- +// Touch data processing function +//---------------------------------------------- +void sn310m_work(struct touch *ts) +{ + unsigned char find_slot = 0; + unsigned short cmd = 0; + status_reg_u status; + data_reg_t data; + button_u button; + unsigned int ids = 0; + int i = 0; + + mutex_lock(&ts->mutex); + + cmd = REG_TS_STATUS; + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&status.uint, sizeof(status_reg_u)); + + if(status.bits.ts_cnt <= ts->pdata->max_fingers) { + unsigned char cnt = 0; + + if(ts->pdata->keycode && (status.bits.ts_cnt == 0)) { + button.bits.bt0_press = (status.bits.button & 0x01) ? 1 : 0; + button.bits.bt1_press = (status.bits.button & 0x02) ? 1 : 0; + button.bits.bt2_press = (status.bits.button & 0x04) ? 1 : 0; + button.bits.bt3_press = (status.bits.button & 0x08) ? 1 : 0; + + ts->pdata->key_report(ts, button.ubyte); + } + + for(cnt = 0; cnt < status.bits.ts_cnt; cnt++) { + unsigned int id; + unsigned int x; + unsigned int y; + unsigned int area; + unsigned int pressure; + + cmd = REG_TS_DATA(cnt); + ts->pdata->i2c_read(ts->client, (unsigned char *)&cmd, sizeof(cmd), (unsigned char *)&data.packet0, sizeof(data_reg_t)); + + id = data.packet0 >> 12; + x = data.packet0 & 0xfff; + y = data.packet1 & 0xfff; + area = data.packet2 & 0xfff; + pressure = ((data.packet1 >> 8) & 0x00f0) + (data.packet2 >> 12); + + dbg("DEBUG(%s) : cmd=%d, id=%d, x=%d, y=%d, area=%d, pressure=%d \n", __func__, cmd, id, x, y, area, pressure); + dbg("DEBUG(%s) : pkt0=%x pkt1=%x pkt2=%x \n", __func__, data.packet0, data.packet1, data.packet2); + + if((x >= ts->pdata->abs_max_x) || (y >= ts->pdata->abs_max_y)) { + if(ts->pdata->event_clear) + ts->pdata->event_clear(ts); + + dbg("ERROR(%s) : x(%d) or y(%d) value overflow!\n", __func__, x, y); + continue; + } + + if(ts->pdata->id_max) { + if((id >= ts->pdata->id_max) || (id < ts->pdata->id_min)) { + if(ts->pdata->event_clear) + ts->pdata->event_clear(ts); + + dbg("ERROR(%s) : id(%d) value overflow!\n", __func__, id); + continue; + } + if((find_slot = sn310m_id_tracking(ts, id)) == 0xFF) { + dbg("ERROR(%s) : Empty slot not found\n", __func__); + continue; + } + } + else { + if(id == 0) + continue; + + find_slot = cnt; + } + + if(ts->finger[find_slot].event == TS_EVENT_UNKNOWN) + ts->finger[find_slot].event = TS_EVENT_PRESS; + else if((ts->finger[find_slot].event == TS_EVENT_PRESS) || (ts->finger[find_slot].event == TS_EVENT_MOVE)) + ts->finger[find_slot].event = TS_EVENT_MOVE; + + if (ts->pdata->lcd_exchg) { + int tmp; + tmp = x; + x = y; + y = ts->pdata->abs_max_x - tmp; + } + + ts->finger[find_slot].status = true; + ts->finger[find_slot].id = id; + ts->finger[find_slot].x = x; + ts->finger[find_slot].y = y; + ts->finger[find_slot].area = (ts->pdata->area_max < area) ? ts->pdata->area_max : area; + ts->finger[find_slot].pressure = (ts->pdata->press_max < pressure) ? ts->pdata->press_max : pressure; + ids |= 1 << find_slot; + } + } + + for(i = 0; i < ts->pdata->max_fingers; i++) { + if(!(ids & (1 << i))) { + if(ts->finger[i].event != TS_EVENT_UNKNOWN) { + ts->finger[i].status = true; + ts->finger[i].event = TS_EVENT_RELEASE; + } + } + } + + ts->pdata->report(ts); + mutex_unlock(&ts->mutex); + wmt_gpio_unmask_irq(ts->pdata->irq_gpio); +} + +unsigned char sn310m_id_tracking(struct touch *ts, unsigned char find_id) +{ + unsigned char find_slot = 0xFF; + int i = 0; + + for(i = 0; i < ts->pdata->max_fingers; i++) { + if(ts->finger[i].id == find_id) + find_slot = i; + + if((ts->finger[i].event == TS_EVENT_UNKNOWN) && (find_slot == 0xFF)) + find_slot = i; + } + return find_slot; +} + +//---------------------------------------------- +// Firmware update Control function +//---------------------------------------------- +int sn310m_flash_firmware(struct device *dev, const char *fw_name) +{ + // nothing to do... + return 0; +} diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h new file mode 100755 index 00000000..0469bf19 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h @@ -0,0 +1,97 @@ +/**************************************************************** + * + * sn310m-touch.c : i2c Touchscreen driver (platform data struct) + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#ifndef __SN310M_TOUCH_H +#define __SN310M_TOUCH_H + +//---------------------------------------------- +// register address for firmware update +//---------------------------------------------- +#define REG_CMD_ISP_MODE 0x02F1 // 0x0200 : prepare eFlash, 0x0100 : finish eFalsh +#define REG_CMD_FLASH_BUS 0x04F1 // 0x0000 : set eFlash bus functions +#define REG_CMD_FLASH_ENABLE 0x08F1 // 0xFFFF : enable eFlash functions +#define REG_CMD_FLASH_AUTH 0x00F4 // 0x0100 : get eFlash approach authority +#define REG_CMD_FLASH_CON_EN 0x02F4 // 0x0000 : enable eFlash controller +#define REG_CMD_FLASH_COMMAND 0x04F4 // 0x0200 : erase eFlash, 0x0000 : write eFlash +#define REG_CMD_FLASH_BUSY 0x08F4 // [15] bit is busy flag for eflash eperating. + +//---------------------------------------------- +// register setting value for firmware update +//---------------------------------------------- +#define REG_SET_PREPARE_FLASH_ACCESS 0x0200 +#define REG_SET_FINISH_FLASH_ACCESS 0x0100 +#define REG_SET_ENABLE_FLASH_ERASE 0x0200 +#define REG_SET_ENABLE_FLASH_WRITE 0x0000 + +#define SN310M_MAX_FW_SIZE (10*1024) // 10 Kbytes +#define REG_FIRMWARE_VERSION (0x3EE0) + +//---------------------------------------------- +// Touch status & data register address +//---------------------------------------------- +#define REG_TS_STATUS 0x00E0 + +typedef struct status_reg__t { + unsigned int ts_cnt :4; // lsb + unsigned int reserved1 :4; + unsigned int button :5; + unsigned int reserved2 :3; // msb +} __attribute__ ((packed)) status_reg_t; + +typedef union status_reg__u { + unsigned short uint; + status_reg_t bits; +} __attribute__ ((packed)) status_reg_u; + +#define REG_TS_DATA_BASE 0x02E0 +#define REG_TS_DATA(x) (((x * 6) << 8) + REG_TS_DATA_BASE) + +typedef struct data_reg__t { + unsigned short packet0; + unsigned short packet1; + unsigned short packet2; +} __attribute__ ((packed)) data_reg_t; + +typedef union data_reg__u { + unsigned int uint; + data_reg_t bits; +} __attribute__ ((packed)) data_reg_u; + + +//---------------------------------------------- +// i2c Control function +//---------------------------------------------- +extern int sn310m_i2c_read(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); +extern int sn310m_i2c_write(struct i2c_client *client, unsigned char *cmd, unsigned int cmd_len, unsigned char *data, unsigned int len); + +//---------------------------------------------- +// Touch initialize & finalize function +//---------------------------------------------- +extern int sn310m_input_open(struct input_dev *input); +extern void sn310m_enable(struct touch *ts); +extern void sn310m_disable(struct touch *ts); +extern int sn310m_early_probe(struct touch *ts); +extern int sn310m_probe(struct touch *ts); + +//---------------------------------------------- +// Calibration function +//---------------------------------------------- +extern int sn310m_calibration(struct touch *ts); + +//---------------------------------------------- +// Touch data processing function +//---------------------------------------------- +extern void sn310m_work(struct touch *ts); + +//---------------------------------------------- +// Firmware update Control function +//---------------------------------------------- +extern int sn310m_flash_firmware(struct device *dev, const char *fw_name); + +#endif // __SN310M_TOUCH_H + diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c new file mode 100755 index 00000000..39d6ce15 --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c @@ -0,0 +1,1121 @@ +/**************************************************************** + * + * touch.c : I2C Touchscreen driver + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/hrtimer.h> +#include <asm/unaligned.h> +#include <linux/firmware.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> + +//---------------------------------------------- +#if defined(CONFIG_HAS_EARLYSUSPEND) + #include <linux/wakelock.h> + #include <linux/earlysuspend.h> + #include <linux/suspend.h> +#endif + +//---------------------------------------------- +#include <linux/input/mt.h> +#include "sn310m-touch-pdata.h" +#include "sn310m-touch.h" + +//---------------------------------------------- +#include "touch.h" +#include <linux/gpio.h> +#include <mach/wmt_iomux.h> + + +extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +extern int wmt_setsyspara(char *varname, unsigned char *varval); + +#define SN310M_NATIVE_INTERFACE /* This is to debug semisens TSC */ + +#if defined(SN310M_NATIVE_INTERFACE) +#include <linux/miscdevice.h> +#include <linux/syscalls.h> +struct touch* g_ts; +int g_MiscInitialize = 0; +static int P_SN310M_Dist_Probe(struct touch* ts); +static int P_SN310M_Dist_Open(struct inode *inode, struct file *file); +static long P_SN310M_Dist_Ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static void P_SN310M_Dist_Remove(void); +#endif + +// function prototype define +//---------------------------------------------- +#ifdef CONFIG_HAS_EARLYSUSPEND + static void touch_suspend(struct early_suspend *h); + static void touch_resume(struct early_suspend *h); +#endif + +irqreturn_t touch_irq(int irq, void *handle); +#if 0 /* unused */ + static void touch_work(struct touch *ts); +#endif +static void touch_work_q(struct work_struct *work); +static void touch_key_report(struct touch *ts, unsigned char button_data); +static void touch_report_protocol_a(struct touch *ts); +static void touch_report_protocol_b(struct touch *ts); +static void touch_event_clear(struct touch *ts); +#if 0 /* unused */ + static void touch_enable(struct touch *ts); + static void touch_disable(struct touch *ts); +#endif +static void touch_input_close(struct input_dev *input); +static int touch_input_open(struct input_dev *input); +static int touch_check_functionality (struct touch_pdata *pdata); +void touch_hw_reset(struct touch *ts); +int touch_info_display(struct touch *ts); +int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id); +int touch_remove(struct i2c_client *client); + + +// Kinsey: +#define WMT_TS_I2C_NAME "wmt-ts" +static struct i2c_client *l_client; + + + + +//---------------------------------------------- +irqreturn_t touch_irq(int irq, void *handle) +{ + struct touch *ts = handle; + if (gpio_irqstatus(ts->pdata->irq_gpio)){ + wmt_gpio_ack_irq(ts->pdata->irq_gpio); + if (is_gpio_irqenable(ts->pdata->irq_gpio)){ + wmt_gpio_mask_irq(ts->pdata->irq_gpio); + #ifdef CONFIG_HAS_EARLYSUSPEND + if(!ts->earlysus) + queue_work(ts->work_queue, &ts->work); + #else + queue_work(ts->work_queue, &ts->work); + #endif + } + return IRQ_HANDLED; + } + return IRQ_NONE; + +} + +//---------------------------------------------- +static void touch_work_q(struct work_struct *work) +{ + struct touch *ts = container_of(work, struct touch, work); + ts->pdata->touch_work(ts); +} + +//---------------------------------------------- +static void touch_key_report(struct touch *ts, unsigned char button_data) +{ + static button_u button_old; + button_u button_new; + + button_new.ubyte = button_data; + if(button_old.ubyte != button_new.ubyte) { + if((button_old.bits.bt0_press != button_new.bits.bt0_press) && (ts->pdata->keycnt > 0)) { + if(button_new.bits.bt0_press) input_report_key(ts->input, ts->pdata->keycode[0], true); + else input_report_key(ts->input, ts->pdata->keycode[0], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[0](0x%04X) %s\n", ts->pdata->keycode[0], button_new.bits.bt0_press ? "press":"release"); + #endif + } + if((button_old.bits.bt1_press != button_new.bits.bt1_press) && (ts->pdata->keycnt > 1)) { + if(button_new.bits.bt1_press) input_report_key(ts->input, ts->pdata->keycode[1], true); + else input_report_key(ts->input, ts->pdata->keycode[1], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[1](0x%04X) %s\n", ts->pdata->keycode[1], button_new.bits.bt1_press ? "press":"release"); + #endif + } + if((button_old.bits.bt2_press != button_new.bits.bt2_press) && (ts->pdata->keycnt > 2)) { + if(button_new.bits.bt2_press) input_report_key(ts->input, ts->pdata->keycode[2], true); + else input_report_key(ts->input, ts->pdata->keycode[2], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[2](0x%04X) %s\n", ts->pdata->keycode[2], button_new.bits.bt2_press ? "press":"release"); + #endif + } + if((button_old.bits.bt3_press != button_new.bits.bt3_press) && (ts->pdata->keycnt > 3)) { + if(button_new.bits.bt3_press) input_report_key(ts->input, ts->pdata->keycode[3], true); + else input_report_key(ts->input, ts->pdata->keycode[3], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[3](0x%04X) %s\n", ts->pdata->keycode[3], button_new.bits.bt3_press ? "press":"release"); + #endif + } + if((button_old.bits.bt4_press != button_new.bits.bt4_press) && (ts->pdata->keycnt > 4)) { + if(button_new.bits.bt4_press) input_report_key(ts->input, ts->pdata->keycode[4], true); + else input_report_key(ts->input, ts->pdata->keycode[4], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[4](0x%04X) %s\n", ts->pdata->keycode[4], button_new.bits.bt4_press ? "press":"release"); + #endif + } + if((button_old.bits.bt5_press != button_new.bits.bt5_press) && (ts->pdata->keycnt > 5)) { + if(button_new.bits.bt5_press) input_report_key(ts->input, ts->pdata->keycode[5], true); + else input_report_key(ts->input, ts->pdata->keycode[5], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[5](0x%04X) %s\n", ts->pdata->keycode[5], button_new.bits.bt5_press ? "press":"release"); + #endif + } + if((button_old.bits.bt6_press != button_new.bits.bt6_press) && (ts->pdata->keycnt > 6)) { + if(button_new.bits.bt6_press) input_report_key(ts->input, ts->pdata->keycode[6], true); + else input_report_key(ts->input, ts->pdata->keycode[6], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[6](0x%04X) %s\n", ts->pdata->keycode[6], button_new.bits.bt6_press ? "press":"release"); + #endif + } + if((button_old.bits.bt7_press != button_new.bits.bt7_press) && (ts->pdata->keycnt > 7)) { + if(button_new.bits.bt7_press) input_report_key(ts->input, ts->pdata->keycode[7], true); + else input_report_key(ts->input, ts->pdata->keycode[7], false); + #if defined(DEBUG_TOUCH_KEY) + dbg("keycode[7](0x%04X) %s\n", ts->pdata->keycode[7], button_new.bits.bt7_press ? "press":"release"); + #endif + } + button_old.ubyte = button_new.ubyte; + } +} + +//---------------------------------------------- +static void touch_report_protocol_a(struct touch *ts) +{ + int id; + + for(id = 0; id < ts->pdata->max_fingers; id++) { + + if(ts->finger[id].event == TS_EVENT_UNKNOWN) continue; + + if(ts->finger[id].event != TS_EVENT_RELEASE) { + if(ts->pdata->id_max) input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); + if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); + if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); + + input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); + dbg("%s : id = %d, x = %d, y = %d\n", __func__, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); + } + else { + ts->finger[id].event = TS_EVENT_UNKNOWN; + dbg("%s : release id = %d\n", __func__, ts->finger[id].id); + } + + input_mt_sync(ts->input); + } + + input_sync(ts->input); +} + +//---------------------------------------------- +static void touch_report_protocol_b(struct touch *ts) +{ + int id; +#if defined(DEBUG_TOUCH) + char *event_str[] = {"unknown", "press", "move", "release"}; +#endif + + for(id = 0; id < ts->pdata->max_fingers; id++) { + if((ts->finger[id].event == TS_EVENT_UNKNOWN) || (ts->finger[id].status == false)) + continue; + + input_mt_slot(ts->input, id); + ts->finger[id].status = false; + + if(ts->finger[id].event != TS_EVENT_RELEASE) { + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + + input_report_abs(ts->input, ABS_MT_TRACKING_ID, ts->finger[id].id); + input_report_abs(ts->input, ABS_MT_POSITION_X, ts->finger[id].x); + input_report_abs(ts->input, ABS_MT_POSITION_Y, ts->finger[id].y); + + if(ts->pdata->area_max) input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, ts->finger[id].area ? ts->finger[id].area : 10); + if(ts->pdata->press_max) input_report_abs(ts->input, ABS_MT_PRESSURE, ts->finger[id].pressure); + +#if defined(DEBUG_TOUCH) + dbg("%s : event = %s, slot = %d, id = %d, x = %d, y = %d\n", __func__, event_str[ts->finger[id].event], id, ts->finger[id].id, ts->finger[id].x, ts->finger[id].y); +#endif + } + else { +#if defined(DEBUG_TOUCH) + dbg("%s : event = %s, slot = %d, id = %d\n", __func__, event_str[ts->finger[id].event], id, ts->finger[id].id); +#endif + ts->finger[id].event = TS_EVENT_UNKNOWN; + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false); + } + } + input_sync(ts->input); +} + +//---------------------------------------------- +static void touch_event_clear(struct touch *ts) +{ + unsigned char id; + + for(id = 0; id < ts->pdata->max_fingers; id++) { + if(ts->finger[id].event == TS_EVENT_MOVE) { + ts->finger[id].status = true; + ts->finger[id].event = TS_EVENT_RELEASE; + } + } + ts->pdata->report(ts); + if(ts->pdata->keycode) + ts->pdata->key_report(ts, 0x00); +} + +//---------------------------------------------- +static int touch_input_open(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + ts->pdata->enable(ts); + + dbg("%s\n", __func__); + + return 0; +} + +//---------------------------------------------- +static void touch_input_close(struct input_dev *input) +{ + struct touch *ts = input_get_drvdata(input); + + ts->pdata->disable(ts); + + dbg("%s\n", __func__); +} + +//---------------------------------------------- +static int touch_check_functionality(struct touch_pdata *pdata) +{ + if(!pdata) { + errlog("Error : Platform data is NULL pointer!\n"); return -1; + } + + pdata->i2c_read = sn310m_i2c_read; + pdata->i2c_write = sn310m_i2c_write; + + pdata->i2c_boot_read = sn310m_i2c_read; + pdata->i2c_boot_write = sn310m_i2c_write; + + pdata->enable = sn310m_enable; + pdata->disable = sn310m_disable; + pdata->probe = sn310m_probe; + + if(!pdata->report) { + if(pdata->id_max) pdata->report = touch_report_protocol_b; + else pdata->report = touch_report_protocol_a; + } + if(!pdata->key_report) pdata->key_report = touch_key_report; + + pdata->touch_work = sn310m_work; + + if(!pdata->irq_func) pdata->irq_func = touch_irq; + + if(!pdata->event_clear) pdata->event_clear = touch_event_clear; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if(!pdata->resume) pdata->resume = touch_resume; + if(!pdata->suspend) pdata->suspend = touch_suspend; +#endif + + //pdata->irq_gpio = 7; + + return 0; +} + +//---------------------------------------------- +void touch_hw_reset(struct touch *ts) +{ + if(ts->pdata->reset_gpio) { + if(gpio_request(ts->pdata->reset_gpio, "touch reset")) { + errlog("--------------------------------------------------------\n"); + errlog("%s : request port error!\n", "touch reset"); + errlog("--------------------------------------------------------\n"); + } + else { + if(ts->pdata->power) { + /* power sequence: reset low -> power on -> reset high */ + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + mdelay(15); + ts->pdata->power(1); + mdelay(50); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + } + else { + /* if there is no power control for touch, then just do reset (high -> low -> high) */ + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + gpio_set_value(ts->pdata->reset_gpio, 0); + mdelay(20); + gpio_set_value(ts->pdata->reset_gpio, 1); + mdelay(15); + } + } + } +} + +//---------------------------------------------- +int touch_info_display(struct touch *ts) +{ + errlog("--------------------------------------------------------\n"); + errlog(" TOUCH SCREEN INFORMATION\n"); + errlog("--------------------------------------------------------\n"); + if(ts->pdata->irq_gpio) { + errlog("TOUCH INPUT Name = %s\n", ts->pdata->name); + + switch(ts->pdata->irq_mode) { + default : + case IRQ_MODE_THREAD: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_THREAD"); break; + case IRQ_MODE_NORMAL: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_NORMAL"); break; + case IRQ_MODE_POLLING: errlog("TOUCH IRQ Mode = %s\n", "IRQ_MODE_POLLING"); break; + } + errlog("TOUCH F/W Version = %d.%02d\n", ts->fw_version / 100, ts->fw_version % 100); + errlog("TOUCH FINGRES MAX = %d\n", ts->pdata->max_fingers); + errlog("TOUCH ABS X MAX = %d, TOUCH ABS X MIN = %d\n", ts->pdata->abs_max_x, ts->pdata->abs_min_x); + errlog("TOUCH ABS Y MAX = %d, TOUCH ABS Y MIN = %d\n", ts->pdata->abs_max_y, ts->pdata->abs_min_y); + + if(ts->pdata->area_max) + errlog("TOUCH MAJOR MAX = %d, TOUCH MAJOR MIN = %d\n", ts->pdata->area_max, ts->pdata->area_min); + + if(ts->pdata->press_max) + errlog("TOUCH PRESS MAX = %d, TOUCH PRESS MIN = %d\n", ts->pdata->press_max, ts->pdata->press_min); + + if(ts->pdata->id_max) { + errlog("TOUCH ID MAX = %d, TOUCH ID MIN = %d\n", ts->pdata->id_max, ts->pdata->id_min); + errlog("Mulit-Touch Protocol-B Used.\n"); + } + else + errlog("Mulit-Touch Protocol-A Used.\n"); + + if(ts->pdata->gpio_init) + errlog("GPIO early-init function implemented\n"); + + if(ts->pdata->reset_gpio) + errlog("H/W Reset function implemented\n"); + + #ifdef CONFIG_HAS_EARLYSUSPEND + errlog("Early-suspend function implemented\n"); + #endif + if(ts->pdata->fw_control) + errlog("Firmware update function(sysfs control) implemented\n"); + + /* flashing sample is not implemented yet */ + if(ts->pdata->flash_firmware) + errlog("Firmware update function(udev control) implemented\n"); + + if(ts->pdata->calibration) + errlog("Calibration function implemented\n"); + } + else { + errlog("TOUCH INPUT Name = %s\n", ts->pdata->name); + errlog("Dummy Touchscreen driver!\n"); + } + errlog("--------------------------------------------------------\n"); + return 0; +} + +//---------------------------------------------- +int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id) +{ + return -1; +} + +//---------------------------------------------- +// +// Power Management function +// +//---------------------------------------------- +#ifdef CONFIG_HAS_EARLYSUSPEND +static void touch_suspend(struct early_suspend *h) +{ + struct touch *ts = container_of(h, struct touch, power); + + dbg("%s++\n", __func__); + + /* TSC enters deep sleep mode */ + dbg("[%s] touch reset goes low!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + + ts->pdata->disable(ts); +} + +//---------------------------------------------- +static void touch_resume(struct early_suspend *h) +{ + struct touch *ts = container_of(h, struct touch, power); + + dbg("%s++\n", __func__); + + /* TSC enters active mode */ + dbg("[%s] touch reset goes high!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + + ts->pdata->enable(ts); +} +#endif + +//---------------------------------------------- +int touch_remove(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("touch_remove++"); + + if(ts->irq) free_irq(ts->irq, ts); + + if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); + + if(ts->pdata->irq_gpio) gpio_free(ts->pdata->irq_gpio); + + input_unregister_device(ts->input); + + dev_set_drvdata(dev, NULL); + +#if defined(SN310M_NATIVE_INTERFACE) + P_SN310M_Dist_Remove(); +#endif + + kfree(ts->finger); ts->finger = NULL; + kfree(ts); ts = NULL; + + return 0; +} + +#if defined(SN310M_NATIVE_INTERFACE) +#define SN310M_DIST_MINOR 250 + +typedef struct { + unsigned int addr; + short *buf; + unsigned int size; +} packet_t; + +static const struct file_operations SN310M_Dist_Fops = +{ + .owner = THIS_MODULE, + .open = P_SN310M_Dist_Open, + .unlocked_ioctl = P_SN310M_Dist_Ioctl, +}; + + +static struct miscdevice SN310M_Dist_MiscDev = +{ + .minor = SN310M_DIST_MINOR, + .name = "sn310m_dist", + .fops = &SN310M_Dist_Fops, + .mode = 0x666, +}; + + +static long P_SN310M_Dist_Ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + packet_t* packet = (packet_t*)arg; + int i; + + mutex_lock(&g_ts->mutex); + switch(cmd) { + case 0: // write data + if(packet->size) { + unsigned short addr = (packet->addr >> 8) | (packet->addr & 0x00ff) << 8; + g_ts->pdata->i2c_write(g_ts->client, (unsigned char *)&addr, sizeof(addr), (unsigned char *)packet->buf, packet->size*2); + dbg("Request I2C Write\n"); + } + break; + + case 1: // read data + if(packet->size) { + unsigned short addr = (packet->addr >> 8) | (packet->addr & 0x00ff) << 8; + short buffer[500] = {0, }; + + g_ts->pdata->i2c_read(g_ts->client, (unsigned char *)&addr, sizeof(addr), (unsigned char *)buffer, packet->size*2); + for(i = 0; (i < packet->size) && (i < 500); i++) { + packet->buf[i] = buffer[i]; + } + dbg("Request I2C Read\n"); + } + break; + + default: + mutex_unlock(&g_ts->mutex); + return -ENOIOCTLCMD; + } + + mutex_unlock(&g_ts->mutex); + return 0; +} + +static int P_SN310M_Dist_Open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int P_SN310M_Dist_Probe(struct touch* ts) +{ + int result = 0; + + g_ts = ts; + result = misc_register(&SN310M_Dist_MiscDev); + if(result == 0) { + dbg("succeeded to register sn310m_misc_device \n"); + } + else { + errlog("failed to register sn310m_misc_device \n"); + } + + return result; +} + +static void P_SN310M_Dist_Remove(void) +{ + misc_deregister(&SN310M_Dist_MiscDev); + g_ts = NULL; +} +#endif +static const struct i2c_device_id sample_ts_id[] = { + { I2C_TOUCH_NAME, 0 }, + {}, +}; + + + +#define TS_DRIVER_NAME "wmt-touch" + +static void wmt_ts_platform_release(struct device *device) +{ + dbg("wmt_ts_platform_release\n"); + return; +} + +static struct platform_device wmt_ts_plt_device = { + .name = TS_DRIVER_NAME, + .id = 0, + .dev = { + .release = wmt_ts_platform_release, + }, +}; + +static int sn310m_keycode[] = { + KEY_HOME, KEY_MENU, KEY_BACK, KEY_SEARCH +}; + +struct touch_pdata sn310m_touch_pdata = { + + .name = "sn310m", // input drv name + .irq_gpio = 7,//SAMPLE_GPIO_0, // irq gpio define + .reset_gpio = 4,//SAMPLE_GPIO_1, // reset gpio define + .reset_level = 0, // reset level setting (1 = High reset, 0 = Low reset) + + .irq_mode = IRQ_MODE_NORMAL, // IRQ_MODE_THREAD, IRQ_MODE_NORMAL, IRQ_MODE_POLLING + .irq_flags = IRQF_SHARED ,//IRQF_TRIGGER_FALLING | IRQF_DISABLED, + + .abs_max_x = 600, + .abs_max_y = 1024, + + .area_max = 10, + .press_max = 255, + + .id_max = 10 + 1, + .id_min = 0, + + .vendor = 0x16B4, + .product = 0x0310, + .version = 0x0001, + + .max_fingers = 5, + + .keycnt = 4, + .keycode = sn310m_keycode, + .lcd_exchg = 0, + + //-------------------------------------------- + // Control function + //-------------------------------------------- + .touch_work = sn310m_work, + .enable = sn310m_enable, + .disable = sn310m_disable, + .early_probe = sn310m_early_probe, + .probe = sn310m_probe, + + //-------------------------------------------- + // I2C control function + //-------------------------------------------- + .i2c_write = sn310m_i2c_write, + .i2c_read = sn310m_i2c_read, + + //-------------------------------------------- + // Calibration function + //-------------------------------------------- + .calibration = sn310m_calibration, + + //-------------------------------------------- + // Firmware update control function + //-------------------------------------------- + .fw_filename = "sn310m_fw.bin", + .fw_filesize = (10 * 1024), // 10K bytes + .input_open = sn310m_input_open, + .flash_firmware = sn310m_flash_firmware, +}; + + +int temp; +static int wmt_ts_probe(struct platform_device *pdev) +{ + int rc = -1; + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts; + + + dbg("wmt_ts_probe\n"); + + if(!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "i2c byte data not supported\n"); + return -EIO; + } + + + client->dev.platform_data = &sn310m_touch_pdata; + + if(touch_check_functionality(client->dev.platform_data) < 0) { + dev_err(&client->dev, "Platform data is not available!\n"); + return -EINVAL; + } + + if(!(ts = kzalloc(sizeof(struct touch), GFP_KERNEL))) { + errlog("touch struct malloc error!\n"); + return -ENOMEM; + } + ts->client = client; + ts->pdata = client->dev.platform_data; + + + /* by limst, setting gpio for IRQ */ + if(ts->pdata->irq_gpio) { + int ret; + + ts->irq = IRQ_GPIO;//MSM_GPIO_TO_INT(ts->pdata->irq_gpio); + dbg("IRQ_GPIO(%d) IRQ(%d) REG\n", ts->pdata->irq_gpio, ts->irq); + + ret = gpio_request(ts->pdata->irq_gpio, "touch_int"); + if(ret < 0) + errlog("FAIL: touch_int gpio_request\n"); + else + dbg("OK: touch_int gpio_request value(%d)\n", gpio_get_value(ts->pdata->irq_gpio)); + + wmt_gpio_setpull(ts->pdata->irq_gpio,WMT_GPIO_PULL_UP); + gpio_direction_input(ts->pdata->irq_gpio); + wmt_gpio_set_irq_type(ts->pdata->irq_gpio, IRQ_TYPE_EDGE_FALLING); + } + + i2c_set_clientdata(client, ts); + + if(ts->pdata->max_fingers) { + if(!(ts->finger = kzalloc(sizeof(finger_t) * ts->pdata->max_fingers, GFP_KERNEL))) { + kfree(ts); + errlog("touch data struct malloc error!\n"); + return -ENOMEM; + } + } + + if(ts->pdata->gpio_init) ts->pdata->gpio_init(); + + if(ts->pdata->early_probe) { + if((rc = ts->pdata->early_probe(ts)) < 0) + goto err_free_mem; + } + + + dev_set_drvdata(dev, ts); + + if(!(ts->input = input_allocate_device())) + goto err_free_mem; + + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", ts->pdata->name); + + if(!ts->pdata->input_open) ts->input->open = touch_input_open; + else ts->input->open = ts->pdata->input_open; + if(!ts->pdata->input_close) ts->input->close = touch_input_close; + else ts->input->close = ts->pdata->input_close; + + /* + * by limst, for the test purpose, + * input device's name is forcedly set to the name of android idc file + */ + ts->input->name = "qwerty";//idc's filename //"touch_dev"; + //ts->input->name = ts->pdata->name; + ts->input->phys = ts->phys; + ts->input->dev.parent = dev; + ts->input->id.bustype = BUS_I2C; + + ts->input->id.vendor = ts->pdata->vendor; + ts->input->id.product = ts->pdata->product; + ts->input->id.version = ts->pdata->version; + + set_bit(EV_SYN, ts->input->evbit); + set_bit(EV_ABS, ts->input->evbit); + + /* Register Touch Key Event */ + if(ts->pdata->keycode) { + int key; + + set_bit(EV_KEY, ts->input->evbit); + + for(key = 0; key < ts->pdata->keycnt; key++) { + if(ts->pdata->keycode[key] <= 0) continue; + set_bit(ts->pdata->keycode[key] & KEY_MAX, ts->input->keybit); + } + } + + input_set_drvdata(ts->input, ts); + + if (sn310m_touch_pdata.lcd_exchg) { + input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); + } else { + input_set_abs_params(ts->input, ABS_MT_POSITION_X, ts->pdata->abs_min_x, ts->pdata->abs_max_x, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, ts->pdata->abs_min_y, ts->pdata->abs_max_y, 0, 0); + } + + if(ts->pdata->area_max) + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, ts->pdata->area_min, ts->pdata->area_max, 0, 0); + + if(ts->pdata->press_max) + input_set_abs_params(ts->input, ABS_MT_PRESSURE, ts->pdata->press_min, ts->pdata->press_max, 0, 0); + + if(ts->pdata->id_max) { + input_set_abs_params(ts->input, ABS_MT_TRACKING_ID, ts->pdata->id_min, ts->pdata->id_max, 0, 0); + input_mt_init_slots(ts->input, ts->pdata->max_fingers); + } + + + mutex_init(&ts->mutex); + if(ts->irq) { + switch(ts->pdata->irq_mode) { + default : + case IRQ_MODE_THREAD: + INIT_WORK(&ts->work, touch_work_q); + if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) + goto err_free_input_mem; + + if((rc = request_threaded_irq(ts->irq, NULL, ts->pdata->irq_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->pdata->name, ts))) { + dev_err(dev, "threaded irq %d request fail!\n", ts->irq); + goto err_free_input_mem; + } + break; + case IRQ_MODE_NORMAL: + INIT_WORK(&ts->work, touch_work_q); + if((ts->work_queue = create_singlethread_workqueue("work_queue")) == NULL) + goto err_free_input_mem; + + if((rc = request_irq(ts->irq, ts->pdata->irq_func, ts->pdata->irq_flags, ts->pdata->name, ts))) { + errlog("irq %d request fail!\n", ts->irq); + goto err_free_input_mem; + } + dbg("irq %d request ok!\n", ts->irq); + break; + case IRQ_MODE_POLLING: + errlog("Error IRQ_MODE POLLING!! but defined irq_gpio\n"); + break; + } /* end of switch */ + } + ts->disabled = true; + + if((rc = input_register_device(ts->input))) { + dev_err(dev, "(%s) input register fail!\n", ts->input->name); + goto err_free_input_mem; + } + + /* by limst, added to turn on the power and reset of Touch IC */ + touch_hw_reset(ts); + +#if defined(CONFIG_HAS_EARLYSUSPEND) + if(ts->pdata->suspend) ts->power.suspend = ts->pdata->suspend; + if(ts->pdata->resume) ts->power.resume = ts->pdata->resume; + + ts->power.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1; + + register_early_suspend(&ts->power); +#endif + + if(ts->pdata->probe) { + ts->pdata->probe(ts); + } + + touch_info_display(ts); + +#if defined(SN310M_NATIVE_INTERFACE) + if(P_SN310M_Dist_Probe(ts) < 0) { + errlog("P_SN310M_Dist_Probe(), fail\n"); + } +#endif + + return 0; + + free_irq(ts->irq, ts); + input_unregister_device(ts->input); + err_free_input_mem: + input_free_device(ts->input); + ts->input = NULL; + err_free_mem: + kfree(ts->finger); + ts->finger = NULL; + kfree(ts); + ts = NULL; + return rc; +} + +static int wmt_ts_remove(struct platform_device *pdev) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("wmt_ts_remove\n"); + + if(ts->irq) free_irq(ts->irq, ts); + + if(ts->pdata->reset_gpio) gpio_free(ts->pdata->reset_gpio); + + if(ts->pdata->irq_gpio) gpio_free(ts->pdata->irq_gpio); + + input_unregister_device(ts->input); + + dev_set_drvdata(dev, NULL); + + #if defined(SN310M_NATIVE_INTERFACE) + P_SN310M_Dist_Remove(); + #endif + + kfree(ts->finger); ts->finger = NULL; + kfree(ts); ts = NULL; + + return 0; +} + +static int wmt_ts_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("%s++\n", __func__); + + /* TSC enters deep sleep mode */ + dbg("[%s] touch reset goes low!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 0); + gpio_set_value(ts->pdata->reset_gpio, 0); + + + ts->pdata->disable(ts); + + return 0; +} +static int wmt_ts_resume(struct platform_device *pdev) +{ + struct i2c_client *client = l_client; + struct device *dev = &client->dev; + struct touch *ts = dev_get_drvdata(dev); + + dbg("%s++\n", __func__); + + /* TSC enters active mode */ + dbg("[%s] touch reset goes high!\n", __func__); + gpio_direction_output(ts->pdata->reset_gpio, 1); + gpio_set_value(ts->pdata->reset_gpio, 1); + + ts->pdata->enable(ts); + //touch_hw_reset(ts); + + return 0; +} + + +static struct platform_driver wmt_ts_plt_driver = { + .driver = { + .name = TS_DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = wmt_ts_probe, + .remove = wmt_ts_remove, + .suspend = wmt_ts_suspend, + .resume = wmt_ts_resume, +}; + + + +struct i2c_board_info ts_i2c_board_info = { + .type = WMT_TS_I2C_NAME, + .flags = 0x00, + .platform_data = NULL, + .archdata = NULL, + .irq = -1, +}; + +static int ts_i2c_register_device (void) +{ + struct i2c_board_info *ts_i2c_bi; + struct i2c_adapter *adapter = NULL; + + ts_i2c_board_info.addr =(unsigned short) 0x3c; + ts_i2c_bi = &ts_i2c_board_info; + adapter = i2c_get_adapter(1);/*in bus 1*/ + + if (NULL == adapter) { + errlog("can not get i2c adapter, client address error\n"); + return -1; + } + l_client = i2c_new_device(adapter, ts_i2c_bi); + if (l_client == NULL) { + errlog("allocate i2c client failed\n"); + return -1; + } + i2c_put_adapter(adapter); + return 0; +} + +static void ts_i2c_unregister_device(void) +{ + if (l_client != NULL) + { + i2c_unregister_device(l_client); + l_client = NULL; + } +} + +static struct tp_info l_tpinfo; +static int wmt_check_touch_env(void) +{ + int ret = 0; + int len = 127; + char retval[200] = {0}; + char *p=NULL; + char *s=NULL; + int Enable=0; + + // Get u-boot parameter + ret = wmt_getsyspara("wmt.io.touch", retval, &len); + if(ret){ + errlog("Read wmt.io.touch Failed.\n"); + return -EIO; + } + memset(&l_tpinfo,0,sizeof(l_tpinfo)); + + p = retval; + sscanf(p,"%d:", &Enable); + p = strchr(p,':'); + p++; + s = strchr(p,':'); + strncpy(l_tpinfo.name,p, (s-p)); + p = s+1; + //dbg("ts_name=%s\n", l_tpinfo.name); + + ret = sscanf(p,"%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", + &l_tpinfo.irq_gpio,&l_tpinfo.panelres_x,&l_tpinfo.panelres_y,&l_tpinfo.rst_gpio, + &(l_tpinfo.xaxis),&(l_tpinfo.xdir),&(l_tpinfo.ydir), + &(l_tpinfo.max_finger_num),&l_tpinfo.i2caddr,&l_tpinfo.low_Impendence_mode,&l_tpinfo.download_option); + + if (ret < 8){ + errlog("Wrong format ts u-boot param(%d)!\nwmt.io.touch=%s\n",ret,retval); + return -ENODEV; + } + + //check touch enable + if(Enable == 0){ + errlog("Touch Screen Is Disabled.\n"); + return -ENODEV; + } + if (strstr(l_tpinfo.name, sn310m_touch_pdata.name) == NULL){ + errlog("Can't find %s in the wmt.io.touch\n", sn310m_touch_pdata.name); + return -ENODEV; + } + + errlog("p.x = %d, p.y = %d, gpio=%d, resetgpio=%d,xaxis=%d,xdir=%d,ydri=%d,maxfingernum=%d,,i2c_addr=0x%X,low_Impendence_mode=%d,s_download_option=%d\n", + l_tpinfo.panelres_x, l_tpinfo.panelres_y, l_tpinfo.irq_gpio, l_tpinfo.rst_gpio, + l_tpinfo.xaxis,l_tpinfo.xdir,l_tpinfo.ydir, + l_tpinfo.max_finger_num,l_tpinfo.i2caddr,l_tpinfo.low_Impendence_mode,l_tpinfo.download_option); + + sn310m_touch_pdata.irq_gpio = l_tpinfo.irq_gpio; + sn310m_touch_pdata.reset_gpio = l_tpinfo.rst_gpio; + sn310m_touch_pdata.abs_max_x = l_tpinfo.panelres_x; + sn310m_touch_pdata.abs_max_y = l_tpinfo.panelres_y; + + memset(retval,0,sizeof(retval)); + ret = wmt_getsyspara("wmt.display.fb0", retval, &len); + if (!ret) { + int tmp[6]; + p = retval; + sscanf(p, "%d:[%d:%d:%d:%d:%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); + if (tmp[4] > tmp[5]) + sn310m_touch_pdata.lcd_exchg = 1; + } + + return 0; +} + + +static int __init sample_touch_init(void) +{ + int ret = 0; + + if(wmt_check_touch_env()) + return -ENODEV; + + + if (ts_i2c_register_device()<0){ + errlog("Error to run ts_i2c_register_device()!\n"); + return -1; + } + + ret = platform_device_register(&wmt_ts_plt_device); + if(ret){ + errlog("wmt ts plat device register failed!\n"); + return ret; + } + ret = platform_driver_register(&wmt_ts_plt_driver); + if(ret){ + errlog("can not register platform_driver_register\n"); + platform_device_unregister(&wmt_ts_plt_device); + return ret; + } + return 0; +} + +static void sample_touch_exit(void) +{ + platform_driver_unregister(&wmt_ts_plt_driver); + platform_device_unregister(&wmt_ts_plt_device); + ts_i2c_unregister_device(); + + return; +} + + +module_init(sample_touch_init); +module_exit(sample_touch_exit); + +#ifndef MODULE +__initcall(sample_touch_init); +#endif + + + +MODULE_AUTHOR("SEMISENS Co., Ltd."); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Touchscreen Driver for SN310M"); diff --git a/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h new file mode 100755 index 00000000..750112ea --- /dev/null +++ b/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h @@ -0,0 +1,54 @@ +/**************************************************************** + * + * touch.c : I2C Touchscreen driver + * + * Copyright (c) 2013 SEMISENS Co.,Ltd + * http://www.semisens.com + * + ****************************************************************/ +#ifndef _TOUCH_H_ +#define _TOUCH_H_ + +//---------------------------------------------- +// extern function define +//---------------------------------------------- +extern void touch_hw_reset(struct touch *ts); +extern int touch_info_display(struct touch *ts); +#if 0 /* depends on kernel version */ +extern int touch_probe(struct i2c_client *client); +extern int touch_remove(struct device *dev); +#else +extern int touch_probe(struct i2c_client *client, const struct i2c_device_id *client_id); +extern int touch_remove(struct i2c_client *client); +#endif + +struct tp_info +{ + char name[64]; + unsigned int xaxis; //0: x, 1: x swap with y + unsigned int xdir; // 1: positive,-1: revert + unsigned int ydir; // 1: positive,-1: revert + unsigned int max_finger_num; + unsigned int download_option; // 0: disable 1:force download 2:force cancel download + unsigned int low_Impendence_mode; // 0: High Impendence Mode 1: Low Impendence Mode + unsigned int irq_gpio; + unsigned int rst_gpio; + unsigned int panelres_x; + unsigned int panelres_y; + unsigned int i2caddr; + unsigned int lcd_exchg; +#if 0 + struct input_dev *inputdev; + struct work_struct int_work; + struct i2c_client *i2cclient; + struct workqueue_struct *wq; +#if SUPPORT_TS_KEY + int key_num; +#endif +#endif + +}; + + + +#endif /* _TOUCH_H_ */ |