/* * Raydium RM31080(T007) touchscreen (SPI bus) - Android version * * Copyright (C) 2011-2012 Raydium Inc. * * Licensed under the GPL-2 or later. * * Version : 0.04 */ //============================================================================= //INCLUDED FILES //============================================================================= #include // BUS_SPI #include #include #include #include #include #include #include #include #include // wake_up_process() #include // kthread_create()、kthread_run() #include // copy_to_user(), #include #include // siginfo #include // rcu_read_lock #include // find_task_by_pid_type #include // sys_clock_gettime() #if defined(CONFIG_HAS_EARLYSUSPEND) #include #endif #include //============================================================================= //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_SPEED_TEST_FUNCTION //#define ENABLE_TEST_AVERAGE //#define ENABLE_CALC_QUEUE_COUNT #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_WORK_QUEUE #include #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_RAW_DATA_QUEUE u8 u8ScanModeState; #endif }; struct rm31080_ts { const struct rm31080_bus_ops *bops; struct device *dev; struct input_dev *input; 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; 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); } 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 void rm31080_ctrl_enter_auto_mode(void) { //Enable auto scan rm31080_spi_byte_write(RM31080_REG_09, 0x10 | 0x40); } void rm31080_ctrl_leave_auto_mode(void) { //Disable auto scan rm31080_spi_byte_write(RM31080_REG_09, 0x00); } #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); rm31080_spi_byte_write(RM31080_REG_10, 0x14); rm31080_spi_byte_write(RM31080_REG_11, 0x17); msleep(15); 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(); 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; } 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; } #ifdef ENABLE_CALC_QUEUE_COUNT 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 //============================================================================= // Description: // Copy Config(Parameters) to HAL's Buffer // Input: // p: HAL's buffer // u32Len : buffer size // Output: // 1: succeed // 0: failed //============================================================================= static long rm31080_get_config(u8 * p, u32 u32Len) { u32 u32Ret; struct rm_spi_ts_platform_data *pdata; pdata = g_input_dev->dev.parent->platform_data; u32Ret = copy_to_user(p, pdata->config, u32Len); if (u32Ret != 0) return 0; return 1; } #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 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] << 4); //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 == 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, 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 } #ifdef ENABLE_AUTO_SCAN raydium_change_scan_mode(spTP->ucTouchCount); #endif } //============================================================================= //============================================================================= 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); } 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_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; } else { u8StartAverage = 0; } 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 (g_stTs.bIsSuspended) { //printk("rm_work_handler stops after suspend\n"); return; } g_stTs.bIsWorkQueueExecuting = 1; iRet = rm31080_ctrl_clear_int(); 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) { return IRQ_HANDLED; } #ifdef ENABLE_WORK_QUEUE queue_work(g_stTs.rm_workqueue, &g_stTs.rm_work); #endif 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; #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); #elif defined(ENABLE_AUTO_SCAN) rm31080_ctrl_clear_int(); rm31080_ctrl_scan_start(); #endif } static void rm31080_stop(struct rm31080_ts *ts) { 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; #ifdef ENABLE_RM31080_DEEP_SLEEP rm31080_ctrl_suspend(); #endif } #ifdef CONFIG_PM static int rm31080_suspend(struct device *dev) { struct rm31080_ts *ts = dev_get_drvdata(dev); rm31080_stop(ts); return 0; } static int rm31080_resume(struct device *dev) { struct rm31080_ts *ts = dev_get_drvdata(dev); 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; 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; 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); 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; 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); 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); 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); 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) { return 0; } static int dev_release(struct inode *inode, struct file *filp) { 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]; status = rm31080_spi_read(pMyBuf[0], pMyBuf, count); 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 = 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 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); break; #endif case RM_IOCTL_SET_PARAMETER: ret = rm31080_get_config((u8 *) arg, (cmd >> 16) & 0xFFFF); break; 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, }; 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_WORK_QUEUE if (g_stTs.rm_workqueue) destroy_workqueue(g_stTs.rm_workqueue); #endif misc_deregister(&raydium_ts_miscdev); 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); 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; } 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); g_spi = spi; if (misc_register(&raydium_ts_miscdev) != 0) { dev_err(&spi->dev, "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), }; static int __init rm31080_spi_init(void) { return spi_register_driver(&rm31080_spi_driver); } module_init(rm31080_spi_init); static void __exit rm31080_spi_exit(void) { spi_unregister_driver(&rm31080_spi_driver); } module_exit(rm31080_spi_exit); MODULE_AUTHOR("Valentine Hsu "); MODULE_DESCRIPTION("Raydium touchscreen SPI bus driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:raydium-t007");