summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/input/touchscreen/semisens
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/touchscreen/semisens')
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/Makefile33
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch-pdata.h201
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.c332
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/sn310m-touch.h97
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c1121
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.h54
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_ */