From 6baded1e990165921ec84d000ac0cbb842a5bab4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=82=93=E8=AE=AD=E9=87=91?= Date: Mon, 23 Aug 2010 20:08:31 +0800 Subject: [PATCH] add touchscreen ctp_it7250 --- drivers/input/touchscreen/Kconfig | 11 +- drivers/input/touchscreen/Makefile | 3 +- drivers/input/touchscreen/ctp_it7250.c | 1083 ++++++++++++++++++++++++ 3 files changed, 1095 insertions(+), 2 deletions(-) create mode 100644 drivers/input/touchscreen/ctp_it7250.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 4c712f5542ff..7e3975d83845 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -92,7 +92,16 @@ config TOUCHSCREEN_XPT2046_320X480_CBN_SPI If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the - module will be called xpt2046_cbn_ts. + module will be called xpt2046_cbn_ts. + +config TOUCHSCREEN_IT7250 + tristate "IT7250 based touchscreens: IT7250 Interface" + help + Say Y here if you have a touchscreen interface using the + xpt2046 controller, and your board-specific initialization + code includes that in its table of SPI devices. + + If unsure, say N (but it's safe to say "Y"). config TOUCHSCREEN_AD7879_I2C tristate "AD7879 based touchscreens: AD7879-1 I2C Interface" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index a34f0b533ab0..e865ae66fc46 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -46,4 +46,5 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_XPT2046_SPI) += xpt2046_ts.o obj-$(CONFIG_TOUCHSCREEN_XPT2046_CBN_SPI) += xpt2046_cbn_ts.o calibration_ts.o largenum_ts.o obj-$(CONFIG_TOUCHSCREEN_XPT2046_320X480_SPI) += xpt2046_ts_320X480.o -#obj-$(CONFIG_TOUCHSCREEN_XPT2046_320X480_CBN_SPI) += xpt2046_cbn_ts.o calibration_ts.o largenum_ts.o \ No newline at end of file +#obj-$(CONFIG_TOUCHSCREEN_XPT2046_320X480_CBN_SPI) += xpt2046_cbn_ts.o calibration_ts.o largenum_ts.o +obj-$(CONFIG_TOUCHSCREEN_IT7250) += ctp_it7250.o diff --git a/drivers/input/touchscreen/ctp_it7250.c b/drivers/input/touchscreen/ctp_it7250.c new file mode 100644 index 000000000000..cc979aa319e6 --- /dev/null +++ b/drivers/input/touchscreen/ctp_it7250.c @@ -0,0 +1,1083 @@ +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +extern void rk2818_mux_api_set(char *name, unsigned int mode); +extern int lp8725_ldo_en(uint8_t ldo,uint8_t enble); +extern int lp8725_set_ldo_vol(uint8_t ldon,uint16_t vol); +extern int lp8725_set_lilo_vol(uint8_t lilon,uint16_t vol); +extern int lp8725_lilo_en(uint8_t lilon,uint8_t enble); + + +struct Ctp_it7250_data { + char status; + char curr_tate; + struct input_dev *input_dev; + struct i2c_client *client; + struct delayed_work delaywork; + int irq; /* Our chip IRQ */ +}; +static struct i2c_client *Ctp_it7250_client; + +#define Ctp_it7250_GPIO_INT RK2818_PIN_PE1 + +#if 0 +#define rk28printk(x...) printk(x) +#else +#define rk28printk(x...) +#endif + + struct KeyInfo +{ + int value; + int key; +}; + +static struct KeyInfo panel_key_info[]={ +{0x01, KEY_HOME}, +{0x02, KEY_MENU}, +{0x03, KEY_BACK}, +{0x04, KEY_SEARCH}, +}; + +#define MAX_FINGER_NUM 3 +//#define DEVICE_ADDRESS 0x8C +#define COMMAND_BUFFER_INDEX 0x20 +#define QUERY_BUFFER_INDEX 0x80 +#define COMMAND_RESPONSE_BUFFER_INDEX 0xA0 +#define POINT_BUFFER_INDEX 0xE0 +#define QUERY_SUCCESS 0x00 +#define QUERY_BUSY 0x01 +#define QUERY_ERROR 0x02 +#define QUERY_POINT 0x80 + + +static u8 gpucPointBuffer[14]; +static u32 gpdwSampleX[3],gpdwSampleY[3],gpdwPressure[1]; + +static int Ctp_it7250_rx_data( u8 reg,u8* rxData, int length) +{ +#if 0 + + int ret; + struct i2c_adapter *adap;int i; + struct i2c_msg msgs[2]; + if(!Ctp_it7250_client) + return ret; + adap = Ctp_it7250_client->adapter; + + //·¢ËͼĴæÆ÷µØÖ· + msgs[0].addr = Ctp_it7250_client->addr; + msgs[0].buf = ® + msgs[0].flags = Ctp_it7250_client->flags; + msgs[0].len =1; + msgs[0].scl_rate = 400*1000; + //½ÓÊÕÊý¾Ý + +// rk28printk("i2c addr=0x%x \r\n",msgs[0].addr); + // rk28printk("msgs[0].buf = 0x%x rxData=0x%x\n",*(msgs[0].buf),*rxData); + + msgs[1].buf = rxData; + msgs[1].addr = Ctp_it7250_client->addr; + msgs[1].flags = Ctp_it7250_client->flags | I2C_M_RD; + msgs[1].len = length; + msgs[1].scl_rate = 400*1000; + + ret = i2c_transfer(adap, msgs, 2); + //DBG("**has run at %s %d ret=%d**\n",__FUNCTION__,__LINE__,ret); +// rk28printk("\r\n msgs[1].buf = 0x%x ret=%d\n",*(msgs[1].buf),ret); + + + //for (i=0;iadapter; + struct i2c_msg msg; + + u8 buf[128];//128 +// rk28printk("reg=0x%x txData=0x%x \r\n",reg,*txData); + buf[0]=reg; + for (i=0;iaddr; +//rk28printk("i2c addr=0x%x",msg.addr); + msg.buf =&buf[0]; + msg.len = length+1;//+1 means add the reg length;by roberts + msg.flags = Ctp_it7250_client->flags; + msg.scl_rate = 400*1000; + + ret = i2c_transfer(adap, &msg, 1); +return ret; +#else + return i2c_master_reg8_send(Ctp_it7250_client, reg, txData, length, 400 * 1000); +#endif + + + + +} + + + +bool ReadQueryBuffer(u8* pucData) +{ + return Ctp_it7250_rx_data( QUERY_BUFFER_INDEX, pucData, 1); +} + +bool ReadCommandResponseBuffer(u8* pucData, unsigned int unDataLength) +{ + return Ctp_it7250_rx_data( COMMAND_RESPONSE_BUFFER_INDEX, pucData, unDataLength); +} + +bool ReadPointBuffer(u8* pucData) +{ + return Ctp_it7250_rx_data( POINT_BUFFER_INDEX, pucData, 14); +} + +bool WriteCommandBuffer(u8* pucData, unsigned int unDataLength) +{ + return Ctp_it7250_tx_data(COMMAND_BUFFER_INDEX, pucData, unDataLength); +} + +static int Ctp_it7250_touch_open(struct input_dev *idev) +{ + +struct Ctp_it7250_data *Ctp_it7250 = (struct Ctp_it7250_data *)i2c_get_clientdata(Ctp_it7250_client); + + +//BTN_TOUCH =0 means no touch ;by robert + input_report_key(Ctp_it7250->input_dev,BTN_TOUCH, 0); + input_sync(Ctp_it7250->input_dev); + + return 0; +} + +static void Ctp_it7250_touch_close(struct input_dev *idev) +{ +return 0; +} + +static irqreturn_t Ctp_it7250_touch_irq(int irq, void *dev_id) +{ + struct Ctp_it7250_data *Ctp_it7250 = dev_id; + + //rk28printk("%s++++ %d \r\n",__FUNCTION__,__LINE__); + disable_irq_nosync(irq); + //rk28printk("%s++++ %d irq=%d\r\n",__FUNCTION__,__LINE__,irq); + schedule_delayed_work(&Ctp_it7250->delaywork,usecs_to_jiffies(5)); + + return IRQ_HANDLED; + +} + + + +static int ts_input_init(struct i2c_client *client) +{ + int ret = -1,i; + struct Ctp_it7250_data *Ctp_it7250; + Ctp_it7250 = i2c_get_clientdata(client); + /* register input device */ + Ctp_it7250->input_dev = input_allocate_device(); + if (Ctp_it7250->input_dev == NULL) { + pr_emerg( "%s: failed to allocate input dev\n", + __FUNCTION__); + return -ENOMEM; + } +rk28printk("+++++++ %s+++++++\n", __FUNCTION__); + Ctp_it7250->input_dev->name = "CTS_Ctp_it7250"; + Ctp_it7250->input_dev->phys = "CTS_Ctp_it7250/input1"; + + //no need to open & close it,it will do it automaticlly;noted by robert + Ctp_it7250->input_dev->open = Ctp_it7250_touch_open; + Ctp_it7250->input_dev->close = Ctp_it7250_touch_close; + + __set_bit(EV_ABS, Ctp_it7250->input_dev->evbit); + __set_bit(ABS_X, Ctp_it7250->input_dev->absbit); + __set_bit(ABS_Y, Ctp_it7250->input_dev->absbit); + + __set_bit(EV_SYN, Ctp_it7250->input_dev->evbit); + __set_bit(EV_KEY, Ctp_it7250->input_dev->evbit); + __set_bit(BTN_TOUCH, Ctp_it7250->input_dev->keybit); + +for (i = 0; i < ARRAY_SIZE(panel_key_info); i++) +{rk28printk("ts_input_init i=%d\r\n",i); + __set_bit(panel_key_info[i].key,Ctp_it7250->input_dev->keybit); +} + //__clear_bit(0, input_dev->keybit); + + input_set_abs_params(Ctp_it7250->input_dev, ABS_X, 0, 1000, 0, 0); + input_set_abs_params(Ctp_it7250->input_dev, ABS_Y, 0, 1000, 0, 0); +//pr_emerg("+++++++ %s\n", __FUNCTION__); + ret = input_register_device(Ctp_it7250->input_dev); + if (ret) { + pr_emerg( + "%s: unabled to register input device, ret = %d\n", + __FUNCTION__, ret); + return ret; + } + rk28printk("+++++++ %s+++++++END\n", __FUNCTION__); + return 0; + +} + +static void CTS_configure_pin(struct i2c_client *client) +{ + //add reset pin;but we not used it ;robert + //had already do it it spi_gpio.c + //end add + //RESET THE CTP;note by robert + spi_gpio_set_pinlevel(SPI_GPIO_P2_15, SPI_GPIO_HIGH); + mdelay(5); + spi_gpio_set_pinlevel(SPI_GPIO_P2_15, SPI_GPIO_LOW); + mdelay(5); + spi_gpio_set_pinlevel(SPI_GPIO_P2_15, SPI_GPIO_HIGH); + mdelay(5); +} + +static int Ctp_it7250_init_irq(struct i2c_client *client) +{ + struct Ctp_it7250_data *Ctp_it7250; + int ret; + + Ctp_it7250 = i2c_get_clientdata(client); + #if 1 + if ( !gpio_is_valid(client->irq)) { + rk28printk("+++++++++++gpio_is_invalid\n"); + return -EINVAL; + } + ret = gpio_request(client->irq, "Ctp_it7250_int"); + if (ret) { + rk28printk( "failed to request Ctp_it7250_init_irq GPIO%d\n",gpio_to_irq(client->irq)); + return ret; + } +#if 1 +ret = gpio_direction_input(client->irq); + if (ret) { + rk28printk("failed to set CTS_configure_pin gpio input\n"); + //goto err_free_gpio; + } + gpio_pull_updown(client->irq,GPIOPullUp); +#endif + + rk28printk("%s gpio_to_irq(%d) is %d\n",__FUNCTION__,client->irq,gpio_to_irq(client->irq)); + + client->irq = gpio_to_irq(client->irq); + #endif + ret = request_irq(client->irq, Ctp_it7250_touch_irq, IRQF_TRIGGER_LOW, client->dev.driver->name, Ctp_it7250); + Ctp_it7250->irq=client->irq; + rk28printk("%s request irq is %d,irq1 is %d,ret is 0x%x\n",__FUNCTION__,client->irq,Ctp_it7250->irq,ret); + if (ret ) { + rk28printk(KERN_ERR "Ctp_it7250_init_irq: request irq failed,ret is %d\n",ret); + return ret; + } + +} + + +// ================================================================================ +// Function Name --- GetFirmwareInformation +// Description --- Get firmware information +// Input --- NULL +//Output --- return true if the command execute successfully, otherwuse return false. +// ================================================================================ +bool GetFirmwareInformation() +{ + u8 ucWriteLength, ucReadLength; + u8 pucData[128]; + u8 ucQuery; +int i; + ucWriteLength = 2; + ucReadLength = 0x09; + pucData[0] = 0x01; + pucData[1] = 0x00; + + // Query + do + { + if(!ReadQueryBuffer(&ucQuery)) + { + ucQuery = QUERY_BUSY; + } + }while(ucQuery & QUERY_BUSY); + + // Write Command + if(!WriteCommandBuffer(pucData, ucWriteLength)) + { + return false; + } + + // Query + do + { + if(!ReadQueryBuffer(&ucQuery)) + { + ucQuery = QUERY_BUSY; + } + }while(ucQuery & QUERY_BUSY); + pucData[5]== 0 ; + pucData[6] == 0 ; + pucData[7] == 0 ; + pucData[8] == 0; + // Read Command Response + if(!ReadCommandResponseBuffer(pucData, ucReadLength)) + { + return false; + } + + + +for (i =0;iinput_dev,BTN_TOUCH, 0); + input_sync(Ctp_it7250->input_dev); + } + else if(dwTouchEvent <=MAX_FINGER_NUM) //CTP_MAX_FINGER_NUMBER) + { + //SynchroSystemEvent(SYSTEM_TOUCH_EVENT_FINGER_ASSERT); + + input_report_abs(Ctp_it7250->input_dev, ABS_X, gpdwSampleX[0]);// & 0xfff + input_report_abs(Ctp_it7250->input_dev, ABS_Y, gpdwSampleY[0]); //& 0xfff + input_report_key(Ctp_it7250->input_dev,BTN_TOUCH, 1); + input_sync(Ctp_it7250->input_dev);rk28printk("x=%d y=%d \r\n",gpdwSampleX[0],gpdwSampleY[0]); + } + else + { + rk28printk("%s SYSTEM_TOUCH_EVENT_PALM_DETECT \r\n",__FUNCTION__); + //SynchroSystemEvent(SYSTEM_TOUCH_EVENT_PALM_DETECT); + } + break; + case 0x80: + dwTouchEvent = CaptouchGetGesture(); + //SynchroSystemEvent(SYSTEM_GESTURE_EVENT); + rk28printk("gesture:0x%x \r\n",dwTouchEvent); + break; + //for keypad below + case 0x40: + rk28printk("ID of button is 0x%x status is 0x%x\r\n",gpucPointBuffer[1],gpucPointBuffer[2]); + switch (gpucPointBuffer[1]) + {case 0x01: + rk28printk("home \r\n"); + if (gpucPointBuffer[2]) + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,1); + else + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,0); + break; + case 0x02: + rk28printk("menu \r\n"); + if (gpucPointBuffer[2]) + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,1); + else + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,0); + break; + case 0x03: + rk28printk("back \r\n"); + if (gpucPointBuffer[2]) + { + rk28printk("back down key=%d\r\n",panel_key_info[(gpucPointBuffer[1]-1)].key); + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,1); + } + else + { + rk28printk("back up key=%d\r\n",panel_key_info[(gpucPointBuffer[1]-1)].key); + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,0); + } + break; + case 0x04: + rk28printk("find \r\n"); + if (gpucPointBuffer[2]) + { + rk28printk("find down key=%d\r\n",panel_key_info[(gpucPointBuffer[1]-1)].key); + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,1); + } + else + { + rk28printk("find up key=%d\r\n",panel_key_info[(gpucPointBuffer[1]-1)].key); + input_report_key(Ctp_it7250->input_dev, panel_key_info[(gpucPointBuffer[1]-1)].key,0); + } + break; + default: + rk28printk("shit default \r\n"); + break; + } + break; + default: + rk28printk("default \r\n"); + break; + } + } + else if (ucQueryResponse & QUERY_ERROR) + { + if (!CaptouchReset()) + rk28printk("!! CaptouchReset success \r\n"); + mdelay(100); + //if (!CaptouchMode(0x00)) + //rk28printk("!! CaptouchMode success \r\n"); + } + } +// rk28printk("enable ctp_irq=%d \r\n",Ctp_it7250->irq); + + enable_irq(Ctp_it7250->irq); + //²»ÊDzéѯģʽ£¬²»ÐèÒªÂÖѯ +//schedule_delayed_work(&Ctp_it7250->delaywork,msecs_to_jiffies(1000)); + +} + + static int Ctp_it7250_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct Ctp_it7250_data *Ctp_it7250; + u16 TempReg=0x0; + u16 val=0x0; + + Ctp_it7250_client = client; + rk28printk("+++++++ %s+++++++\n", __FUNCTION__); + Ctp_it7250 = kzalloc(sizeof(struct Ctp_it7250_data), GFP_KERNEL); + if (!Ctp_it7250) + { + rk28printk("[Ctp_it7250_probe]:alloc data failed.\n"); + return -ENOMEM; + } + +// INIT_WORK(&Ctp_it7250->irq_work, Ctp_it7250_irq_worker); + INIT_DELAYED_WORK(&Ctp_it7250->delaywork, Ctp_it7250_delaywork_func); + + + Ctp_it7250->client = client; + i2c_set_clientdata(client, Ctp_it7250); + + + + ts_input_init(client); +// CTS_configure_pin(client); + +{ +#if 0 +lp8725_lilo_en(2,0); +mdelay(100); + +lp8725_lilo_en(2,1); +mdelay(100); +lp8725_set_lilo_vol(2,300); +mdelay(5); +#endif + +} +CaptouchHWInitial(); +Ctp_it7250_init_irq(client); + + +//²»ÊDzéѯģʽ£¬²»ÐèÒªÂÖѯ +//schedule_delayed_work(&Ctp_it7250->delaywork,msecs_to_jiffies(50)); + + + rk28printk("+++++++ %s+++++++\n", __FUNCTION__); + return 0; + +} + + + +static int Ctp_it7250_remove(struct i2c_client *client) +{ + + return 0; +} + + + +#ifdef CONFIG_PM +static int Ctp_it7250_suspend(struct i2c_client *client, pm_message_t state) +{//pr_emerg("\n irq1=%d \n",irq1); +struct Ctp_it7250_data *Ctp_it7250 = (struct Ctp_it7250_data *)i2c_get_clientdata(client); + +//send command to make ctp into sleep mode +#if 1 + u8 ucWriteLength; + u8 pucData[128]; + u8 ucQuery; + + ucWriteLength = 3; + pucData[0] = 0x04; + pucData[1] = 0x00; + pucData[2] = 0x02; + + // Query + do + { + if(!ReadQueryBuffer(&ucQuery)) + { + ucQuery = QUERY_BUSY; + } + }while(ucQuery & QUERY_BUSY); + + // Write Command + rk28printk("%s WriteCommandBuffer\r\n",__FUNCTION__); + if(!WriteCommandBuffer(pucData, ucWriteLength)) + { + return false; + } + #endif +//send sleep command end + + disable_irq(Ctp_it7250->irq); + + return 0; +} + +static int Ctp_it7250_resume(struct i2c_client *client) +{ +struct Ctp_it7250_data *Ctp_it7250 = (struct Ctp_it7250_data *)i2c_get_clientdata(client); +//read command to wakeup ctp +#if 1 +u8 ucQuery; +ReadQueryBuffer(&ucQuery); +#endif +//wakeup end + enable_irq(Ctp_it7250->irq); + return 0; +} +#else +#define Ctp_it7250_suspend NULL +#define Ctp_it7250_resume NULL +#endif + +static const struct i2c_device_id Ctp_it7250_id[] = { + {"Ctp_it7250", 0}, + { } +}; + +static struct i2c_driver Ctp_it7250_driver = { + .driver = { + .name = "Ctp_it7250", + }, + .id_table = Ctp_it7250_id, + .probe = Ctp_it7250_probe, + .remove = Ctp_it7250_remove, +}; + +static int __init Ctp_it7250_init(void) +{ + int ret; + rk28printk("+++++++ %s++\n", __FUNCTION__); + ret=i2c_add_driver(&Ctp_it7250_driver); + rk28printk("**Ctp_it7250_init_init return %d**\n",ret); + return ret; +} + +static void __exit Ctp_it7250_exit(void) +{ + /* We move these codes here because we want to detect the + * pen down event even when touch driver is not opened. + */ + i2c_del_driver(&Ctp_it7250_driver); +} + + late_initcall(Ctp_it7250_init); +module_exit(Ctp_it7250_exit); + +MODULE_AUTHOR("Robert_mu"); + -- 2.34.1