summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorAli Ekici <aekici@nvidia.com>2012-01-10 15:58:28 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-01-24 10:58:58 -0800
commitbd4116d82f800957161272a89eaa4015f6b9c0f4 (patch)
treec8124a2f1c78223069fb42611a98f1258c017170 /drivers/input
parent42e6bff9dc477683df5e235eaf04d3c628ba1442 (diff)
input: touch: rm31080a: DirectTouch Raydium driver
Raydium is responsible from pushing this driver to kernel.org. This driver contains two distinct drivers, one communicates with Touch IC using SPI and pushes raw touch data received to a file system, another driver who is a misc driver receives processed touch data and initiates touch input_abs_report touch commands which can only be issued by a driver. Changed misc_deregister call from rm31080_spi_exit to rm31080_spi_remove Bug 832605 Reviewed-on: http://git-master/r/74432 Change-Id: I8f361130bfe3236cf88ab4348c3d578c84c63ba7 Reviewed-by: Dan Willemsen <dwillemsen@nvidia.com> Signed-off-by: Ali Ekici <aekici@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/76820 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/Kconfig13
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/rm31080a_ts.c1819
-rw-r--r--drivers/input/touchscreen/rm31080a_ts.h42
4 files changed, 1875 insertions, 0 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b438838b46a7..a4523838cacf 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -745,4 +745,17 @@ config TOUCHSCREEN_TPS6507X
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
+config TOUCHSCREEN_RM31080A
+ tristate "RAYDIUM_31080A based touchscreens"
+ depends on SPI_MASTER
+ help
+ Say Y here if you have a touchscreen interface using the
+ RAYDIUM_T31080A controller, and your board-specific initialization
+ code includes that in its table of SPI devices.
+
+ If unsure, say N (but it's safe to say "Y").
+
+ To compile this driver as a module, choose M here: the
+ module will be called RAYDIUM_31080A.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 023d75578e23..8a38afe36425 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_RM31080A) += rm31080a_ts.o
diff --git a/drivers/input/touchscreen/rm31080a_ts.c b/drivers/input/touchscreen/rm31080a_ts.c
new file mode 100644
index 000000000000..abe4752670e0
--- /dev/null
+++ b/drivers/input/touchscreen/rm31080a_ts.c
@@ -0,0 +1,1819 @@
+/*
+
+ * Raydium RM31080(T007) touchscreen (SPI bus) - Android version
+ *
+ * Copyright (C) 2011-2012 Raydium Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ * Version : 0.03
+ */
+
+//=============================================================================
+//INCLUDED FILES
+//=============================================================================
+#include <linux/input.h> // BUS_SPI
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/sched.h> // wake_up_process()
+#include <linux/kthread.h> // kthread_create()、kthread_run()
+#include <asm/uaccess.h> // copy_to_user(),
+#include <linux/miscdevice.h>
+#include <asm/siginfo.h> // siginfo
+#include <linux/rcupdate.h> // rcu_read_lock
+#include <linux/sched.h> // find_task_by_pid_type
+#include <linux/syscalls.h> // sys_clock_gettime()
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif
+
+
+
+#include "rm31080a_ts.h"
+
+//=============================================================================
+//DEFINITIONS
+//=============================================================================
+#define ENABLE_WORK_QUEUE
+#define ENABLE_REPORT_TO_UART
+#define ENABLE_RM31080_DEEP_SLEEP
+#define ENABLE_AUTO_SCAN
+//#define ENABLE_AUTO_FREQ
+//#define ENABLE_TS_THREAD
+//#define ENABLE_KERNEL_CALC //calculate touch point by kernel layer
+//#define ENABLE_TIMER_RELEASE_TOUCH
+//#define ENABLE_SPEED_TEST_FUNCTION
+//#define ENABLE_TIMER_DEBUG
+//#define ENABLE_TEST_AVERAGE
+
+#define MAX_SPI_FREQ_HZ 50000000
+#define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
+
+#ifdef ENABLE_RAW_DATA_QUEUE
+ #define QUEUE_COUNT 128
+ #define RAW_DATA_LENGTH 2048
+
+ #define RM_SCAN_MODE_MANUAL 0x00
+ #define RM_SCAN_MODE_PREPARE_AUTO 0x01
+ #define RM_SCAN_MODE_AUTO_SCAN 0x02
+
+
+ #define RM_NEED_NONE 0x00
+ #define RM_NEED_TO_SEND_SCAN 0x01
+ #define RM_NEED_TO_READ_RAW_DATA 0x02
+ #define RM_NEED_TO_SEND_SIGNAL 0x03
+#endif
+
+
+#ifdef ENABLE_SPEED_TEST_FUNCTION
+ //#define TEST_SPI_READ_SPEED
+ //#define TEST_INT_TO_CLEAR_INT
+#endif
+
+#ifdef ENABLE_WORK_QUEUE
+#include <linux/workqueue.h>
+#endif
+
+#ifdef ENABLE_KERNEL_CALC
+#include "raydium_ts_main.h"
+#include "raydium_ts_spi_if.h"
+#include "raydium_ts_t007.h"
+#endif
+
+//=============================================================================
+//STRUCTURE DECLARATION
+//=============================================================================
+struct rm31080a_ts_para {
+ unsigned long ulHalPID;
+ bool bInitFinish;
+ bool bCalcFinish;
+ bool bEnableScriber;
+ bool bEnableAutoScan;
+ bool bIsSuspended;
+ struct mutex mutex;
+ #ifdef ENABLE_WORK_QUEUE
+ struct workqueue_struct *rm_workqueue;
+ struct work_struct rm_work;
+ bool bIsWorkQueueExecuting;
+ #endif
+ #ifdef ENABLE_TIMER_DEBUG
+ u32 u32WaitHalCount;
+ #endif
+ #ifdef ENABLE_RAW_DATA_QUEUE
+ u8 u8ScanModeState;
+ #endif
+};
+
+struct rm31080_ts {
+ const struct rm31080_bus_ops *bops;
+ struct device *dev;
+ struct input_dev *input;
+ #ifdef ENABLE_TS_THREAD
+ struct task_struct *ts_task;
+ #endif
+ #ifdef ENABLE_TIMER_RELEASE_TOUCH
+ struct timer_list timer;
+ #endif
+ #ifdef ENABLE_TIMER_DEBUG
+ struct timer_list timer_debug;
+ #endif
+ unsigned int irq;
+ bool disabled;
+ bool suspended;
+ char phys[32];
+ struct mutex access_mutex;
+ #if defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+ #endif
+};
+
+struct rm31080_bus_ops {
+ u16 bustype;
+ int (*read)(struct device *dev, u8 reg);
+ int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf);
+ int (*write)(struct device *dev, u8 reg, u16 val);
+};
+
+#ifdef ENABLE_RAW_DATA_QUEUE
+struct rm31080_queue_info {
+ u8 (*pQueue)[RAW_DATA_LENGTH];
+ u16 u16Front;
+ u16 u16Rear;
+};
+#endif
+
+//=============================================================================
+//GLOBAL VARIABLES DECLARATION
+//=============================================================================
+struct input_dev *g_input_dev;
+struct spi_device *g_spi;
+struct rm31080a_ts_para g_stTs;
+
+#ifdef ENABLE_RAW_DATA_QUEUE
+struct rm31080_queue_info g_stQ;
+#endif
+//=============================================================================
+//FUNCTION DECLARATION
+//=============================================================================
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+static void rm31080_early_suspend(struct early_suspend *es);
+static void rm31080_early_resume(struct early_suspend *es);
+#endif
+//=============================================================================
+// Description:
+// Debug function: test speed.
+// Input:
+// N/A
+// Output:
+// 1:succeed
+// 0:failed
+//=============================================================================
+#ifdef ENABLE_SPEED_TEST_FUNCTION
+void my_calc_time(int iStart)
+{
+ static volatile unsigned int u32Max = UINT_MAX;
+ #if 0
+ char tbuf[50];
+ unsigned long long t;
+ unsigned long nanosec_rem;
+ t = cpu_clock(u32Max);
+ nanosec_rem = do_div(t, 1000000000);
+ sprintf(tbuf, "<%5lu.%06lu> ",
+ (unsigned long) t,
+ nanosec_rem / 1000);
+ tbuf[14]=0;
+ printk("%s\n",tbuf);
+ #endif
+
+ static long iTimebuffer[1000];
+ static unsigned long long t1,t2;
+ unsigned long nanosec_rem;
+ static int iIndex=0;
+
+ if (iStart)
+ {
+ t1 = cpu_clock(u32Max);
+ return;
+ }
+ else
+ t2 = cpu_clock(u32Max);
+
+ t2 = t2 - t1;
+
+ nanosec_rem = do_div(t2, 1000000000);
+
+ if (t2) //more than 1 Second
+ {
+ iTimebuffer[iIndex] = 999999;
+ }
+ else
+ {
+ iTimebuffer[iIndex] = nanosec_rem/1000; //micro second
+ }
+
+ iIndex ++;
+ if (iIndex==1000)
+ {
+ for(iIndex = 0;iIndex < 1000;iIndex++)
+ {
+ printk(" %04d,%06d\n",iIndex,(u32)iTimebuffer[iIndex]);
+ }
+ iIndex =0;
+ }
+
+
+}
+#endif //ENABLE_SPEED_TEST_FUNCTION
+//=============================================================================
+// Description:
+// RM31080 spi interface.
+// Input:
+// N/A
+// Output:
+// 1:succeed
+// 0:failed
+//=============================================================================
+int rm31080_spi_read(u8 u8addr, u8 *rxbuf, size_t len)
+{
+ static DEFINE_MUTEX(lock);
+
+ int status;
+ struct spi_message message;
+ struct spi_transfer x[2];
+
+ if (!mutex_trylock(&lock))
+ {
+ printk("Raydium TS: rm31080_spi_read trylock fail\n");
+ return -EINVAL;
+ }
+
+ spi_message_init(&message);
+ memset(x, 0, sizeof x);
+
+ u8addr |= 0x80;
+ x[0].len = 1;
+ x[0].tx_buf = &u8addr;
+ spi_message_add_tail(&x[0], &message);
+
+ x[1].len = len;
+ x[1].rx_buf = rxbuf;
+ spi_message_add_tail(&x[1], &message);
+
+ status = spi_sync(g_spi, &message);
+
+ mutex_unlock(&lock);
+ return status; // 0 = succeed
+}
+
+int rm31080_spi_write(u8 *txbuf, size_t len)
+{
+ return spi_write(g_spi, txbuf, len);
+ #if 0
+ struct spi_transfer t = {
+ .tx_buf = txbuf,
+ .len = len,
+ };
+ struct spi_message m;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ return spi_sync(spi, &m);
+ #endif
+}
+
+
+
+#if 0
+static int rm31080_spi_burst_read(u8 u8Addr,u8 u8Value)
+{
+ return 1;
+}
+
+static int rm31080_spi_burst_write(u8 u8Addr,u8 u8Value)
+{
+ return 1;
+}
+#endif
+static int rm31080_spi_byte_read(u8 u8Addr,u8 *pu8Value)
+{
+ int iErrorCode;
+ iErrorCode = rm31080_spi_read(u8Addr,pu8Value,1);
+ if (iErrorCode != 0)
+ {
+ return 0;//fail
+ }
+ return 1;
+}
+
+
+static int rm31080_spi_byte_write(u8 u8Addr,u8 u8Value)
+{
+ int iErrorCode;
+ u8 buf[2];
+ buf[0] = u8Addr;
+ buf[1] = u8Value;
+
+ iErrorCode = rm31080_spi_write(buf, 2);
+
+ if (iErrorCode != 0)
+ {
+ printk("rm31080_spi_write_byte failed:Reg=%x",u8Addr);
+ return 0;//fail
+ }
+ return 1;
+}
+//=============================================================================
+// Description:
+// RM31080 control functions.
+// Input:
+// N/A
+// Output:
+// 1:succeed
+// 0:failed
+//=============================================================================
+#ifdef ENABLE_RAW_DATA_QUEUE
+
+#define RM31080_REG_01 0x01
+#define RM31080_REG_02 0x02
+#define RM31080_REG_09 0x09
+#define RM31080_REG_0E 0x0E
+#define RM31080_REG_10 0x10
+#define RM31080_REG_11 0x11
+#define RM31080_REG_1F 0x1F
+#define RM31080_REG_40 0x40
+#define RM31080_REG_41 0x41
+#define RM31080_REG_80 0x80
+#define RM31080_REG_F2 0xF2
+
+#define RM31080_RAW_DATA_LENGTH 1530
+static int rm31080_ctrl_clear_int(void)
+{
+ u8 u8Flag;
+ return rm31080_spi_byte_read(RM31080_REG_F2,&u8Flag);
+}
+
+#ifdef ENABLE_AUTO_SCAN
+#if 0
+void rm31080_ctrl_auto_mode_init(void)
+{
+ WriteSensor(REG_YACTIVEH, 0x04);
+ WriteSensor(REG_YACTIVEL, 0x38);
+ WriteSensor(0x0F, 0x88);
+ //please check [0x0f]=0x88 ,if auto scan can't work.
+}
+void rm31080_ctrl_analog_init(void)
+{
+ WriteSensor(0x7F, 0x01); //Bank1
+ WriteSensor(0x48, 0x00);
+ WriteSensor(0x49, 0x80);
+ WriteSensor(0x2F, 0x80);
+ WriteSensor(0x7F, 0x00); //Bank0
+ WriteSensor(0x6B, 0xF1);
+}
+#endif //if 0
+
+void rm31080_ctrl_enter_auto_mode(void)
+{
+ #if 0
+ //1.Disable digit_filter
+ //rm31080_spi_byte_write(RM31080_REG_40, 0x0F );
+ //rm31080_spi_byte_write(RM31080_REG_41, 0xFF );
+ rm31080_spi_byte_write(RM31080_REG_1F, 0x00 | 0x05 );//REG_DIGITAL_FILTER
+ rm31080_spi_byte_write(RM31080_REG_0E, 0x38 | 0x02 );//REG_SENSING
+ rm31080_spi_byte_write(RM31080_REG_10, 0x00 ); // REG_SEQ
+
+ //2.Enable Analog_filter
+ rm31080_spi_byte_write(0x7F, 0x01);//bank 1
+ rm31080_spi_byte_write(0x09, 0x19);
+ rm31080_spi_byte_write(0x43, 0xFF);
+ rm31080_spi_byte_write(0x7F, 0x00);//bank 0
+ #endif
+
+ //3.Enable auto scan
+ rm31080_spi_byte_write(RM31080_REG_09, 0x10 | 0x40);
+}
+
+void rm31080_ctrl_leave_auto_mode(void)
+{
+ //1.Disable auto scan
+ rm31080_spi_byte_write(RM31080_REG_09, 0x00);
+
+ #if 0
+ //2.Disable Analog_filter
+ rm31080_spi_byte_write(0x7F, 0x01);//bank 1
+ rm31080_spi_byte_write(0x09, 0xD9);
+ rm31080_spi_byte_write(0x43, 0x44);
+ rm31080_spi_byte_write(0x7F, 0x00);//bank 0
+
+ //3.Enable Digit_filter
+ rm31080_spi_byte_write(RM31080_REG_1F, 0x00 | 0x07 ); //REG_DIGITAL_FILTER
+ rm31080_spi_byte_write(RM31080_REG_0E, 0x38 | 0x04 ); //REG_SENSING
+ rm31080_spi_byte_write(RM31080_REG_10, 0x10 ); //REG_SEQ
+ #endif
+
+}
+#endif //ENABLE_AUTO_SCAN
+
+#ifdef ENABLE_RM31080_DEEP_SLEEP
+static int rm31080_ctrl_suspend(void)
+{
+ //Flow designed by Roger 20110930
+ //rm31080_ts_send_signal(g_stTs.ulHalPID,RM_SIGNAL_SUSPEND);
+ g_stTs.bInitFinish = 0;
+ msleep(8);
+ rm31080_ctrl_clear_int();
+ //disable auto scan
+ rm31080_spi_byte_write(RM31080_REG_09,0x00);
+ #if 1 //by valentine
+ rm31080_spi_byte_write(RM31080_REG_10,0x14);
+ rm31080_spi_byte_write(RM31080_REG_11,0x17);
+ msleep(15);
+ #endif
+ rm31080_spi_byte_write(RM31080_REG_11,0x06);
+ return 1;
+}
+#endif
+
+static int rm31080_ctrl_scan_start(void)
+{
+ return rm31080_spi_byte_write(RM31080_REG_11,0x17);
+}
+
+static u32 rm31080_ctrl_configure(void)
+{
+ u32 u32Flag;
+
+ switch (g_stTs.u8ScanModeState)
+ {
+ case RM_SCAN_MODE_MANUAL:
+ u32Flag = RM_NEED_TO_SEND_SCAN | RM_NEED_TO_READ_RAW_DATA | RM_NEED_TO_SEND_SIGNAL;
+ break;
+ #ifdef ENABLE_AUTO_SCAN
+ case RM_SCAN_MODE_PREPARE_AUTO:
+ rm31080_ctrl_enter_auto_mode();
+ g_stTs.u8ScanModeState = RM_SCAN_MODE_AUTO_SCAN;
+ u32Flag = RM_NEED_NONE;
+ break;
+ case RM_SCAN_MODE_AUTO_SCAN:
+ rm31080_ctrl_leave_auto_mode();
+ rm31080_ctrl_scan_start(); //20111213 : fixed bug:wake up from AutoScan needs scan_start() twice
+ g_stTs.u8ScanModeState = RM_SCAN_MODE_MANUAL;
+ u32Flag = RM_NEED_TO_SEND_SCAN | RM_NEED_TO_READ_RAW_DATA | RM_NEED_TO_SEND_SIGNAL;
+ break;
+ #endif //ENABLE_AUTO_SCAN
+ default:
+ u32Flag = RM_NEED_NONE;
+ break;
+ }
+
+ return u32Flag;
+}
+
+static void rm31080_enter_manual_mode(void)
+{
+ flush_workqueue(g_stTs.rm_workqueue);
+
+ if (g_stTs.u8ScanModeState == RM_SCAN_MODE_MANUAL)
+ return;
+
+ if(g_stTs.u8ScanModeState == RM_SCAN_MODE_PREPARE_AUTO)
+ {
+ g_stTs.u8ScanModeState = RM_SCAN_MODE_MANUAL;
+ return;
+ }
+
+ if(g_stTs.u8ScanModeState == RM_SCAN_MODE_AUTO_SCAN)
+ {
+ rm31080_ctrl_leave_auto_mode();
+ g_stTs.u8ScanModeState = RM_SCAN_MODE_MANUAL;
+ msleep(10);
+ }
+
+}
+
+static int rm31080_ctrl_read_raw_data(u8 *p)
+{
+ int iRet;
+ iRet = rm31080_spi_byte_write(RM31080_REG_01,0x10);
+ if (iRet)
+ iRet = rm31080_spi_byte_write(RM31080_REG_02,0x00);
+
+ if (iRet)
+ {
+ iRet = rm31080_spi_read(RM31080_REG_80,p,RM31080_RAW_DATA_LENGTH); //return 0 =succeed
+ iRet = !iRet;
+ }
+
+ if(!iRet)
+ {
+ printk("rm31080 read raw data failed\n");
+ }
+
+ return iRet;
+}
+#endif //ENABLE_RAW_DATA_QUEUE
+//=============================================================================
+// Description:
+// Queuing functions.
+// Input:
+// N/A
+// Output:
+// 0:succeed
+// others:error code
+//=============================================================================
+#ifdef ENABLE_RAW_DATA_QUEUE
+
+static void rm31080_queue_reset(void)
+{
+ g_stQ.u16Rear = 0;
+ g_stQ.u16Front = 0;
+}
+
+static int rm31080_queue_init(void)
+{
+ rm31080_queue_reset();
+ g_stQ.pQueue = kmalloc(QUEUE_COUNT * RAW_DATA_LENGTH, GFP_KERNEL);
+ if (g_stQ.pQueue == NULL)
+ {
+ printk("rm31080_queue_init failed\n");
+ return -ENOMEM;
+ }
+ //printk("Queue Addr:%x\n",(unsigned int)(g_stQ.pQueue));
+ return 0;
+}
+
+static void rm31080_queue_free(void)
+{
+ if (!g_stQ.pQueue)
+ return;
+ kfree(g_stQ.pQueue);
+ g_stQ.pQueue = NULL;
+}
+//=============================================================================
+// Description:
+// About full/empty buffer distinction,
+// There are a number of solutions like:
+// 1.Always keep one slot open.
+// 2.Use a fill count to distinguish the two cases.
+// 3.Use read and write counts to get the fill count from.
+// 4.Use absolute indices.
+// we chose "keep one slot open" to make it simple and robust
+// and also avoid race condition.
+// Input:
+// N/A
+// Output:
+// 1:empty
+// 0:not empty
+//=============================================================================
+static int rm31080_queue_is_empty(void)
+{
+ if (g_stQ.u16Rear == g_stQ.u16Front)
+ return 1;
+ return 0;
+}
+//=============================================================================
+// Description:
+// check queue full.
+// Input:
+// N/A
+// Output:
+// 1:full
+// 0:not full
+//=============================================================================
+static int rm31080_queue_is_full(void)
+{
+ if (g_stQ.u16Rear + 1 == g_stQ.u16Front)
+ return 1;
+
+ if ((g_stQ.u16Rear == (QUEUE_COUNT - 1)) &&
+ (g_stQ.u16Front == 0))
+ return 1;
+
+ return 0;
+}
+#if 0 //don't delete, for debug
+static int rm31080_queue_get_current_count(void)
+{
+ if (g_stQ.u16Rear >= g_stQ.u16Front)
+ return g_stQ.u16Rear - g_stQ.u16Front;
+
+ return (QUEUE_COUNT - g_stQ.u16Front) + g_stQ.u16Rear;
+}
+#endif
+static void *rm31080_enqueue_start(void)
+{
+ if (!g_stQ.pQueue) //error handling for no memory
+ return NULL;
+
+ if (!rm31080_queue_is_full())
+ return &g_stQ.pQueue[g_stQ.u16Rear];
+
+ printk("rm31080 Queue full with Queue Count:%d\n",QUEUE_COUNT);
+ return NULL;
+}
+static void rm31080_enqueue_finish(void)
+{
+ if (g_stQ.u16Rear == (QUEUE_COUNT - 1)) g_stQ.u16Rear = 0;
+ else g_stQ.u16Rear ++;
+}
+static void *rm31080_dequeue_start(void)
+{
+ if (!rm31080_queue_is_empty())
+ return &g_stQ.pQueue[g_stQ.u16Front];
+
+ return NULL;
+}
+static void rm31080_dequeue_finish(void)
+{
+ if (g_stQ.u16Front == (QUEUE_COUNT - 1)) g_stQ.u16Front = 0;
+ else g_stQ.u16Front ++;
+}
+
+static long rm31080_queue_read_raw_data(u8 *p,u32 u32Len)
+{
+ u8 *pQueue;
+ u32 u32Ret;
+ pQueue = rm31080_dequeue_start();
+ if (!pQueue)
+ return 0;
+
+
+ u32Ret = copy_to_user(p, pQueue, u32Len);
+ if (u32Ret != 0)
+ return 0;
+
+ rm31080_dequeue_finish();
+ return 1;
+
+}
+#endif //ENABLE_RAW_DATA_QUEUE
+
+#ifdef ENABLE_AUTO_FREQ
+void raydium_auto_freq()
+{
+ g_stTs.bInitFinish = 0;
+ msleep(10);
+ rm31080_ctrl_clear_int();
+
+ //roger_auto_freq_detection();
+
+ g_stTs.bInitFinish = 1;
+ rm31080_ctrl_scan_start();
+
+}
+#endif //ENABLE_TEST_AUTO_FREQ
+//=============================================================================
+#ifdef ENABLE_AUTO_SCAN
+void raydium_change_scan_mode(u8 u8TouchCount)
+{
+ static u32 u32NoTouchCount = 0;
+ if (u8TouchCount)
+ {
+ u32NoTouchCount = 0;
+ return;
+ }
+ if (u32NoTouchCount < 100)
+ {
+ u32NoTouchCount++;
+ }
+ else if (g_stTs.u8ScanModeState == RM_SCAN_MODE_MANUAL)
+ {
+ #ifdef ENABLE_AUTO_FREQ
+ raydium_auto_freq();
+ #else
+ //printk("===1.perpare enter to AutoScan\n");
+ if (g_stTs.bEnableAutoScan)
+ g_stTs.u8ScanModeState = RM_SCAN_MODE_PREPARE_AUTO;
+ #endif
+ u32NoTouchCount = 0;
+ }
+}
+#endif //ENABLE_AUTO_SCAN
+//=============================================================================
+//report touch data for scriber
+//
+//=============================================================================
+#ifdef ENABLE_REPORT_TO_UART
+void raydium_report_to_uart_printf(unsigned char *ucData,unsigned char ucCount)
+{
+ unsigned char i;
+ for (i=0;i<ucCount;i++)
+ {
+ printk("%02X",ucData[i]);
+ }
+ printk("\n");
+}
+void raydium_report_to_uart(void *p)
+{
+ unsigned char ucData[1+1+(4*12)+1];//1=Tag,1=Touch count,4=(xH xL ,yH yL) ,12=max point,1=Check sum
+ rm_touch_event *spTP;
+ unsigned short usX,usY;
+ int i,j;
+
+ if (g_stTs.bEnableScriber==0)
+ return;
+
+ spTP = (rm_touch_event *)p;
+
+ ucData[0] = 0x8E;
+ ucData[1] = spTP->ucTouchCount;
+ j=2;
+ for (i=0;i<spTP->ucTouchCount;i++)
+ {
+ usX = spTP->usX[i] + 1; //1~1536
+ usY = spTP->usY[i] + 1; //1~960
+ ucData[j++] = ((usX>>8) & 0xFF) | ( spTP->ucID[i] << 3 );//add id
+ ucData[j++] = ((usX ) & 0xFF);
+ ucData[j++] = ((usY>>8) & 0xFF);
+ ucData[j++] = ((usY ) & 0xFF);
+ }
+
+ //check sum
+ ucData[j] = 0;
+ for (i=0;i<j;i++)
+ {
+ ucData[j] += ucData[i];
+ }
+ ucData[j] = 0x100 - ucData[j];
+ j++;
+
+ //print
+ raydium_report_to_uart_printf(ucData,j);
+ if (spTP->ucTouchCount==0) //send more , to avoid losing
+ {
+ raydium_report_to_uart_printf(ucData,j);
+ raydium_report_to_uart_printf(ucData,j);
+ }
+}
+#endif
+//=============================================================================
+void raydium_report_pointer(void *p)
+{
+ static unsigned char ucLastTouchCount = 0;
+ int i;
+ int iCount;
+ rm_touch_event *spTP;
+ spTP = (rm_touch_event *)p;
+
+ iCount = max(ucLastTouchCount,spTP->ucTouchCount);
+ if (iCount)
+ {
+ for (i=0;i<iCount;i++)
+ {
+ //if (i==5)break; //due to the "pointer location" can't support great than 5 points
+ if (i==10)break; //due to the "touch test" can't support great than 10 points
+
+ if (i<spTP->ucTouchCount)
+ {
+ input_report_abs(g_input_dev, ABS_MT_TRACKING_ID,spTP->ucID[i]);
+ //input_report_abs(g_input_dev, ABS_MT_TOUCH_MAJOR,10);
+ input_report_abs(g_input_dev, ABS_MT_TOUCH_MAJOR,100);
+ if (spTP->usX[i] >= (RM_INPUT_RESOLUTION_X-1))
+ input_report_abs(g_input_dev, ABS_MT_POSITION_X,(RM_INPUT_RESOLUTION_X-1)-1);//fixed bug: OS scale fail
+ else
+ input_report_abs(g_input_dev, ABS_MT_POSITION_X,spTP->usX[i]);
+
+ if (spTP->usY[i] >= (RM_INPUT_RESOLUTION_Y-1))
+ input_report_abs(g_input_dev, ABS_MT_POSITION_Y,(RM_INPUT_RESOLUTION_Y-1)-1);//fixed bug: OS scale fail
+ else
+ input_report_abs(g_input_dev, ABS_MT_POSITION_Y,spTP->usY[i]);
+ }
+ input_mt_sync(g_input_dev);
+ }
+ ucLastTouchCount = spTP->ucTouchCount;
+ input_report_key(g_input_dev, BTN_TOUCH, spTP->ucTouchCount > 0);
+ input_sync(g_input_dev);
+ #ifdef ENABLE_REPORT_TO_UART
+ raydium_report_to_uart(p);
+ #endif
+
+
+ }
+
+ #if 0
+ if (spTP->ucTouchCount) {
+ for(i=0;i<spTP->ucTouchCount;i++)
+ {
+ printk("Touch:%d:%04d,%04d:ID:%d\n",spTP->ucTouchCount,spTP->usX[i],spTP->usY[i],spTP->ucID[i]);
+ }
+ }
+ else
+ {
+ //printk("x");
+ }
+ #endif
+
+ #ifdef ENABLE_AUTO_SCAN
+ raydium_change_scan_mode(spTP->ucTouchCount);
+ #endif
+}
+
+
+//=============================================================================
+// release touch event
+//
+//=============================================================================
+#ifdef ENABLE_TIMER_RELEASE_TOUCH
+static void rm31080_touch_release(void)
+{
+ rm_touch_event stTP;
+ stTP.ucTouchCount = 0;
+ raydium_report_pointer((void*)&stTP);
+}
+
+static void rm31080_timer(unsigned long handle)
+{
+ //struct rm31080_ts *ts = (void *)handle;
+ //mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+ //mod_timer(&ts->timer, jiffies + HZ);
+ rm31080_touch_release();
+}
+#endif //ENABLE_TIMER_RELEASE_TOUCH
+
+#ifdef ENABLE_TIMER_DEBUG
+static void rm31080_debug_timer(unsigned long handle)
+{
+ struct rm31080_ts *ts = (void *)handle;
+ mod_timer(&ts->timer_debug,jiffies + msecs_to_jiffies(10*1000));
+ printk("Wait HAL Count in 10 second:%d\n",g_stTs.u32WaitHalCount);
+ g_stTs.u32WaitHalCount = 0;
+}
+#endif //ENABLE_TIMER_DEBUG
+//=============================================================================
+
+
+//=============================================================================
+int rm31080_ts_send_signal(int pid,int iInfo)
+{
+ struct siginfo info;
+ struct task_struct *t;
+ int ret;
+
+ /* send the signal */
+ memset(&info, 0, sizeof(struct siginfo));
+ info.si_signo = RM_TS_SIGNAL;
+ info.si_code = SI_QUEUE; // this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space,
+ // and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data
+ // is not delivered to the user space signal handler function.
+ info.si_int = iInfo; //real time signals may have 32 bits of data.
+
+ rcu_read_lock();
+ t = find_task_by_vpid(pid);
+ if(t == NULL){
+ printk("no such pid\n");
+ rcu_read_unlock();
+ return -ENODEV;
+ }
+ rcu_read_unlock();
+ ret = send_sig_info(RM_TS_SIGNAL, &info, t); //send the signal
+ if (ret < 0) {
+ printk("error sending signal\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+
+//=============================================================================
+static void __rm31080_enable(struct rm31080_ts *ts)
+{
+ enable_irq(ts->irq);
+}
+
+static void __rm31080_disable(struct rm31080_ts *ts)
+{
+ disable_irq(ts->irq);
+
+ //if (del_timer_sync(&ts->timer))
+ // rm31080_touch_release();
+}
+
+static void vtest_toggle(struct rm31080_ts *ts, bool disable)
+{
+ mutex_lock(&ts->input->mutex);
+
+ if (!ts->suspended && ts->input->users != 0)
+ {
+
+ if (disable) {
+ if (ts->disabled)
+ __rm31080_enable(ts);
+ } else {
+ if (!ts->disabled)
+ __rm31080_disable(ts);
+ }
+ }
+
+ ts->disabled = disable;
+
+ mutex_unlock(&ts->input->mutex);
+}
+
+static ssize_t vtest_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rm31080_ts *ts = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", ts->disabled);
+}
+
+static ssize_t vtest_disable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rm31080_ts *ts = dev_get_drvdata(dev);
+ unsigned long val;
+ int error;
+
+ error = strict_strtoul(buf, 10, &val);
+ if (error)
+ return error;
+
+ vtest_toggle(ts, val);
+
+ return count;
+}
+static DEVICE_ATTR(disable, 0664, vtest_disable_show, vtest_disable_store);
+static struct attribute *vtest_attributes[] = {
+ &dev_attr_disable.attr,
+ NULL
+};
+
+static const struct attribute_group vtest_attr_group = {
+ .attrs = vtest_attributes,
+};
+
+
+
+static int rm31080_input_open(struct input_dev *input)
+{
+ struct rm31080_ts *ts = input_get_drvdata(input);
+
+ /* protected by input->mutex */
+ if (!ts->disabled && !ts->suspended)
+ __rm31080_enable(ts);
+
+ return 0;
+}
+
+static void rm31080_input_close(struct input_dev* input)
+{
+ struct rm31080_ts *ts = input_get_drvdata(input);
+
+ /* protected by input->mutex */
+ if (!ts->disabled && !ts->suspended)
+ __rm31080_disable(ts);
+}
+
+
+//=============================================================================
+#ifdef ENABLE_TS_THREAD
+static int rm31080_ts_thread(void *handle)
+{
+ struct rm31080_ts *ts = (void *)handle;
+ struct task_struct *tsk = current;
+ struct sched_param param = { .sched_priority = 1 }; //sched_get_priority_min(),sched_get_priority_max()
+
+ sched_setscheduler(tsk, SCHED_FIFO, &param);
+
+ //set_freezable();
+ while (!kthread_should_stop())
+ {
+ //if (ucb->irq_pending) {
+ // ucb->irq_pending = 0;
+ // handle_pending_irq(ucb);
+ //}
+
+ #ifdef ENABLE_KERNEL_CALC
+ ts_main_calc();
+ #endif
+
+ msleep(10000);
+
+ #if 0
+ if (ts_pen_up(ucb->ac97)) {
+ ts_irq_enable(ucb->ac97);
+
+ /*
+ * If we spat out a valid sample set last time,
+ * spit out a "pen off" sample here.
+ */
+ if (valid) {
+ ts_event_release(ucb->ts_idev);
+ valid = 0;
+ }
+
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ } else {
+ valid = 1;
+ ts_evt_add(ucb->ts_idev, p, x, y);
+ timeout = msecs_to_jiffies(10);
+ }
+
+ wait_event_freezable_timeout(ucb->ts_wait,
+ ucb->irq_pending || ucb->ts_restart ||
+ kthread_should_stop(), timeout);
+ #endif
+ }
+
+ /* Send the "pen off" if we are stopping with the pen still active */
+ //if (valid)
+ // ts_event_release(ucb->ts_idev);
+
+ ts->ts_task = NULL;
+ return 0;
+}
+#endif //ENABLE_TS_THREAD
+
+#ifdef ENABLE_TEST_AVERAGE //only for test
+#define _AVERAGE_COUNT 2
+s8 g_bAverageBuf[_AVERAGE_COUNT][2048];
+int test_soft_average(s8 *pSource)
+{
+ static u8 u8AverageIndex = 0;
+ static u8 u8StartAverage = 0;
+ u16 i,j;
+ s16 s16Sum;
+
+ for (i = 0; i < RM31080_RAW_DATA_LENGTH; i++) //RM31080_RAW_DATA_LENGTH =1530
+ g_bAverageBuf[u8AverageIndex][i] = pSource[i] - 0x80;
+ u8AverageIndex++;
+
+ if (u8AverageIndex == _AVERAGE_COUNT)
+ {
+ u8StartAverage = 1;
+ u8AverageIndex = 0;
+ }
+ #if 1
+ else u8StartAverage = 0;
+ #endif
+
+ if (u8StartAverage)
+ {
+ for (i = 0; i < RM31080_RAW_DATA_LENGTH; i++)
+ {
+ s16Sum = 0;
+ for (j = 0;j < _AVERAGE_COUNT; j++)
+ s16Sum += g_bAverageBuf[j][i];
+ pSource[i] = (s16Sum /_AVERAGE_COUNT) + 0x80;
+ }
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+
+#ifdef ENABLE_WORK_QUEUE
+//1.2
+static void rm_work_handler(struct work_struct *work)
+{
+ void *pKernelBuffer;
+ u32 u32Flag;
+ int iRet;
+
+
+ #if 1
+ if(g_stTs.bIsSuspended)
+ {
+ printk("rm_work_handler stops after suspend\n");
+ return;
+ }
+ #else
+ while(g_stTs.bIsSuspended)
+ {
+ msleep(1);
+ }
+ #endif
+ g_stTs.bIsWorkQueueExecuting = 1;
+
+
+ iRet = rm31080_ctrl_clear_int();
+
+
+ #ifdef TEST_INT_TO_CLEAR_INT
+ my_calc_time(0);
+ #endif
+
+ #ifdef ENABLE_TIMER_DEBUG
+ u32 u32CurrentQueueCount = rm31080_queue_get_current_count();
+ if (u32CurrentQueueCount>g_stTs.u32WaitHalCount)
+ g_stTs.u32WaitHalCount = u32CurrentQueueCount;
+ #endif
+
+
+ u32Flag = rm31080_ctrl_configure();
+
+
+
+ if(u32Flag | RM_NEED_TO_SEND_SCAN)
+ {
+ rm31080_ctrl_scan_start();
+ }
+
+ if(u32Flag | RM_NEED_TO_READ_RAW_DATA)
+ {
+ pKernelBuffer = rm31080_enqueue_start();
+ if (pKernelBuffer)
+ {
+ iRet = rm31080_ctrl_read_raw_data((u8 *)pKernelBuffer);
+ #ifdef ENABLE_TEST_AVERAGE
+ if (iRet)
+ {
+ iRet = test_soft_average((s8 *)pKernelBuffer);
+ }
+ #endif
+ if (iRet)
+ {
+ rm31080_enqueue_finish();
+ }
+ }
+ }
+
+ if(u32Flag | RM_NEED_TO_SEND_SIGNAL)
+ {
+ if(g_stTs.bCalcFinish)
+ {
+ g_stTs.bCalcFinish = 0;
+ rm31080_ts_send_signal(g_stTs.ulHalPID,RM_SIGNAL_INTR);
+ }
+ }
+ g_stTs.bIsWorkQueueExecuting = 0;
+}
+#endif
+
+static irqreturn_t rm31080_irq(int irq, void *handle)
+{
+
+ //struct rm31080_ts *ts = handle;
+ if (!g_stTs.bInitFinish)
+ {
+ //printk("Raydium : spi irq - Ignored when Init.\n");
+ return IRQ_HANDLED;
+ }
+
+ #ifdef TEST_INT_TO_CLEAR_INT
+ my_calc_time(1);
+ #endif
+
+ #ifdef ENABLE_WORK_QUEUE
+ //schedule_work(&g_stTs.rm_work);
+ queue_work(g_stTs.rm_workqueue, &g_stTs.rm_work);
+ #endif
+
+ //if (to do :touch point has been sent)
+ // mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+
+ return IRQ_HANDLED;
+}
+//=============================================================================
+static void rm31080_init_ts_structure_part(void)
+{
+ g_stTs.bInitFinish = 0;
+ g_stTs.bCalcFinish = 0;
+ g_stTs.bEnableScriber = 0;
+ g_stTs.bIsSuspended = 0;
+ g_stTs.bEnableAutoScan = 1;//default
+
+ #ifdef ENABLE_TIMER_DEBUG
+ g_stTs.u32WaitHalCount = 0;
+ #endif
+
+ #ifdef ENABLE_RAW_DATA_QUEUE
+ g_stTs.u8ScanModeState = RM_SCAN_MODE_MANUAL;
+ #endif
+}
+static void rm31080_init_ts_structure(void)
+{
+ g_stTs.ulHalPID = 0;
+
+ memset(&g_stTs, 0, sizeof(struct rm31080a_ts_para));
+
+ #ifdef ENABLE_WORK_QUEUE
+ g_stTs.rm_workqueue = create_singlethread_workqueue("rm_work");
+ INIT_WORK(&g_stTs.rm_work,rm_work_handler);
+ g_stTs.bIsWorkQueueExecuting = 0;
+ #endif
+}
+//=============================================================================
+static void rm31080_start(struct rm31080_ts *ts)
+{
+ #ifdef ENABLE_RM31080_DEEP_SLEEP
+ struct rm_spi_ts_platform_data *pdata;
+ #endif
+
+ if (!g_stTs.bIsSuspended)
+ return;
+ g_stTs.bIsSuspended = 0;
+
+
+ #ifdef ENABLE_RM31080_DEEP_SLEEP
+ //flow designed by Roger //20110930
+ pdata = g_input_dev->dev.parent->platform_data;
+ gpio_set_value(pdata->gpio_reset, 0);
+ msleep(120);
+ gpio_set_value(pdata->gpio_reset, 1);
+ msleep(10);
+ rm31080_init_ts_structure_part();
+ rm31080_ts_send_signal(g_stTs.ulHalPID,RM_SIGNAL_RESUME);
+ //printk("Reset HW finish\n");
+ #elif defined(ENABLE_AUTO_SCAN)
+ rm31080_ctrl_clear_int();
+ rm31080_ctrl_scan_start();
+ #endif
+
+
+}
+
+static void rm31080_stop(struct rm31080_ts *ts)
+{
+
+ //printk("Raydium TS: rm31080_stop():\n");
+ int iCount;
+ if (g_stTs.bIsSuspended)
+ return;
+
+ iCount = 0;
+ while(g_stTs.bIsWorkQueueExecuting)
+ {
+ printk("Raydium TS: Work_Queue is Executing.\n");
+ msleep(1);
+ iCount++;
+ if (iCount>1000)
+ break;
+ }
+ g_stTs.bIsSuspended = 1;
+ //to do :flush_work_queue()
+
+ #ifdef ENABLE_RM31080_DEEP_SLEEP
+ rm31080_ctrl_suspend();
+ #endif
+}
+
+#ifdef CONFIG_PM
+#if 0
+static int rm31080_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+ //printk("Raydium TS: rm31080_spi_suspend():\n");
+ return 0;
+}
+
+static int rm31080_spi_resume(struct spi_device *spi)
+{
+ //printk("Raydium TS: rm31080_spi_resume():\n");
+ return 0;
+}
+#endif
+
+
+static int rm31080_suspend(struct device *dev)
+{
+ struct rm31080_ts *ts = dev_get_drvdata(dev);
+ //printk("Raydium TS: rm31080_suspend():\n");
+ rm31080_stop(ts);
+ return 0;
+}
+
+static int rm31080_resume(struct device *dev)
+{
+ struct rm31080_ts *ts = dev_get_drvdata(dev);
+ //printk("Raydium TS: rm31080_resume():\n");
+ rm31080_start(ts);
+ return 0;
+}
+
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)
+static void rm31080_early_suspend(struct early_suspend *es)
+{
+ struct rm31080_ts *ts;
+ struct device *dev;
+ //printk("Raydium TS: rm31080_early_suspend():\n");
+
+ ts = container_of(es, struct rm31080_ts, early_suspend);
+ dev = ts->dev;
+
+ if (rm31080_suspend(dev) != 0)
+ {
+ dev_err(dev, "%s: failed\n", __func__);
+ }
+
+}
+
+static void rm31080_early_resume(struct early_suspend *es)
+{
+ struct rm31080_ts *ts;
+ struct device *dev;
+ //printk("Raydium TS: rm31080_early_resume():\n");
+
+ ts = container_of(es, struct rm31080_ts, early_suspend);
+ dev = ts->dev;
+
+ if (rm31080_resume(dev) != 0)
+ {
+ dev_err(dev, "%s: failed\n", __func__);
+ }
+}
+#else
+static const struct dev_pm_ops rm31080_pm_ops = {
+ .suspend = rm31080_suspend,
+ .resume = rm31080_resume,
+};
+#endif
+#endif
+
+
+struct rm31080_ts *rm31080_input_init(struct device *dev, unsigned int irq,
+ const struct rm31080_bus_ops *bops)
+{
+
+ struct rm31080_ts *ts;
+ struct input_dev *input_dev;
+ int err;
+
+ if (!irq) {
+ dev_err(dev, "no IRQ?\n");
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);//ts = kzalloc(sizeof(struct rm31080_ts), GFP_KERNEL);
+
+ input_dev = input_allocate_device();
+
+ if (!ts || !input_dev) {
+ dev_err(dev, "Failed to allocate memory\n");
+ err = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ g_input_dev = input_dev;
+
+ ts->bops = bops;
+ ts->dev = dev;
+ ts->input = input_dev;
+ ts->irq = irq;
+
+
+ #ifdef ENABLE_TIMER_RELEASE_TOUCH
+ //sample code :
+ //ts->timer.expires = jiffies + HZ;
+ //setup_timer(&ts->timer, rm31080_timer, (unsigned long) ts);
+ //mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
+ #endif
+ #ifdef ENABLE_TIMER_DEBUG
+ //ts->timer_debug.expires = jiffies + msecs_to_jiffies(10*1000);
+ setup_timer(&ts->timer_debug, rm31080_debug_timer, (unsigned long) ts);
+ mod_timer(&ts->timer_debug, jiffies + msecs_to_jiffies(10*1000));
+ g_stTs.u32WaitHalCount = 0;
+ #endif
+
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
+
+ input_dev->name = "raydium_ts";
+ input_dev->phys = ts->phys;
+ input_dev->dev.parent = dev;
+ input_dev->id.bustype = bops->bustype;
+
+ input_dev->open = rm31080_input_open;
+ input_dev->close = rm31080_input_close;
+
+ input_set_drvdata(input_dev, ts);
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(ABS_X, input_dev->absbit);
+ __set_bit(ABS_Y, input_dev->absbit);
+ __set_bit(ABS_PRESSURE, input_dev->absbit);
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+
+
+ /* For single touch */
+ input_set_abs_params(input_dev, ABS_X,
+ 0,
+ RM_INPUT_RESOLUTION_X-1,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ 0,
+ RM_INPUT_RESOLUTION_Y-1,
+ 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, 1, 0, 0);//0, 255, 0, 0);
+
+ /* For multi touch */
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, 0xFF, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, RM_INPUT_RESOLUTION_X-1, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, RM_INPUT_RESOLUTION_Y-1, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TRACKING_ID,
+ 0, 32, 0, 0);
+
+
+
+ #if 0
+ input_dev->id.product = (revid & 0xff);
+ input_dev->id.version = revid >> 8;
+ #endif
+
+ #if 0 //move to board-touch-raydium_spi.c
+ gpio_direction_input(irq_to_gpio(ts->irq));
+ tegra_gpio_enable(irq_to_gpio(ts->irq));
+ #endif
+
+ err = request_threaded_irq(ts->irq, NULL, rm31080_irq,
+ IRQF_TRIGGER_RISING,
+ dev_name(dev), ts);
+ if (err) {
+ dev_err(dev, "irq %d busy?\n", ts->irq);
+ goto err_free_mem;
+ }
+
+
+ mutex_init(&ts->access_mutex);
+ #if defined(CONFIG_HAS_EARLYSUSPEND)
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.suspend = rm31080_early_suspend;
+ ts->early_suspend.resume = rm31080_early_resume;
+ register_early_suspend(&ts->early_suspend);
+ #endif
+
+
+ __rm31080_disable(ts);
+
+ err = sysfs_create_group(&dev->kobj, &vtest_attr_group);
+ if (err)
+ goto err_free_irq;
+
+
+ err = input_register_device(input_dev);
+ if (err)
+ goto err_remove_attr;
+
+ return ts;
+
+
+err_remove_attr:
+ sysfs_remove_group(&dev->kobj, &vtest_attr_group);
+err_free_irq:
+ free_irq(ts->irq, ts);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(ts);
+err_out:
+ return ERR_PTR(err);
+}
+
+static int
+dev_open(struct inode *inode, struct file *filp)
+{
+ //printk("%s():\n", __FUNCTION__);
+ return 0;
+}
+
+static int
+dev_release(struct inode *inode, struct file *filp)
+{
+ //printk("%s():\n", __FUNCTION__);
+ g_stTs.bInitFinish = 0;
+ rm31080_enter_manual_mode();
+ return 0;
+}
+
+static ssize_t
+dev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
+{
+ unsigned long missing;
+ ssize_t status = 0;
+ u8 *pMyBuf;
+
+ pMyBuf = kmalloc(count, GFP_KERNEL);
+ if (pMyBuf == NULL)
+ return -ENOMEM;
+
+ pMyBuf[0] = buf[0];
+ #ifdef TEST_SPI_READ_SPEED
+ if (count > 1000) my_calc_time(1);
+ #endif
+ //status = spi_write_then_read(g_spi, pMyBuf, 1, pMyBuf, count);
+ status = rm31080_spi_read(pMyBuf[0],pMyBuf, count);
+
+ #ifdef TEST_SPI_READ_SPEED
+ if (count > 1000) my_calc_time(0);
+ #endif
+
+ #if 0//def TEST_INT_TO_CLEAR_INT
+ if (g_stTs.bInitFinish)
+ {
+ if (buf[0] == 0xF2 && count == 1)
+ {
+ my_calc_time(0);
+ }
+ }
+ #endif
+
+ if (status!=0)
+ {
+ printk("rm31080_spi_read() fail\n");
+ }
+
+ status = count;
+ missing = copy_to_user(buf, pMyBuf, count);
+ if (missing == status)
+ status = -EFAULT;
+ else
+ status = status - missing;
+
+ kfree(pMyBuf);
+ return status;
+}
+
+static ssize_t
+dev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ u8 *pMyBuf;
+ unsigned long missing;
+ ssize_t status = 0;
+
+ pMyBuf = kmalloc(count, GFP_KERNEL);
+ if (pMyBuf == NULL)
+ return -ENOMEM;
+
+ missing = copy_from_user(pMyBuf, buf, count);
+ if (missing == 0) {
+ //status = spi_write(g_spi, pMyBuf, count);
+ status = rm31080_spi_write(pMyBuf, count);
+ } else
+ status = -EFAULT;
+
+ kfree(pMyBuf);
+ return count;
+}
+
+//=============================================================================
+// Description:
+// I/O Control routin.
+// Input:
+// file:
+// cmd :
+// arg :
+// Output:
+// 1: succeed
+// 0: failed
+//=============================================================================
+static long
+dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long ret = 1;
+ switch (cmd & 0xFFFF)
+ {
+ case RM_IOCTL_REPORT_POINT:
+ raydium_report_pointer((void *)arg);
+ break;
+ case RM_IOCTL_SET_HAL_PID:
+ g_stTs.ulHalPID = arg;
+ break;
+ case RM_IOCTL_INIT_START:
+ g_stTs.bInitFinish = 0;
+ rm31080_enter_manual_mode();
+ break;
+ case RM_IOCTL_INIT_END:
+ g_stTs.bInitFinish = 1;
+ g_stTs.bCalcFinish = 1;
+ #ifdef ENABLE_RAW_DATA_QUEUE
+ //printk("------ IOCTL init finish\n");
+ ret = rm31080_ctrl_scan_start();
+ #endif
+ break;
+ case RM_IOCTL_FINISH_CALC:
+ g_stTs.bCalcFinish = 1;
+ break;
+ case RM_IOCTL_SCRIBER_CTRL:
+ g_stTs.bEnableScriber = (bool)arg;
+ break;
+ case RM_IOCTL_AUTOSCAN_CTRL:
+ g_stTs.bEnableAutoScan = (bool)arg;
+ break;
+ #ifdef ENABLE_RAW_DATA_QUEUE
+ case RM_IOCTL_READ_RAW_DATA:
+ ret = rm31080_queue_read_raw_data((u8 *)arg,(cmd>>16) & 0xFFFF);
+ #endif
+ default:
+ break;
+ }
+ return ret;
+
+}
+static struct file_operations dev_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_open,
+ .release = dev_release,
+ .read = dev_read,
+ .write = dev_write,
+ .unlocked_ioctl = dev_ioctl,
+};
+
+static struct miscdevice raydium_ts_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "raydium_ts",
+ .fops = &dev_fops,
+};
+
+
+static const struct rm31080_bus_ops rm31080_spi_bus_ops = {
+ .bustype = BUS_SPI,
+// .read = rm31080_spi_read,
+// .multi_read = rm31080_spi_multi_read,
+// .write = rm31080_spi_write,
+};
+
+
+static int __devexit rm31080_spi_remove(struct spi_device *spi)
+{
+ struct rm31080_ts *ts = spi_get_drvdata(spi);
+
+ #ifdef ENABLE_RAW_DATA_QUEUE
+ rm31080_queue_free();
+ #endif
+
+ #ifdef ENABLE_KERNEL_CALC
+ ts_main_free();
+ #endif
+
+
+ #ifdef ENABLE_TS_THREAD
+ if (ts->ts_task)
+ kthread_stop(ts->ts_task);
+ #endif
+
+ //to do :remove gpio;
+ sysfs_remove_group(&ts->dev->kobj, &vtest_attr_group);
+ free_irq(ts->irq, ts);
+ input_unregister_device(ts->input);
+ kfree(ts);
+ spi_set_drvdata(spi, NULL);
+ misc_deregister(&raydium_ts_miscdev);
+ return 0;
+}
+
+static int __devinit rm31080_spi_probe(struct spi_device *spi)
+{
+ struct rm31080_ts *ts;
+
+ rm31080_init_ts_structure();
+ rm31080_init_ts_structure_part();
+
+ if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) {
+ dev_err(&spi->dev, "SPI CLK %d Hz?\n", spi->max_speed_hz);
+ return -EINVAL;
+ }
+
+
+ #if 0 //sample code: test spi
+ unsigned char buf[10];
+ unsigned int iCount =0;
+ //write:[0x50]=0x11,[0x51]=0x22,[0x52]=0x33,[0x53]=0x44
+ //you can test REG 0x50 ~ 0x5F
+ while(1)
+ {
+ buf[0]=0x50;
+ buf[1]=0x55;
+ buf[2]=0xAA;
+ buf[3]=0x00;
+ buf[4]=0xFF;
+ spi_write(spi, &buf[0], 5);
+
+ //read [0x50]~[0x53]
+ buf[5]= 0x50 | 0x80;
+ buf[6]=buf[7]=buf[8]=buf[9]=0;
+ spi_write_then_read(spi, &buf[5], 1, &buf[6], 4);
+ if ((buf[1]!=buf[6])||
+ (buf[2]!=buf[7])||
+ (buf[3]!=buf[8])||
+ (buf[4]!=buf[9]))
+ {
+ printk("Wrote Data :%x,%x,%x,%x\n",buf[1],buf[2],buf[3],buf[4]);
+ printk("Data From SPI:%x,%x,%x,%x\n",buf[6],buf[7],buf[8],buf[9]);
+ }
+ iCount++;
+ if (iCount%10000==0)
+ {
+ printk("spi ok\n");
+ }
+ };
+ #endif
+
+ #if 0 //sample code: to change setting here
+ //spi->bits_per_word = 16;
+ //spi->max_speed_hz = xxxxx;
+ err = spi_setup(spi);
+ if (err) {
+ dev_dbg(&spi->dev, "spi master doesn't support xxx\n");
+ return err;
+ }
+ #endif
+
+ ts = rm31080_input_init(&spi->dev, spi->irq, &rm31080_spi_bus_ops);
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+ spi_set_drvdata(spi, ts);
+
+ #ifdef ENABLE_KERNEL_CALC
+ raydium_ts_set_spi(spi);
+ ts_main_init();
+ while(1)
+ {
+ raydium_ts_t007_wait_for_scan();
+ ts_main_calc();
+ raydium_ts_t007_start_scan();
+ msleep(100);
+ }
+ #else
+ g_spi = spi;
+ #endif
+
+
+ #ifdef ENABLE_TS_THREAD
+ BUG_ON(ts->ts_task);
+ ts->ts_task = kthread_run(rm31080_ts_thread, (void *)ts, "RM31080_ts");
+ if (IS_ERR(ts->ts_task)) {
+ //ret = PTR_ERR(ts->ts_task);
+ ts->ts_task = NULL;
+ }
+ #endif
+
+ if (misc_register(&raydium_ts_miscdev) != 0)
+ {
+ printk("Raydium TS: cannot register miscdev\n");
+ return 0;
+ }
+
+ #ifdef ENABLE_RAW_DATA_QUEUE
+ rm31080_queue_init();
+ #endif
+
+ return 0;
+}
+
+static struct spi_driver rm31080_spi_driver = {
+ .driver = {
+ .name = "rm_ts_spidev",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ #if !defined(CONFIG_HAS_EARLYSUSPEND)
+ .pm = &rm31080_pm_ops,
+ #endif
+ },
+ .probe = rm31080_spi_probe,
+ .remove = __devexit_p(rm31080_spi_remove),
+// .suspend = rm31080_spi_suspend,
+// .resume = rm31080_spi_resume,
+};
+
+
+static int __init rm31080_spi_init(void)
+{
+ return spi_register_driver(&rm31080_spi_driver);
+/*
+ if (iRet!=0)
+ {
+ printk("Raydium spi register failed\n");
+ return iRet;
+ }
+ printk("Raydium spi register ok\n");
+ if (misc_register(&raydium_ts_miscdev) != 0)
+ {
+ printk("Raydium TS: cannot register miscdev\n");
+ return 0;
+ }
+
+ return iRet;
+*/
+}
+
+module_init(rm31080_spi_init);
+
+static void __exit rm31080_spi_exit(void)
+{
+ #ifdef ENABLE_WORK_QUEUE
+ if (g_stTs.rm_workqueue)
+ destroy_workqueue(g_stTs.rm_workqueue);
+ #endif
+ spi_unregister_driver(&rm31080_spi_driver);
+}
+module_exit(rm31080_spi_exit);
+
+MODULE_AUTHOR("Valentine Hsu <valentine.hsu@rad-ic.com>");
+MODULE_DESCRIPTION("Raydium touchscreen SPI bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:raydium-t007");
diff --git a/drivers/input/touchscreen/rm31080a_ts.h b/drivers/input/touchscreen/rm31080a_ts.h
new file mode 100644
index 000000000000..fb4c009b294b
--- /dev/null
+++ b/drivers/input/touchscreen/rm31080a_ts.h
@@ -0,0 +1,42 @@
+#ifndef _RM31080A_TS_H_
+#define _RM31080A_TS_H_
+
+#define ENABLE_RAW_DATA_QUEUE
+
+#define RM_IOCTL_REPORT_POINT 0x1001
+#define RM_IOCTL_SET_HAL_PID 0x1002
+#define RM_IOCTL_INIT_START 0x1003
+#define RM_IOCTL_INIT_END 0x1004
+#define RM_IOCTL_FINISH_CALC 0x1005
+#define RM_IOCTL_SCRIBER_CTRL 0x1006
+#define RM_IOCTL_READ_RAW_DATA 0x1007
+#define RM_IOCTL_AUTOSCAN_CTRL 0x1008
+
+
+//#define RM_INPUT_RESOLUTION_X 1536
+//#define RM_INPUT_RESOLUTION_Y 960
+#define RM_INPUT_RESOLUTION_X 4096
+#define RM_INPUT_RESOLUTION_Y 4096
+
+
+#define RM_TS_SIGNAL 44
+#define RM_TS_MAX_POINTS 16
+
+#define RM_SIGNAL_INTR 0x00000001
+#define RM_SIGNAL_SUSPEND 0x00000002
+#define RM_SIGNAL_RESUME 0x00000003
+
+typedef struct
+{
+ unsigned char ucTouchCount;
+ unsigned char ucID[RM_TS_MAX_POINTS];
+ unsigned short usX[RM_TS_MAX_POINTS];
+ unsigned short usY[RM_TS_MAX_POINTS];
+ unsigned short usZ[RM_TS_MAX_POINTS];
+}rm_touch_event;
+
+struct rm_spi_ts_platform_data{
+ int gpio_reset;
+};
+
+#endif //_RM31080A_TS_H_