summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c')
-rwxr-xr-xANDROID_3.4.5/drivers/input/touchscreen/semisens/touch.c1121
1 files changed, 1121 insertions, 0 deletions
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");