1604 lines
46 KiB
C
1604 lines
46 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 ]
|