/* drivers/input/touchscreen/gt216_ts.c
*
* FocalTech TouchScreen driver in android 4.x.
*
* Copyright (c) 2010 Focal tech Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/earlysuspend.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/init-input.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/input/mt.h>
#include <linux/io.h>
#include <mach/sys_config.h>
#include <mach/gpio.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/input-polldev.h>
#include "gt216_ts.h"
struct ts_event {
u16 au16_x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */
u16 au16_y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */
u8 au8_touch_event[CFG_MAX_TOUCH_POINTS]; /*touch event:
0 -- down; 1-- contact; 2 -- contact */
u8 au8_finger_id[CFG_MAX_TOUCH_POINTS]; /*touch ID */
u16 pressure;
u8 touch_point;
};
struct gt216_ts_data {
unsigned int irq;
unsigned int x_max;
unsigned int y_max;
u32 irq_handle;
struct work_struct pen_event_work;
struct workqueue_struct *ts_workqueue;
struct i2c_client *client;
struct input_dev *input_dev;
struct ts_event event;
struct gt216_platform_data *pdata;
#ifdef CONFIG_PM
struct early_suspend *early_suspend;
#endif
};
static struct ctp_config_info config_info = {
.input_type = CTP_TYPE,
};
static int screen_max_x = 0;
static int screen_max_y = 0;
static int revert_x_flag = 0;
static int revert_y_flag = 0;
static int exchange_x_y_flag = 0;
static u32 int_handle = 0;
static __u32 twi_id = 0;
static int int_number = 0;
static u32 wakeup_number = 0;
static bool is_suspend = false;
static struct i2c_client *this_client;
static struct gt216_ts_data *gt216_ts;
static void i2c_button_poll(struct input_polled_dev *poll_dev);
static int get_button_value(char *keyValue);
static char get_button_code(char *keyValue);
char button_code_config[12] = {
KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,
KEY_7,KEY_8,KEY_9,KEY_A,KEY_B
};
#define FTS_CTL_IIC
/*
*gt216_i2c_Read-read data and write data by i2c
*@client: handle of i2c
*@writebuf: Data that will be written to the slave
*@writelen: How many bytes to write
*@readbuf: Where to store data read from slave
*@readlen: How many bytes to read
*
*Returns negative errno, else the number of messages executed
*
*
*/
#if 1
int gt216_i2c_Read( char *writebuf,
int writelen, char *readbuf, int readlen)
{
int ret;
if (writelen > 0) {
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = writelen,
.buf = writebuf,
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = readlen,
.buf = readbuf,
},
};
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
dev_err(&this_client->dev, "%s:i2c read error.\n", __func__);
} else {
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = readlen,
.buf = readbuf,
},
};
ret = i2c_transfer(this_client->adapter, msgs, 1);
if (ret < 0)
dev_err(&this_client->dev, "%s:i2c read error.\n", __func__);
}
return ret;
}
/*write data by i2c*/
int gt216_i2c_Write( char *writebuf, int writelen)
{
int ret;
struct i2c_msg msg[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = writelen,
.buf = writebuf,
},
};
ret = i2c_transfer(this_client->adapter, msg, 1);
if (ret < 0)
dev_err(&this_client->dev, "%s i2c write error.\n", __func__);
//printk("%s:i2c write error----mrzhang.\n", __func__);
return ret;
}
#if 0
/*release the point*/
static void gt216_ts_release(struct gt216_ts_data *data)
{
input_mt_sync(data->input_dev);
input_sync(data->input_dev);
}
#endif
/*Read touch point information when the interrupt is asserted.*/
static int initGT216(void)
{
int ret;
unsigned char set1[] = {0x06, 0x10}; //禁止组合键,禁止PWM,电平中断模式,idle时间0ms 0x04-> 2 4 del
#if 0
//0x10-0x1f寄存器,对应各通道灵敏度,范围0x02-0x3f,0x02灵敏度最高,0x3f灵敏度最低
unsigned char set2[] = {0x10, 0x05,0x11, 0x07,0x12, 0x07,0x13, 0x0a,0x14, 0x0a,0x15,0x08,0x16, \
0x08,0x17, 0x09,0x18, 0x09,0x19, 0x08,0x1a, 0x08,0x1b, 0x04,0x1c, 0x3f, \
0x1d, 0x3f,0x1e, 0x3f,0x1f, 0x3f};
#else
//灵敏度调低点,以防外部干扰导致死机
/*unsigned char set2[] = {0x10, 0x06, 0x08, 0x08, 0x0b, 0x0b, 0x09, 0x09, 0x0a, \
0x0a, 0x09, 0x03, 0x08, 0x3f, 0x3f, 0x3f, 0x3f};*/
unsigned char set2[] = {0x10, 0x04, 0x05, 0x05, 0x05, 0x04, 0x05, 0x07, 0x05, \
0x05, 0x07, 0x03, 0x03, 0x3f, 0x3f, 0x3f, 0x3f};
#endif
unsigned char set3[] = {0x01,0x01};
//rstGT216();
char reg = 0x01;
char value = 0;
ret = gt216_i2c_Write( set1, sizeof(set1) );
if(ret < 0)
return -1;
ret = gt216_i2c_Write( set2, sizeof(set2) );
if(ret < 0)
return -1;
return 0;
}
/*The gt216 device will signal the host about TRIGGER_FALLING.
*Processed when the interrupt is asserted.
*/
static int ctp_get_system_config(void)
{
twi_id = config_info.twi_id;
int_number = config_info.int_number;
wakeup_number = config_info.wakeup_number;
printk("int_number = %d wakeup_number = %d\n",int_number,wakeup_number);
return 1;
}
static int get_button_value(char *keyValue)
{
static char down_flag = 0;
static char up_flag = 0;
static char interrupt_state = 0;
char writeReg[3] = {0x01,0x02,0x03};
char readKeyValue[2] = {0};
char readInterruptState = 0;
static char key_store[2];
if( 0 > gt216_i2c_Read(&writeReg[0],1,&readInterruptState,1))
return KEY_ERRO;
if(readInterruptState&0x01 == 0x01){
up_flag = 0;
if (interrupt_state == 0&&++down_flag>=6){
down_flag = 0;
interrupt_state = 1;
if( 0 > gt216_i2c_Read(&writeReg[1],1,&readKeyValue[0],1))
return KEY_ERRO;
if( 0 > gt216_i2c_Read(&writeReg[2],1,&readKeyValue[1],1))
return KEY_ERRO;
if(readKeyValue[0]||readKeyValue[1]){
key_store[0] = keyValue[0] = readKeyValue[0];
key_store[1] = keyValue[1] = readKeyValue[1];
return KEY_DOWN;
}else {
keyValue[0] = key_store[0] ;
keyValue[1] = key_store[1] ;
return KEY_UP ;
}
}
}else {
down_flag = 0;
if (interrupt_state == 1&&++up_flag>=6){
up_flag = 0;
interrupt_state = 0;
if( 0 > gt216_i2c_Read(&writeReg[1],1,&readKeyValue[0],1))
return KEY_ERRO;
if( 0 > gt216_i2c_Read(&writeReg[2],1,&readKeyValue[1],1))
return KEY_ERRO;
if(readKeyValue[0]||readKeyValue[1]){
key_store[0] = keyValue[0] = readKeyValue[0];
key_store[1] = keyValue[1] = readKeyValue[1];
return KEY_DOWN;
}else {
keyValue[0] = key_store[0] ;
keyValue[1] = key_store[1] ;
return KEY_UP ;
}
}
}
return KEY_ERRO;
}
static char get_button_code(char *keyValue)
{
int i;
int value = keyValue[0]|keyValue[1]<<8;
printk("value = 0x%x 0x%x 0x%x\n ",value,keyValue[0],keyValue[1]<<8);
for(i = 0; i <16;i++)
{
if(value & (1<<i))
{
printk("i=%d \n",i);
return button_code_config[i];
}
}
return -1;
}
static void i2c_button_poll(struct input_polled_dev *poll_dev)
{
char keyValue[2] = {0};
switch(get_button_value(keyValue)){
case KEY_DOWN:
input_report_key(poll_dev->input,get_button_code(keyValue),1);
input_sync(poll_dev->input);
printk("code : %d down\n",get_button_code(keyValue));
break;
case KEY_UP:
input_report_key(poll_dev->input,get_button_code(keyValue),0);
input_sync(poll_dev->input);
printk("code : %d up\n",get_button_code(keyValue));
break;
}
}
struct gt216_platform_data gt216_padta;
static int reg_get(){
int i;
char wbuff[16] = {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f};
char rbuff=0x0;
for(i=0;i<16;i++){
if( 0 > gt216_i2c_Read(&wbuff[i],1,&rbuff,1))
return -1;
printk("addr = 0x%x value=0x%x\n",wbuff[i],rbuff);
rbuff=0x0;
}
return 0;
}
static int gt216_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct gt216_platform_data *pdata = >216_padta;
//struct input_dev *input_dev;
struct input_polled_dev *input_poll_dev;
int err = 0,ret = 0;
printk("**********gt216_ts_probe************\n");
printk("client.adapter.timeout = %d\n",(client->adapter)->timeout);
client->irq = gpio_to_irq(int_number);
printk("client->irq =%d\n",client->irq);
gt216_padta.reset = wakeup_number;
#if 1
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit_check_functionality_failed;
}
gt216_ts = kzalloc(sizeof(struct gt216_ts_data), GFP_KERNEL);
if (!gt216_ts) {
err = -ENOMEM;
goto exit_alloc_data_failed;
}
this_client = client;
gt216_ts->client = client;
gt216_ts->pdata = pdata;
i2c_set_clientdata(client, gt216_ts);
input_poll_dev = input_allocate_polled_device();
if(!input_poll_dev)
return -1;
input_poll_dev->poll = i2c_button_poll;
input_poll_dev->poll_interval = 10; //10ms
#endif
gt216_ts->input_dev = input_poll_dev->input;
int i;
__set_bit(EV_KEY, gt216_ts->input_dev->evbit);
for( i = 0; i< sizeof(button_code_config)/sizeof(button_code_config[0]);i++)
{
__set_bit(button_code_config[i], gt216_ts->input_dev->keybit);
}
__set_bit(INPUT_PROP_DIRECT, gt216_ts->input_dev->propbit);
gt216_ts->input_dev->name = GT216_NAME;
err = input_register_polled_device(input_poll_dev);
if (err) {
dev_err(&client->dev,
"gt216_ts_probe: failed to register input device: %s\n",
dev_name(&client->dev));
goto exit_input_register_device_failed;
}
/*make sure CTP already finish startup process */
msleep(150);
while (0 > initGT216())
{
printk("gt216 init fail\n");
msleep(100);
}
printk("gt216 init ok\n");
int rg = reg_get();
if(rg)printk("reg_get err \n");
return 0;
exit_input_register_device_failed:
input_free_device(gt216_ts->input_dev);
#ifdef CONFIG_PM
exit_request_reset:
gpio_free(gt216_ts->pdata->reset);
#endif
exit_irq_request_failed:
i2c_set_clientdata(client, NULL);
kfree(gt216_ts);
exit_create_singlethread:
kfree(gt216_ts);
exit_alloc_data_failed:
exit_check_functionality_failed:
return err;
#endif
}
#ifdef CONFIG_PM
static void gt216_ts_suspend(struct early_suspend *handler)
{
struct gt216_ts_data *ts = i2c_get_clientdata(this_client);
dev_dbg(&ts->client->dev, "[FTS]gt216 suspend\n");
disable_irq(ts->irq);
}
static void gt216_ts_resume(struct early_suspend *handler)
{
struct gt216_ts_data *ts = i2c_get_clientdata(this_client);
dev_dbg(&ts->client->dev, "[FTS]gt216 resume.\n");
ctp_wakeup(config_info.wakeup_number, 0, 20);
enable_irq(ts->irq);
}
#else
#define gt216_ts_suspend NULL
#define gt216_ts_resume NULL
#endif
static int __devexit gt216_ts_remove(struct i2c_client *client)
{
struct gt216_ts_data *gt216_ts;
gt216_ts = i2c_get_clientdata(this_client);
input_unregister_device(gt216_ts->input_dev);
#ifdef CONFIG_PM
gpio_free(gt216_ts->pdata->reset);
#endif
sw_gpio_irq_free(gt216_ts->irq_handle);
kfree(gt216_ts);
i2c_set_clientdata(this_client, NULL);
return 0;
}
static int i2c_driver_gt216_detect(struct i2c_client *client, struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
int ret;
printk("****************client->adapter = %d*******************\n",client->adapter->nr);
if(twi_id == adapter->nr)
{
printk("%s: addr = %x\n", __func__, client->addr);
ret = i2c_test(client);
if(!ret){
printk("%s:I2C connection might be something wrong \n", __func__);
return -ENODEV;
}
const char *type_name = GT216_NAME;
strlcpy(info->type, type_name, I2C_NAME_SIZE);
return 0;
}else
{
return -ENODEV;
}
}
static const struct i2c_device_id gt216_ts_id[] = {
{GT216_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, gt216_ts_id);
static const unsigned short normal_i2c[] = {0x58, I2C_CLIENT_END};
static struct i2c_driver gt216_ts_driver = {
.class = I2C_CLASS_HWMON,
.probe = gt216_ts_probe,
.remove = __devexit_p(gt216_ts_remove),
.id_table = gt216_ts_id,
.suspend = gt216_ts_suspend,
.resume = gt216_ts_resume,
.driver = {
.name = GT216_NAME,
.owner = THIS_MODULE,
},
.address_list = normal_i2c,
};
static int __init gt216_ts_init(void)
{
int ret;
printk("***********gt216_ts_init*************~~~~~~~~~~~~~~~~\n");
if (input_fetch_sysconfig_para(&(config_info.input_type))) {
printk("%s: ctp_fetch_sysconfig_para err.\n", __func__);
return 0;
} else {
ret = input_init_platform_resource(&(config_info.input_type));
if (0 != ret) {
printk("%s:ctp_ops.init_platform_resource err. \n", __func__);
}
}
ctp_get_system_config();
ctp_wakeup(config_info.wakeup_number, 0, 20);
gt216_ts_driver.detect = i2c_driver_gt216_detect,
ret = i2c_add_driver(>216_ts_driver);
if (ret) {
printk(KERN_WARNING "Adding gt216 driver failed "
"(errno = %d)\n", ret);
} else {
pr_info("Successfully added driver %s\n",
gt216_ts_driver.driver.name);
}
return ret;
}
static void __exit gt216_ts_exit(void)
{
i2c_del_driver(>216_ts_driver);
}
module_init(gt216_ts_init);
module_exit(gt216_ts_exit);
MODULE_AUTHOR("<luowj>");
MODULE_DESCRIPTION("FocalTech TouchScreen driver");
MODULE_LICENSE("GPL");
头文件:
#ifndef __LINUX_gt216_TS_H__
#define __LINUX_gt216_TS_H__
/* -- dirver configure -- */
#define CFG_MAX_TOUCH_POINTS 2
#define PRESS_MAX 0xFF
#define FT_PRESS 0x08
#define GT216_NAME "gt216"
#define KEY_ERRO -1
#define KEY_DOWN 0
#define KEY_UP 1
/*register address*/
#define gt216_REG_FW_VER 0xA6
#define gt216_REG_POINT_RATE 0x88
#define gt216_REG_THGROUP 0x80
int gt216_i2c_Read(char *writebuf, int writelen,
char *readbuf, int readlen);
int gt216_i2c_Write(char *writebuf, int writelen);
/* The platform data for the Focaltech gt216 touchscreen driver */
struct gt216_platform_data {
unsigned int x_max;
unsigned int y_max;
unsigned long irqflags; /*default:IRQF_TRIGGER_FALLING*/
unsigned int irq;
unsigned int reset;
};
#endif