summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
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_