1559 lines
45 KiB
C

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright (c) 2009 Tony YC Huang <tony.yc.huang@qisda.com>
*
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/arch/map.h>
#include <linux/miscdevice.h>
#include "s3c_ts_iic.h"
#include <asm/arch/regs-gpio.h>
//Tony test
#include <linux/kthread.h>
#include <linux/sched.h>
/* Qisda, howard hsu, 2010/01/27, TOUCH firmware update { */
#include <asm/uaccess.h> //for copy_from_user
/* } Qisda, howard hsu, 2010/01/27, TOUCH firmware update */
//Aaron, add for the feature of buffered touch data
#define USE_BUFFERED_TOUCH_DATA
/* Aaron, 20090122, add for CPU sleep prevention */
/* prevent cpu from sleep when any event happens */
#ifdef CONFIG_PM_PLATFORM_POWER_SAVING
#define CPU_SLEEP_PREVENT
#endif //#ifdef CONFIG_PM_PLATFORM_POWER_SAVING
int Cyio_PushEvent(char eventId, char unique);
#ifdef USE_BUFFERED_TOUCH_DATA
static int go_in_suspend = 0;
#endif
#ifdef CPU_SLEEP_PREVENT
extern unsigned int g_wakeup_event_occurs;
#endif
//Tony test
//#define IN_2416_EMU_BOARD
//#define QISDA_TEST_GPIO_PROBE
//Qisda Tony 090415 [
//#define POLLING_MODE
//#define KTHREAD_USE
//Qisda Tony 090415 ]
#define DEVICE_NAME "s3c2410-ts-iic"
#define TRUE 1
#define FALSE 0
#define printk(x...)
//#ifdef IN_2416_EMU_BOARD
//#define GPIO_NUM (0x3)
//#else
//#define GPIO_NUM (0x2)
//#endif
#define KEY_BUF_SIZE 1
struct s3c_ts_iic {
struct input_dev *dev;
struct i2c_client *client;
struct platform_device *pdev;
long xp;
long yp;
unsigned int polling_time;
};
struct t_point {
short x;
short y;
};
static struct platform_driver s3c_ts_iic_driver;
static struct work_struct workq_readdata;
static struct s3c_ts_iic *ts_iic;
static char *s3c_ts_iic_name = "TouchScreen Of IIC Type";
#ifdef QISDA_TEST_GPIO_PROBE
static void __iomem *g_pGPIOReg_GPFCON;
#endif
struct t_point keybuffer[KEY_BUF_SIZE];
static short IdxBottom =0;
static struct timer_list touch_iic_timer_qisda;
#ifdef POLLING_MODE
static int need_calibration = FALSE;
#endif
#ifdef KTHREAD_USE
static wait_queue_head_t wait;
static struct task_struct *kmain_task=NULL;
#endif
//Tony test
#define NEW_TCOM_BOARD
//static void touch_iic_disable_interrupt(void) { printk("touch_iic_disable_interrupt\n"); writel(readl(S3C24XX_EINTMASK) | (0x1<<GPIO_NUM), S3C24XX_EINTMASK); }
//static void touch_iic_enable_interrupt(void) { printk("touch_iic_enable_interrupt\n"); writel(readl(S3C24XX_EINTMASK) & ~(0x1<<GPIO_NUM), S3C24XX_EINTMASK); }
//static void touch_iic_clear_interrupt_pending(void) { printk("touch_iic_clear_interrupt_pending\n"); writel(0x1<<GPIO_NUM, S3C24XX_EINTPEND); }
//static void touch_iic_set_interrupt_method(int eSM) {writel(readl(S3C24XX_EXTINT0) & ~(0x7<<(GPIO_NUM<<2)) | (eSM<<(GPIO_NUM<<2)),S3C24XX_EXTINT0);}
static void touhc_iic_timer_handler_qisda(unsigned long data) { schedule_work(&workq_readdata); }
/*kit.mod 2009/11/17*/
#define TOUCH_IIC_CALIBRATION 1
#define TOUCH_IIC_SET_POLLING_TIME 2
#define TOUCH_DEVICE_POWER_STATE 3
#define TOUCH_DEVICE_ACTIVE_STATE 0 //Power State D0
#define TOUCH_DEVICE_SLEEP_STATE 1 //Power State D1
#define TOUCH_DEVICE_DEEPSLEEP_STATE 2 //Power State D2
#define TOUCH_DEVICE_POWEROFF_STATE 3 //Power State D3
/*kit.end*/
/* Qisda, howard hsu, 2010/01/27, TOUCH firmware update { */
#define TOUCH_IIC_FW_UPDATE 4
#define TOUCH_IIC_GET_FW_INFO 6 /* get fw version */
/* } Qisda, howard hsu, 2010/01/27, TOUCH firmware update */
/*kit.add 2010/01/30*/
#define TOUCH_IIC_T_SENSOR_ENABLE 5
/*kit.end*/
/*kit.add 2009/11/16*/
#define TOUCH_ACTIVE_POLLING_TIME 20 //default value
#define TOUCH_SLEEP_POLLING_TIME 20 //10
#define TOUCH_DEEPSLEEP_POLLING_TIME 20 //1
/*kit.end*/
/*kit.add 2009/11/04*/
static short isTouchPowerOff = 0;
static short touchPowerState = TOUCH_DEVICE_ACTIVE_STATE;
static short touchPollingTime = TOUCH_ACTIVE_POLLING_TIME;
extern unsigned int wkup_srce;
/*kit.end*/
/*
static void touch_iic_port_initialize(void)
{
#ifndef IN_2416_EMU_BOARD
//Set GPG3 pull-up, enable touch panel functions
writel(readl(S3C2410_GPGDAT) | (1<<3), S3C2410_GPGDAT);
writel(readl(S3C2410_GPGUP) | (0x2<<6),S3C2410_GPGUP);
writel(readl(S3C2410_GPGCON) | (0x1<<6),S3C2410_GPGCON);
#endif
//Qisda Tony 090415 [
#ifndef POLLING_MODE
#ifdef IN_2416_EMU_BOARD
s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_EINT3);
s3c2410_gpio_pullup(S3C2410_GPF3, 2);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
#endif
#endif
//Qisda Tony 090415 ]
}
*/
/*
static void touch_iic_init(void)
{
printk("touch_iic_init\n");
touch_iic_port_initialize();
//Qisda Tony 090415 [
#ifndef POLLING_MODE
touch_iic_disable_interrupt();
touch_iic_set_interrupt_method(S3C2410_EXTINT_FALLEDGE);
//Tony test
#ifndef KTHREAD_USE
init_timer(&touch_iic_timer_qisda);
touch_iic_timer_qisda.function =touhc_iic_timer_handler_qisda;
#endif
#endif
//Qisda Tony 090415 ]
memset(keybuffer,0x0,sizeof(keybuffer));
}
*/
#ifdef USE_BUFFERED_TOUCH_DATA
#define BUFFERED_DATA_LEN 16
/* Aaron: two coordinates on each point */
/* two bytes for each coordinate */
/* block read for max byte num=32, ((32/2)/2)=8 */
/* <=CHECK_LEN_EACH_TIME shall NOT be larger than 8, sync with qisda_iic.c */
#define CHECK_LEN_EACH_TIME 8
static int IsPanelPressed = 0;
static void bufferd_touch_point_handler(int WithRelease)
{
/* [0] is the index of check count */
/* [1] is the check length */
/* buffered data start from [2],x1_y1_x2_y2_x3_y3 */
int buffered_data[BUFFERED_DATA_LEN*2+(2+1)] = {0};
int i, IndexOffset;
//printk("bufferd_touch_point_handler: start\n");
buffered_data[1] = CHECK_LEN_EACH_TIME;
for (i = 0; i < (BUFFERED_DATA_LEN/CHECK_LEN_EACH_TIME); i++) {
buffered_data[0] = i;
ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_BUFFERED_POSITION,buffered_data);
}
//Aaron: send input event.
if ((buffered_data[2] == 0) && (buffered_data[3] == 0)) {
/* If buffered data is empty, do nothing before return*/
return;
}
for (i = 1; i < (BUFFERED_DATA_LEN+1); i++) {
IndexOffset = 2 * i;
/* check if next point data is zero, which means no more data. */
if ((i == BUFFERED_DATA_LEN) ||
(!buffered_data[IndexOffset + 2] && !buffered_data[IndexOffset + 2 + 1])) {
//TODO: send release event.
input_report_abs(ts_iic->dev, ABS_X, buffered_data[IndexOffset]);
input_report_abs(ts_iic->dev, ABS_Y, buffered_data[IndexOffset + 1]);
// //for debug
// //printk("\n bufferd_touch_point_handler: panel is touching(%d,%d)[%d]\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1],i);
if (WithRelease) {
if (!IsPanelPressed) {
/* in case that only one buffered data with release */
input_report_key(ts_iic->dev, BTN_TOUCH, 1);
input_report_abs(ts_iic->dev, ABS_PRESSURE,1);
//printk("bufferd_touch_point_handler: panel is Pressed(only one buffered data)\n");
//maybe not necessary//IsPanelPressed = 1;
}
input_report_key(ts_iic->dev, BTN_TOUCH, 0);
input_report_abs(ts_iic->dev, ABS_PRESSURE,0);
IsPanelPressed = 0;
//printk("bufferd_touch_point_handler: panel is Released(%d,%d)[%d]\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1],i);
}
input_sync(ts_iic->dev);
break;
}
//TODO: send press event
input_report_abs(ts_iic->dev, ABS_X, buffered_data[IndexOffset]);
input_report_abs(ts_iic->dev, ABS_Y, buffered_data[IndexOffset + 1]);
if (!IsPanelPressed) {
input_report_key(ts_iic->dev, BTN_TOUCH, 1);
input_report_abs(ts_iic->dev, ABS_PRESSURE,1);
IsPanelPressed = 1;
printk("bufferd_touch_point_handler: panel is Pressed(%d,%d)\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1]);
// } else {
// //for debug
// printk("\n bufferd_touch_point_handler: panel is touching(%d,%d)[%d]\n",buffered_data[IndexOffset],buffered_data[IndexOffset + 1],i);
}
input_sync(ts_iic->dev);
}
}
#endif
static void ts_iic_workqueue(struct work_struct *work)
{
static int startpoint[2];
static int emptyKeyBuffer=TRUE;
int curpoint[2];
short i=0;
#ifdef NEW_TCOM_BOARD
static int zeroCount=0;
static int prevpoint[2];
#endif
//Qisda Tony 090415 [
#ifdef POLLING_MODE
#ifdef KTHREAD_USE
for(;;){
//This only get the interrupt periodically. No while loop in workqueue, use polling....
//Tony test
//Tony test
#ifndef NEW_TCOM_BOARD
#else
ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_POSITION,curpoint);
if((curpoint[0]==0) ||(curpoint[1]==0))
{
if(emptyKeyBuffer==TRUE) goto finished;
#ifdef NEW_TCOM_BOARD
else
{
if(zeroCount<3)
{
zeroCount++;
goto finished;
}
else
{
//printk("\nooooo %d,%d\n",curpoint[0],curpoint[1]);
goto release;
}
}
#else
else goto release;
#endif
}
//key input
ts_iic->xp = keybuffer[IdxBottom].x = curpoint[0];
ts_iic->yp =keybuffer[IdxBottom].y = curpoint[1];
input_report_abs(ts_iic->dev, ABS_X, ts_iic->xp);
input_report_abs(ts_iic->dev, ABS_Y, ts_iic->yp);
input_report_key(ts_iic->dev, BTN_TOUCH, 1);
input_report_abs(ts_iic->dev, ABS_PRESSURE,1);
input_sync(ts_iic->dev);
//printk("\n--%d,%d,%d\n",curpoint[0],curpoint[1],IdxBottom);
#ifdef NEW_TCOM_BOARD
prevpoint[0]=curpoint[0];
prevpoint[1]=curpoint[1];
#endif
if(emptyKeyBuffer==TRUE)
{
emptyKeyBuffer=FALSE;
memcpy(startpoint,curpoint,sizeof(startpoint));
printk("\n--%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom);
}
IdxBottom++;
if( IdxBottom >= KEY_BUF_SIZE )
IdxBottom = 0;
goto finished;
release:
printk("++%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom);
for(i=0;i<KEY_BUF_SIZE;++i)
printk("%d,%d\n",keybuffer[i].x,keybuffer[i].y);
i = IdxBottom -1;
if(i<=-1)
i = KEY_BUF_SIZE -1;
startpoint[0]-=keybuffer[i].x;
startpoint[1]-=keybuffer[i].y;
//Put your gesture function here!!!!
/*if(( startpoint[1]<-50) || (startpoint[1]>50))
printk(KERN_ERR "ts_iic_workqueue okokokokokokokokok\n");*/
// Key input
if (Cyio_PushEvent('R', 1) >= 0)
{
Cyio_PushEvent( (keybuffer[0].x >> 8) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].x >> 0) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].y >> 8) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].y >> 0) & 0xFF, 0 );
}
memset(keybuffer,0x0,sizeof(keybuffer));
memset(startpoint,0x0,sizeof(startpoint));
IdxBottom = 0;
emptyKeyBuffer = TRUE;
//Key input
ts_iic->xp =ts_iic->yp = 0;
input_report_key(ts_iic->dev, BTN_TOUCH, 0);
input_report_abs(ts_iic->dev, ABS_PRESSURE,0);
input_sync(ts_iic->dev);
#ifdef NEW_TCOM_BOARD
prevpoint[0]=0;
prevpoint[1]=0;
zeroCount = 0;
#endif
finished:
msleep(15);
#endif //#if NEW_TCOM_BOARD
}
#else //Not Ktherad_use
//This only get the interrupt periodically. No while loop in workqueue, use polling....
ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_POSITION,curpoint);
if((curpoint[0]==0) ||(curpoint[1]==0))
{
if(emptyKeyBuffer==TRUE) goto finished;
#ifdef NEW_TCOM_BOARD
else
{
if(zeroCount<3)
{
zeroCount++;
goto finished;
}
else
{
//printk("\nooooo %d,%d\n", curpoint[0], curpoint[1]);
goto release;
}
}
#else
else goto release;
#endif
}
//key input
ts_iic->xp = keybuffer[IdxBottom].x = curpoint[0];
ts_iic->yp =keybuffer[IdxBottom].y = curpoint[1];
input_report_abs(ts_iic->dev, ABS_X, ts_iic->xp);
input_report_abs(ts_iic->dev, ABS_Y, ts_iic->yp);
input_report_key(ts_iic->dev, BTN_TOUCH, 1);
input_report_abs(ts_iic->dev, ABS_PRESSURE,1);
input_sync(ts_iic->dev);
//printk("\n--%d,%d,%d\n",curpoint[0],curpoint[1],IdxBottom);
if(emptyKeyBuffer==TRUE)
{
emptyKeyBuffer=FALSE;
memcpy(startpoint,curpoint,sizeof(startpoint));
printk("\n++%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom);
}
IdxBottom++;
if( IdxBottom >= KEY_BUF_SIZE )
IdxBottom = 0;
goto finished;
release:
printk("--%d,%d,%d\n", curpoint[0], curpoint[1],IdxBottom);
for(i=0;i<KEY_BUF_SIZE;++i)
printk("%d,%d\n",keybuffer[i].x,keybuffer[i].y);
i = IdxBottom -1;
if(i<=-1)
i = KEY_BUF_SIZE -1;
startpoint[0]-=keybuffer[i].x;
startpoint[1]-=keybuffer[i].y;
//Put your gesture function here!!!!
/*if(( startpoint[1]<-50) || (startpoint[1]>50))
printk(KERN_ERR "ts_iic_workqueue okokokokokokokokok\n");*/
// Key input
if (Cyio_PushEvent('R', 1) >= 0)
{
Cyio_PushEvent( (keybuffer[0].x >> 8) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].x >> 0) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].y >> 8) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].y >> 0) & 0xFF, 0 );
}
memset(keybuffer,0x0,sizeof(keybuffer));
memset(startpoint,0x0,sizeof(startpoint));
IdxBottom = 0;
emptyKeyBuffer = TRUE;
//Key input
ts_iic->xp =ts_iic->yp = 0;
input_report_key(ts_iic->dev, BTN_TOUCH, 0);
input_report_abs(ts_iic->dev, ABS_PRESSURE,0);
input_sync(ts_iic->dev);
#ifdef NEW_TCOM_BOARD
prevpoint[0]=0;
prevpoint[1]=0;
zeroCount = 0;
#endif
finished:
if(need_calibration){
printk("TOUCH_IIC_CALIBRATION...");
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_CALIBRATION, NULL);
need_calibration = FALSE;
printk("done\n");
}
touch_iic_timer_qisda.expires = jiffies + (HZ/ts_iic->polling_time);
mod_timer(&touch_iic_timer_qisda,touch_iic_timer_qisda.expires);
return;
#endif //KTHREAD_USE
#else // NOT POLLING_MODE
//This only get the interrupt
ts_iic->client->driver->command(ts_iic->client,QISDA_IIC_READ_POSITION,curpoint);
if((curpoint[0]==0) ||(curpoint[1]==0))
{
//printk("\n[%d] --%d,%d,%d\n", __LINE__, curpoint[0], curpoint[1], emptyKeyBuffer);
if(emptyKeyBuffer==TRUE){
emptyKeyBuffer = FALSE;
#ifdef USE_BUFFERED_TOUCH_DATA
bufferd_touch_point_handler(1); /* with release */
go_in_suspend = 0;
#endif
goto finished;
}
else{
//printk("goto release \n");
goto release;
}
}
#ifdef USE_BUFFERED_TOUCH_DATA
if (go_in_suspend) {
bufferd_touch_point_handler(0); /* without release */
go_in_suspend = 0;
}
#endif
//key input
ts_iic->xp = keybuffer[IdxBottom].x = curpoint[0];
ts_iic->yp =keybuffer[IdxBottom].y = curpoint[1];
input_report_abs(ts_iic->dev, ABS_X, ts_iic->xp);
input_report_abs(ts_iic->dev, ABS_Y, ts_iic->yp);
#ifdef USE_BUFFERED_TOUCH_DATA
if (!IsPanelPressed) {
input_report_key(ts_iic->dev, BTN_TOUCH, 1);
input_report_abs(ts_iic->dev, ABS_PRESSURE,1);
IsPanelPressed = 1;
}
#else
input_report_key(ts_iic->dev, BTN_TOUCH, 1);
input_report_abs(ts_iic->dev, ABS_PRESSURE,1);
#endif
input_sync(ts_iic->dev);
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPH12, S3C2410_GPH12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPH12, 1);
#endif
//printk("\n[%d] --%d,%d,%d\n", __LINE__, curpoint[0], curpoint[1], emptyKeyBuffer);
if((startpoint[0]==0) || (startpoint[1]==0))
{
emptyKeyBuffer=FALSE;
memcpy(startpoint,curpoint,sizeof(startpoint));
printk("\n++%d,%d,%d\n",startpoint[0],startpoint[1],IdxBottom);
}
IdxBottom++;
if( IdxBottom >= KEY_BUF_SIZE )
IdxBottom = 0;
goto finished;
release:
printk("--%d,%d,%d\n", curpoint[0], curpoint[1],IdxBottom);
for(i=0;i<KEY_BUF_SIZE;++i)
printk("%d,%d\n",keybuffer[i].x,keybuffer[i].y);
i = IdxBottom -1;
if(i<=-1)
i = KEY_BUF_SIZE -1;
startpoint[0]-=keybuffer[i].x;
startpoint[1]-=keybuffer[i].y;
//Put your gesture function here!!!!
/*if(( startpoint[1]<-50) || (startpoint[1]>50))
printk(KERN_ERR "ts_iic_workqueue okokokokokokokokok\n");*/
// Key input
if (Cyio_PushEvent('R', 1) >= 0)
{
Cyio_PushEvent( (keybuffer[0].x >> 8) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].x >> 0) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].y >> 8) & 0xFF, 0 );
Cyio_PushEvent( (keybuffer[0].y >> 0) & 0xFF, 0 );
}
memset(keybuffer,0x0,sizeof(keybuffer));
memset(startpoint,0x0,sizeof(startpoint));
IdxBottom = 0;
emptyKeyBuffer = TRUE;
//Key input
ts_iic->xp =ts_iic->yp = 0;
#ifdef USE_BUFFERED_TOUCH_DATA
IsPanelPressed = 0;
#endif
input_report_key(ts_iic->dev, BTN_TOUCH, 0);
input_report_abs(ts_iic->dev, ABS_PRESSURE,0);
input_sync(ts_iic->dev);
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPH12, S3C2410_GPH12_OUTP);
s3c2410_gpio_setpin(S3C2410_GPH12, 0);
#endif
#ifdef NEW_TCOM_BOARD
prevpoint[0]=0;
prevpoint[1]=0;
zeroCount = 0;
#endif
del_timer(&touch_iic_timer_qisda);
enable_irq(IRQ_EINT2);
//touch_iic_clear_interrupt_pending();
//touch_iic_enable_interrupt();
return;
finished:
//msleep(15);
touch_iic_timer_qisda.expires = jiffies + (HZ/ts_iic->polling_time);
mod_timer(&touch_iic_timer_qisda,touch_iic_timer_qisda.expires);
return;
#endif
//Qisda Tony 090415 ]
}
//static void ts_iic_port_deinit(void)
//{
//}
//Qisda Tony 090415 [
#ifndef POLLING_MODE
static irqreturn_t touch_iic_isr(int irq, void *dev_id)
{
//static int count=0;
printk(KERN_ERR "\ntouch_iic_isr\n");
disable_irq(IRQ_EINT2);
#ifdef CPU_SLEEP_PREVENT
g_wakeup_event_occurs = 1;
//printk("touch_iic_isr: set g_wakeup_event_occurs\n");
#endif
//touch_iic_disable_interrupt();
//touch_iic_clear_interrupt_pending();
touch_iic_timer_qisda.expires = jiffies + (HZ/ts_iic->polling_time);
add_timer(&touch_iic_timer_qisda);
//It wait for kernel timer launch.
//schedule_work(&workq_readdata);
//Enable interrupt funciton will postphone at workqueue stage
//touch_iic_enable_interrupt();
return IRQ_HANDLED;
}
#endif
//Qisda Tony 090415 ]
static int s3c_ts_iic_open(struct inode *inode, struct file *file)
{
return 0;
}
/* Qisda, howard hsu, 2010/01/27, touch firmware update { */
#define NORMAL_SLAVE_ADDR 0x5C
#define BOOTLOADER_SLAVE_ADDR 0x5D
#define OPCODE_INIT 0
#define OPCODE_USER 1
#define OPCODE_AES 2
#define OPCODE_EEPROM 3
#define OPCODE_QUERY 8
typedef struct BLModeInfo {
char Status;
char FlashLock;
char Version;
char Key;
} __attribute__((packed)) BLModeInfo;
int normalmode_read_eeprom(unsigned int eepr_addr, unsigned char *buff)
{
unsigned char tmp[4];
struct i2c_msg msg;
unsigned long nmsgs;
int ret=0;
tmp[0]=120;
tmp[1]=0x01;//read
tmp[2]=(eepr_addr&0xFF);
tmp[3]=eepr_addr>>8;
nmsgs=1;
msg.len=4; //mem address
msg.addr=NORMAL_SLAVE_ADDR;
msg.flags=0;
msg.buf=tmp;
ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs);
nmsgs=1;
msg.len=1; //mem address
msg.addr=NORMAL_SLAVE_ADDR;
msg.flags=I2C_M_RD;
msg.buf=buff;
ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs);
if(ret<0)
printk("normalmode_read_eeprom error code:%d\n",ret);
return ret;
}
int normalmode_read_op(unsigned int mem_addr,unsigned char *buff)
{
unsigned char tmp[2];
struct i2c_msg msg[2];
unsigned long nmsgs;
int ret=0;
tmp[0]=mem_addr;
//tmp[0]=mem_addr;
//tmp[1]=val;
nmsgs=2;
msg[0].len=1; //mem address
msg[0].addr=NORMAL_SLAVE_ADDR;
msg[0].flags=0;
msg[0].buf=tmp;
msg[1].len=1;
msg[1].addr=NORMAL_SLAVE_ADDR;
msg[1].flags=I2C_M_RD;
msg[1].buf=buff;
ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs);
if(ret<0)
printk("[normalmode_read_op] error:%d\n",ret);
else
printk("[normalmode_read_op] ok addr:%d value:%d\n",mem_addr,buff[0]);
return ret;
}
int normalmode_write_op(unsigned char mem_addr,unsigned char val)
{
unsigned char tmp[2];
struct i2c_msg msg;
unsigned long nmsgs;
int ret=0;
tmp[0]=mem_addr;
tmp[1]=val;
nmsgs=1;
msg.len=2; //mem address
msg.addr=NORMAL_SLAVE_ADDR;
msg.flags=0;
msg.buf=tmp;
ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs);
if(ret<0)
printk("[normalmode_write_op] error:%d\n",ret);
else
printk("[normalmode_write_op] ok addr:%d value:%d\n",mem_addr,val);
return ret;
}
int blmode_read_op(int opcode)
{
struct i2c_msg msg;
unsigned long nmsgs;
int ret=0;
BLModeInfo *bl_info = vmalloc(sizeof(BLModeInfo));
nmsgs = 1;
msg.addr = BOOTLOADER_SLAVE_ADDR;
msg.flags= I2C_M_RD; //0 for write
msg.len = 4;
msg.buf = bl_info;
ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs);
if(ret<0)
{
printk("[blmode_read_op] error:%d\n",ret);
}
else
{
printk("[blmode_read_op] ok:[%x][%x][%x][%x]\n",bl_info->Status,bl_info->FlashLock,bl_info->Version,bl_info->Key);
if ( (bl_info->Status&0x80) != 0) {
ret = -8;
}
else {
if (opcode==OPCODE_AES)
{
if(bl_info->FlashLock==0x00)
printk("=Flash is locked\n");
else if (bl_info->FlashLock==0x05)
printk("=Flash verified failed\n");
else if (bl_info->FlashLock==0xFF)
printk("=Flash is erased\n");
else if (bl_info->FlashLock==0xA5)
printk("=Flash is unlocked\n");
else
printk("=Flash status Unknown(%x)\n",bl_info->FlashLock);
}
}
}
return ret;
}
int blmode_write_op(char *data_ptr)
{
struct i2c_msg msg;
unsigned long nmsgs;
int ret=0;
nmsgs = 1;
msg.addr = BOOTLOADER_SLAVE_ADDR;
msg.flags= 0;
msg.len = 143;
msg.buf = data_ptr;
ret = i2c_transfer(ts_iic->client->adapter, &msg, nmsgs);
if(ret<0)
{
printk("blmode_write_op error:%d\n",ret);
}
else
{
ret = data_ptr[0];
printk("opcode[%d] OK\n",data_ptr[0]);
}
return ret;
}
int blmode_wait_ready()
{
unsigned int pin_state;
int count = 0;
int ret =0;
do {
pin_state = (__raw_readl(S3C2410_GPFDAT)&(1<<2));
count++;
msleep(20);
} while((pin_state!=0)&&(count<100)); //wait for 2 seconds
//printk("[blmode_wait_ready]count=%d pin=%d\n",count,pin_state);
ret = (pin_state==0)? 0:1;
return ret;
}
int get_touch_firmware_info(char *buff)
{
/* read version */
normalmode_read_op(119,buff);
}
int enter_blmode (int method)
{
disable_irq(IRQ_EINT2);
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
s3c2410_gpio_pullup(S3C2410_GPF2, 0);
if( method==0 )
{
printk("TP:HW_blmode entry\n");
//turn-off
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 0);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 0);
#endif
msleep(2000);
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 1);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 1);
#endif
//s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
//s3c2410_gpio_pullup(S3C2410_GPF2, 0);
blmode_read_op(OPCODE_QUERY);
blmode_wait_ready();
blmode_read_op(OPCODE_QUERY);
}
else
{
printk("TP:SW_blmode entry\n");
msleep(100);
normalmode_write_op(120,5);
blmode_read_op(OPCODE_QUERY);
blmode_wait_ready();
blmode_read_op(OPCODE_QUERY);
}
}
int reset_touch()
{
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 0);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 0);
#endif
//s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP); //?smart card
//s3c2410_gpio_setpin(S3C2410_GPC3, 0);
msleep(2000);
//on
//s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
//s3c2410_gpio_pullup(S3C2410_GPF2, 2);
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 1);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 1);
#endif
msleep(400);
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL);
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
enable_irq(IRQ_EINT2);
msleep(100);
}
int update_touch_firmware(unsigned long size, char* frame_data)
{
unsigned int pin_state;
int count, count_max;
int opcode, result;
int i;
unsigned long offset = 0;
/*
disable_irq(IRQ_EINT2);
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
s3c2410_gpio_pullup(S3C2410_GPF2, 0);
msleep(100);
normalmode_write_op(120,5);
blmode_wait_ready();
blmode_read_op(OPCODE_QUERY);
*/
enter_blmode(0);
char *cmd_buff = vmalloc(143, GFP_KERNEL);
char *data_ptr = frame_data;
unsigned long limit = frame_data + size;
char *p_head;
char *p_tail;
count = 0;
do {
p_head = strchr(data_ptr,'$');
if ( (p_head != NULL)&& (p_tail<limit) )
{
p_tail = strchr(p_head+1,0xd);
if( (p_tail!=NULL) && (p_tail<limit))
{
printk("p_head=%lu p_tail=%lu \n",p_head, p_tail);
unsigned long length = p_tail - p_head;
p_head++;
if(length!=287)
goto FAIL;
char tmpToken[3];
memset( tmpToken, 0, sizeof(tmpToken) );
for(i=0;i<143;i++)
{
strncpy( tmpToken, p_head+i*2, 2 );
sprintf( cmd_buff+i, "%c", simple_strtol( tmpToken,NULL,16) );
}
count++;
printk("OpCode[%2x] CRC[%2x][%2x]\n",cmd_buff[0],cmd_buff[141],cmd_buff[142]);
opcode = blmode_write_op(cmd_buff);
printk("[blmode_write_op][%d]=%d\n",count,opcode);
if ( opcode < 0) {
goto FAIL;
}
if ( opcode!= OPCODE_USER)
{
if( blmode_wait_ready() != 0)
goto FAIL_BUSY;
result = blmode_read_op(opcode);
printk("[blmode_read_op]=%d\n",result);
if (result<0)
goto FAIL;
}
data_ptr = p_tail+1;
if( data_ptr > (limit-280) )
{
printk("end of file,stop\n");
printk("curr:%lu limit:%lu\n",data_ptr,limit);
p_head=0;
}
}
else
{
p_head=0;
}
}
printk("==p_head=%lu\n",p_head);
} while(p_head!=0);
vfree(cmd_buff);
/* printk("restore EINT\n");
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
enable_irq(IRQ_EINT2);
msleep(100); */
reset_touch();
return 0;
FAIL_BUSY:
printk("[FAIL]Dev is Busy\n");
FAIL:
return -1;
}
/* } Qisda, howard hsu, 2010/01/27, touch firmware update */
/*******************************/
/****** GPF2 => TP_INT ******/
/****** GPF5 => TOUCH_EN ******/
/*** GPC3 => T-Sensor Power ***/
/*******************************/
static int s3c_ts_iic_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd){
case TOUCH_IIC_CALIBRATION:
#ifdef POLLING_MODE
need_calibration = TRUE;
#else
printk("TOUCH_IIC_CALIBRATION...");
disable_irq(IRQ_EINT2);
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_CALIBRATION, NULL);
printk("done\n");
enable_irq(IRQ_EINT2);
#endif
break;
case TOUCH_IIC_SET_POLLING_TIME:
if((arg<1) || (arg>80)){
printk("polling time should be 1-80\n");
}
else{
ts_iic->polling_time = arg;
touchPollingTime = arg;
}
break;
/*kit.mod 2009/11/04*/
case TOUCH_DEVICE_POWER_STATE:
switch(arg)
{
case TOUCH_DEVICE_ACTIVE_STATE:
if(isTouchPowerOff)
{
isTouchPowerOff = 0;
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 1);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 1);
#endif
msleep(200);
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT, NULL);
/*kit.add 2010/01/20, for turn on TP_INT(GPF2) power*/
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
/*kit.end*/
enable_irq(IRQ_EINT2);
}
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_ACTIVE_MODE, NULL);
/*kit.add 2009/11/16*/
ts_iic->polling_time = touchPollingTime;
touchPowerState = TOUCH_DEVICE_ACTIVE_STATE;
/*kit.end*/
printk("Touch Device => Active State\n");
break;
case TOUCH_DEVICE_SLEEP_STATE:
if(isTouchPowerOff)
{
isTouchPowerOff = 0;
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 1);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 1);
#endif
msleep(200);
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL);
/*kit.add 2010/01/20, for turn on TP_INT(GPF2) power*/
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
/*kit.end*/
enable_irq(IRQ_EINT2);
}
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_SLEEP_MODE, NULL);
/*kit.add 2009/11/16*/
ts_iic->polling_time = TOUCH_SLEEP_POLLING_TIME;
touchPowerState = TOUCH_DEVICE_SLEEP_STATE;
/*kit.end*/
printk("Touch Device => Sleep State\n");
break;
case TOUCH_DEVICE_DEEPSLEEP_STATE:
if(isTouchPowerOff)
{
isTouchPowerOff = 0;
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 1);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 1);
#endif
msleep(200);
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL);
/*kit.add 2010/01/20, for turn on TP_INT(GPF2) power*/
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
/*kit.end*/
enable_irq(IRQ_EINT2);
}
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_DEEPSLEEP_MODE, NULL);
/*kit.add 2009/11/16*/
ts_iic->polling_time = TOUCH_DEEPSLEEP_POLLING_TIME;
touchPowerState = TOUCH_DEVICE_DEEPSLEEP_STATE;
/*kit.end*/
printk("Touch Device => Deep Sleep State\n");
break;
case TOUCH_DEVICE_POWEROFF_STATE:
if(isTouchPowerOff)
printk("Touch Device => Already Power Off State\n");
else
{
isTouchPowerOff = 1;
disable_irq(IRQ_EINT2);
/*kit.add 2010/01/20, turn off TP_INT(GPF2) power*/
/*test1: TP_INT(GPF2) => Input, Disable*/
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
s3c2410_gpio_pullup(S3C2410_GPF2, 0);
/*test2: TP_INT(GPF2) => Input, Pull Low*/
//s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
//s3c2410_gpio_setpin(S3C2410_GPF2, 1);
/*kit.end*/
/*Turn off touch power(TOUCH_EN)*/
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 0);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 0);
#endif
printk("Touch Device => Power Off State\n");
}
/*kit.add 2009/11/16*/
touchPowerState = TOUCH_DEVICE_POWEROFF_STATE;
/*kit.end*/
break;
default:
printk("Touch Device => No Such Power State...\n");
}
break;
/*kit.end*/
/* Qisda, howard hsu, 2010/01/27, TOUCH firmware update { */
case TOUCH_IIC_FW_UPDATE:
{
printk("Call TOUCH_IIC_FW_UPDATE\n");
unsigned long fw_size = 0;
int result = 0;
if(copy_from_user(&fw_size, (unsigned long*) arg, sizeof(unsigned long)))
return -EFAULT;
unsigned char *fw_data = vmalloc(fw_size, GFP_KERNEL);
if(copy_from_user(fw_data, (char*) ((char *)arg+sizeof(unsigned long)), fw_size))
return -EFAULT;
printk("FW_Size=%d\n",fw_size);
result = update_touch_firmware(fw_size,fw_data);
printk("TOUCH_IIC_FW_UPDATE Complete(result=%d)!!!\n",result);
vfree(fw_data);
return result;
}
break;
case TOUCH_IIC_GET_FW_INFO:
{
char info = 0;
get_touch_firmware_info(&info);
if(copy_to_user((void *)arg, (const void *) &info, sizeof(char)))
return -EFAULT;
}
break;
/* } Qisda, howard hsu, 2010/01/27, TOUCH firmware update */
/*kit.add 2010/01/30*/
case TOUCH_IIC_T_SENSOR_ENABLE:
{
switch(arg)
{
case 0:
s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
s3c2410_gpio_setpin(S3C2410_GPC3, 0);
printk("T-Sensor power off\n");
break;
case 1:
s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
s3c2410_gpio_setpin(S3C2410_GPC3, 1);
printk("T-Sensor power on\n");
break;
default:
printk("T-Sensor no such command\n");
break;
}
}
break;
/*kit.end*/
default:
printk("No such command\n");
}
return 0;
}
/* File operations struct for character device */
static const struct file_operations s3c_ts_iic_fops = {
.owner = THIS_MODULE,
.ioctl = s3c_ts_iic_ioctl,
.open = s3c_ts_iic_open,
.release = NULL
};
int s3c_ts_iic_port_init(struct i2c_client *c)
{
int err = 0;
ts_iic->client = c;
err = c->driver->command(c,QISDA_IIC_INIT,NULL);
if(err<0){
printk("Touch init faied\n");
goto fail;
}
//touch_iic_init();
//touch_iic_port_initialize();
//Qisda Tony 090415 [
#ifdef POLLING_MODE
#ifdef KTHREAD_USE
init_waitqueue_head(&wait);
kmain_task = kthread_create(ts_iic_workqueue, NULL,"ts_iic_kthread");
wake_up_process(kmain_task);
#else
init_timer(&touch_iic_timer_qisda);
touch_iic_timer_qisda.function =touhc_iic_timer_handler_qisda;
//touch_iic_timer_qisda.data;
touch_iic_timer_qisda.expires = jiffies + 10*HZ;
add_timer(&touch_iic_timer_qisda);
#endif
#else //NOT POLLING_MODE
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
#ifndef KTHREAD_USE
init_timer(&touch_iic_timer_qisda);
touch_iic_timer_qisda.function =touhc_iic_timer_handler_qisda;
#endif
set_irq_type(IRQ_EINT2, S3C2410_EXTINT_FALLEDGE);
err = request_irq(IRQ_EINT2, touch_iic_isr, SA_INTERRUPT, DEVICE_NAME, (void *) ts_iic->pdev);
if (err) {
printk("request_irq failed (IRQ_EINT2) !!!\n");
free_irq(IRQ_EINT2, ts_iic->dev);
//ts_iic_port_deinit();
goto fail;
}
//touch_iic_clear_interrupt_pending();
//touch_iic_enable_interrupt();
#endif //End of NOT POLLING_MODE
memset(keybuffer,0x0,sizeof(keybuffer));
//Qisda Tony 090415 ]
if (register_chrdev (TOUCH_MAJOR, "touch_cmd", &s3c_ts_iic_fops)) {
printk("unable to get major %d\n", TOUCH_MAJOR);
}
printk("s3c_ts_iic_port_init is initialized!!\n");
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_pullup(S3C2410_GPD10, 2);
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10,1);
#else
s3c2410_gpio_pullup(S3C2410_GPF5, 2);
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5,1);
#endif
/*Qisda Qube for open smartcard pwr*/
#if defined (CONFIG_QISDA_AS090B00_EVT1) || defined (CONFIG_QISDA_AS090B00_EVT1_1)
s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
/*kit.mod 2009/12/25*/
s3c2410_gpio_setpin(S3C2410_GPC3, 0);
/*kit.end*/
#endif
/*Qisda Qube for open smartcard pwr*/
return 0;
fail:
platform_driver_unregister(&s3c_ts_iic_driver);
input_free_device(ts_iic->dev);
kfree(ts_iic);
return -EIO;
}
static int __init s3c_ts_iic_probe(struct platform_device *pdev)
{
struct input_dev *input_dev;
int err;
//Tony test
#ifdef QISDA_TEST_GPIO_PROBE
g_pGPIOReg_GPFCON = ioremap(0x56000050, 0x00100000);
writel(readl(g_pGPIOReg_GPFCON) | (0x1<<0), g_pGPIOReg_GPFCON);
writel(readl(g_pGPIOReg_GPFCON+0x04) | (0x1<<0), g_pGPIOReg_GPFCON+0x04);
writel(readl(g_pGPIOReg_GPFCON+0x08) | (0x2<<0), g_pGPIOReg_GPFCON+0x08);
#endif
ts_iic = kzalloc(sizeof(struct s3c_ts_iic), GFP_KERNEL);
input_dev = input_allocate_device();
if (!input_dev) {
err = -ENOMEM;
goto fail;
}
ts_iic->dev = input_dev;
ts_iic->dev->evbit[0] = ts_iic->dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
ts_iic->dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(ts_iic->dev, ABS_X, 0, 0xFFF, 0, 0);
input_set_abs_params(ts_iic->dev, ABS_Y, 0, 0xFFF, 0, 0);
input_set_abs_params(ts_iic->dev, ABS_PRESSURE, 0, 1, 0, 0);
ts_iic->dev->private = ts_iic;
ts_iic->dev->name = s3c_ts_iic_name;
ts_iic->dev->id.bustype = BUS_I2C;
ts_iic->dev->id.vendor = 0xDEAD;
ts_iic->dev->id.product = 0xBEEF;
ts_iic->dev->id.version = 0x0010;
platform_set_drvdata(pdev, ts_iic);
/* All went ok, so register to the input system */
err = input_register_device(ts_iic->dev);
if(err) {
goto fail;
}
ts_iic->pdev = pdev;
ts_iic->polling_time = 20;
INIT_WORK(&workq_readdata,ts_iic_workqueue);
//However, stop interrupt first. This is because the signal is emitted from the panel repeatedly
//Unless we set the interrupt mode of the the panel to stop emitting.
//touch_iic_disable_interrupt();
//printk("s3c_ts_iic_probe IRQ is initialized!!\n");
// touch panel enable in common-smdk.c
//writel((readl(S3C2416_GPKCON) & ~(1<<5) | (1<<4)), S3C2416_GPKCON);
//writel((readl(S3C2416_GPKDAT) | (1<<2)), S3C2416_GPKDAT);
return 0;
fail:
input_free_device(input_dev);
kfree(ts_iic);
return -EIO;
}
static int s3c_ts_iic_remove(struct platform_device *dev)
{
return 0;
}
#ifdef CONFIG_PM
static int s3c_ts_iic_suspend(struct platform_device *dev, pm_message_t state)
{
/*kit.add 2010/01/06, turn off Tilt-Sensor power*/
s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
s3c2410_gpio_setpin(S3C2410_GPC3, 0);
/*kit.end*/
/*kit.test 2010/01/30, turn off SPI_INT power*/
s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_INP);
s3c2410_gpio_pullup(S3C2410_GPF3, 0); /* pull-up/down disable */
/*kit.end*/
/*kit.add 2009/11/04*/
if(wkup_srce == 1)
{
printk("\nTouch Suspend: Add touch to wakeup source, do not turn off touch power...\n");
}
//else if(wkup_srce == 0)
else
{
if(!isTouchPowerOff)
{
printk("\nTouch Suspend: Do not add touch to wakeup source, turn off touch power...\n");
disable_irq(IRQ_EINT2);
/*kit.add 2010/01/20, turn off TP_INT(GPF2) power*/
/*test1: TP_INT(GPF2) => Input, Disable*/
//s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
//s3c2410_gpio_pullup(S3C2410_GPF2, 0);
/*test2: TP_INT(GPF2) => Input, Pull Low*/
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP);
s3c2410_gpio_setpin(S3C2410_GPF2, 1);
/*kit.end*/
/*turn off TOUCH_EN power*/
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 0);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 0);
#endif
}
}
/*kit.end*/
#ifdef USE_BUFFERED_TOUCH_DATA
go_in_suspend = 1;
#endif
return 0;
}
static int s3c_ts_iic_resume(struct platform_device *pdev)
{
/*kit.add 2010/01/06, for Tilt-Sensor power*/
s3c2410_gpio_cfgpin(S3C2410_GPC3, S3C2410_GPC3_OUTP);
s3c2410_gpio_setpin(S3C2410_GPC3, 1);
/*kit.end*/
/*kit.test 2010/01/30, for SPI_INT power*/
s3c2410_gpio_cfgpin(S3C2410_GPF3, S3C2410_GPF3_EINT3);
s3c2410_gpio_pullup(S3C2410_GPF3, 2); /* pull-up enable */
/*kit.end*/
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT, NULL);
/*kit.add 2009/11/04*/
if(wkup_srce == 1)
{
printk("\nTouch Resume: Touch is wakeup source\n");
}
//else if(wkup_srce == 0)
else
{
printk("\nTouch Resume: Touch is not wakeup source, turn on touch power and enable IRQ...\n");
if(!isTouchPowerOff)
{
/*turn on TOUCH_EN power*/
#ifdef CONFIG_QISDA_BK060B00
s3c2410_gpio_cfgpin(S3C2410_GPD10, S3C2410_GPD10_OUTP);
s3c2410_gpio_setpin(S3C2410_GPD10, 1);
#else
s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_setpin(S3C2410_GPF5, 1);
#endif
msleep(200);
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_INIT,NULL);
/*kit.add 2010/01/20, config TP_INT(GPF2) to interrupt*/
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 2);
/*kit.end*/
enable_irq(IRQ_EINT2);
switch(touchPowerState)
{
case TOUCH_DEVICE_ACTIVE_STATE:
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_ACTIVE_MODE, NULL);
ts_iic->polling_time = touchPollingTime;
touchPowerState = TOUCH_DEVICE_ACTIVE_STATE;
break;
case TOUCH_DEVICE_SLEEP_STATE:
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_SLEEP_MODE, NULL);
ts_iic->polling_time = TOUCH_SLEEP_POLLING_TIME;
touchPowerState = TOUCH_DEVICE_SLEEP_STATE;
break;
case TOUCH_DEVICE_DEEPSLEEP_STATE:
ts_iic->client->driver->command(ts_iic->client, QISDA_IIC_DEEPSLEEP_MODE, NULL);
ts_iic->polling_time = TOUCH_DEEPSLEEP_POLLING_TIME;
touchPowerState = TOUCH_DEVICE_DEEPSLEEP_STATE;
break;
case TOUCH_DEVICE_POWEROFF_STATE:
touchPowerState = TOUCH_DEVICE_DEEPSLEEP_STATE;
break;
default:
break;
}
}
}
/*kit.end*/
return 0;
}
#else
#define s3c_ts_iic_suspend NULL
#define s3c_ts_iic_resume NULL
#endif
static struct platform_driver s3c_ts_iic_driver = {
.probe = s3c_ts_iic_probe,
.remove = s3c_ts_iic_remove,
.suspend = s3c_ts_iic_suspend,
.resume = s3c_ts_iic_resume,
.driver = {
.owner = THIS_MODULE,
.name = DEVICE_NAME,
},
};
//static char banner[] __initdata = KERN_INFO "Touchscreen driver Of IIC type for Qisda\n";
static int __init s3c_ts_iic_init(void) { return platform_driver_register(&s3c_ts_iic_driver); }
static void __exit s3c_ts_iic_exit(void){ platform_driver_unregister(&s3c_ts_iic_driver); }
module_init(s3c_ts_iic_init);
module_exit(s3c_ts_iic_exit);
MODULE_AUTHOR("Tony.YC.Huang@qisda.com");
MODULE_DESCRIPTION("Touchscreen driver Of IIC type for Qisda");
MODULE_LICENSE("GPL");
//Qisda Tony 090406, add Auo touch i2c driver ]