/*---------------------------------------------------------------------------------------------------------
* driver/input/touchscreen/goodix_touch.c
*
* Copyright(c) 2010 Goodix Technology Corp.
* Author: Eltonny
* Date: 2010.11.11
*
*---------------------------------------------------------------------------------------------------------*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/delay.h>
#define DEBUG 1
#include <linux/device.h>
#include <linux/earlysuspend.h>
#include <linux/platform_device.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/gpio.h>
#include <linux/ioc4.h>
#include <linux/io.h>
#include <mach/ut210_gpio_reg.h>
#include "goodix_touch.h"
#include "goodix_queue.h"
#ifndef GUITAR_GT80X
#error The code does not match the hardware version.
#endif
#define GOODIX_DEBUG_F
#ifdef GOODIX_DEBUG_F
#define GOODIXTS_DEBUG(fmt,args...) printk( "[goodix_ts]: " fmt, ## args) //printk( KERN_DEBUG "[egalax_i2c]: " fmt, ## args)
#define DBG() printk("[%s]:%d => \n",__FUNCTION__,__LINE__)
#else
#define GOODIXTS_DEBUG(fmt,args...) do{ }while(0)
#define DBG() do{ }while(0)
#endif
#ifdef utv210
static volatile VIC_REG *VICREG;
static volatile UT210_GPIO_REG *UT210_GPIOREG; //denis_wei add 2010-12-08
#define TIMER //采用的是定时器扫描的方式
#ifdef EINT29 //如果是定义EINT29表示采用的是中断的方式 是对中断的定义
#define EINT_KEY (IRQ_RTC_TIC)//按键中断
#define KEY_EINT_EN do { VICREG->VICINTENABLE |= (0x1<<29); \
VICREG->VICINTENCLEAR &= (~(0x1<<29));}while(0)
#define KEY_EINT_DIS do {VICREG->VICINTENABLE &= (~(0x1<<29));\
VICREG->VICINTENCLEAR |= (0x1<<29); } while(0)
static void goodix_key_callback(struct work_struct *work);
static DECLARE_WORK(key_work, goodix_key_callback);
static struct input_dev * s_input_dev = NULL;
#endif
/***wangyulu******/
#define MAX_BUTTON_CNT 3
static int goodix_scancode[MAX_BUTTON_CNT] = {0x1A,0x1B,0x1C};
static int goodix_keycode[MAX_BUTTON_CNT] = {KEY_BACK, KEY_HOME,KEY_MENU};
static int goodix_scancode_history[MAX_BUTTON_CNT] = {0,0,0,0};
///wangyulu lock_key time
#ifdef TIMER //对定时器的定义
#define KEY_DETECT_INTERVAL (msecs_to_jiffies(60))//定时60ms
static struct timer_list key_timer;
static void lockkey_timer_callback(struct work_struct *work);
static DECLARE_WORK(lock_work, lockkey_timer_callback);
static struct input_dev * s_input_dev = NULL;
static void goodix_key_timer_handler(unsigned long data);
#endif
#endif
#define MID706_SP
static struct point_queue finger_list; //record the fingers list
/*************************************************/
static struct i2c_client * i2c_connect_client = NULL;
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h);
static void goodix_ts_late_resume(struct early_suspend *h);
#endif
#define GOODIX_KEY_I2C (0xC4>>1)//触摸按键芯片的设备地址
/*Function as i2c_master_send */
static int i2c_write_key(struct i2c_client *client,uint8_t *data,int len)
{
struct i2c_msg msg;
int ret=-1;
//发送设备地址
msg.flags=!I2C_M_RD;//写消息
msg.addr=GOODIX_KEY_I2C;
msg.len=len;
msg.buf=data;
ret=i2c_transfer(i2c_get_adapter(1),&msg,1);
return ret;
}
//************ urbetter+ ******************
static int goodix_i2c_rxdata(char *rxdata, int length)
{
int ret;
struct i2c_msg msgs[] = {
{
.addr = GOODIX_KEY_I2C,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = GOODIX_KEY_I2C,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
ret = i2c_transfer(i2c_get_adapter(1), msgs, 2);//i2c_get_adapter(1)选着iic 1
if (ret < 0)
pr_err("msg %s i2c read error: %d\n", __func__, ret);
return ret;
}
#ifdef TIMER
////轮询处理函数wangyulu
static void goodix_key_timer_handler(unsigned long data)
{
//ceshi
schedule_work(&lock_work);
mod_timer(&key_timer,jiffies + KEY_DETECT_INTERVAL);
}
/////lock_key的处理函数 key_703 wangyulu
static void lockkey_timer_callback(struct work_struct *work)
{
int i;
int boy_flag = 0;
unsigned char buf[2];
buf[0] = 0xc5;
goodix_i2c_rxdata(buf, 1);
//printk("key_TIMER=0x%02X\n", buf[0]); //没有按下是0xff boy
for(i = 0; i < MAX_BUTTON_CNT; i++)
{
if((buf[0] == goodix_scancode_history[i]) || (buf[0] == goodix_scancode[i]))
{
printk("key_TIMER=0x%02X\n", buf[0]); //没有按下是0xff boy
goodix_scancode_history[i]= buf[0];
input_report_key(s_input_dev, goodix_keycode[i], 1);
}
if(buf[0] == 0xFF)
{
input_report_key(s_input_dev, goodix_keycode[i], 0);
}
}
}
#endif
static int goodix_key_input_init(struct goodix_ts_data *ts)
{
int i;
s_input_dev = ts->input_dev;
set_bit(EV_KEY, ts->input_dev->evbit);
for(i = 0; i < MAX_BUTTON_CNT; i++)
set_bit(goodix_keycode[i], ts->input_dev->keybit);
/******wangyulu********添加time*****/
#ifdef TIMER
init_timer(&key_timer);
key_timer.function = goodix_key_timer_handler;
key_timer.expires = jiffies + KEY_DETECT_INTERVAL;
add_timer(&key_timer);
#endif
}
static int goodix_init_key(struct goodix_ts_data *ts)
{
int ret=-1;
#ifdef EINT29
//KEY_EINT_NUM INT11 wangyulu
gpio_request(S5PV210_GPH3(5), "goodix_key_int");
s3c_gpio_cfgpin(S5PV210_GPH3(5), 0xf<<20);
s3c_gpio_setpull(S5PV210_GPH3(5), S3C_GPIO_PULL_DOWN);
set_irq_type(EINT_KEY, IRQ_TYPE_EDGE_RISING);
gpio_free(S5PV210_GPH3(5));
KEY_EINT_EN;
#else
if(ts->use_irq)
enable_irq(ts->client->irq);
#endif
uint8_t config_info[]={
0x88,0x08,0x90,0x90,0x90,0x90,0x50,0x58,0x55,0x56,
0x0e,0x00,0x00,0x00,0x09,0x04,0x00,0x00,0x00,
0x00,0x05,0x06,0x07,0x00,0xc8};
#endif
ret=i2c_write_key(ts->client,config_info,sizeof(config_info));
if(ret > 0)
ret = 0;
goodix_key_input_init(ts); //urbetter+ boy
return ret;
}
#ifdef EINT29
///add wangyulu 按键中断处理函数
static irqreturn_t goodix_key_irq_handler(int irq, void *dev_id)
{
struct goodix_ts_data *ts = dev_id;
printk("goodix_key_irq_handler\n"); //没有按下是0xff boy
KEY_EINT_DIS;
schedule_work(&key_work);
return IRQ_HANDLED;
}
static void goodix_key_callback(struct work_struct *work)/////adb wangyulu interrupter
{
int i;
int boy_flag = 0;
unsigned char buf[2];
buf[0] = 0xc5;
goodix_i2c_rxdata(buf, 1);
printk("key_EINT29=0x%02X\n", buf[0]); //没有按下是0xff boy
for(i = 0; i < MAX_BUTTON_CNT; i++)
{
if((buf[0] == goodix_scancode_history[i]) || (buf[0] == goodix_scancode[i]))
{
goodix_scancode_history[i]= buf[0];
input_report_key(s_input_dev, goodix_keycode[i], 1);
}
if(buf[0] == 0xFF)
{
input_report_key(s_input_dev, goodix_keycode[i], 0);
}
}
KEY_EINT_EN;
}
#endif
static void utv210_gpio_init(void)
{
int ret = 0;
VICREG = ioremap(0xf2000000, sizeof(VIC_REG));
UT210_GPIOREG = ioremap(0xe0200000, sizeof(UT210_GPIO_REG));
//wangyulu key
#ifdef EINT29
set_irq_type(EINT_KEY, IRQ_TYPE_EDGE_RISING);
ret = gpio_request(S5PV210_GPH3(5), "goodix_key_int");
if (ret < 0) {
gpio_free(S5PV210_GPH3(5)); // now bug; TODO
}
ret = gpio_request(S5PV210_GPH3(5), "goodix_key_int");
s3c_gpio_setpull(S5PV210_GPH3(5), S3C_GPIO_PULL_DOWN);
gpio_free(S5PV210_GPH3(5));
//denis_wei add 2010-12-10 for touch interrupt detect
UT210_GPIOREG->GPH1.GP_CON &= ~((0xf<<20) );//gph13 as input port
UT210_GPIOREG->GPH1.GP_CON |= ((0xf<<20));//gph13 interrupt port
UT210_GPIOREG->GPH1.GP_DAT &= ~((0x1<<20) );//gph13. output 1
UT210_GPIOREG->GPH1.GP_PUD &= ~((0x3<<20) );//gph13 pull disable
UT210_GPIOREG->GPH1.GP_PUD |= ((0x2<<20));//gph13 pull-up enable
#endif
#ifdef TIMER
s3c_gpio_cfgpin(S5PV210_GPH3(5), 0x0<<20);
gpio_direction_output(S5PV210_GPH3(5), 1);
s3c_gpio_setpull(S5PV210_GPH3(5), S3C_GPIO_PULL_DOWN);
#endif
}
/*******************************************************
功能:
触摸屏探测函数
在注册驱动时调用(要求存在对应的client);
用于IO,中断等资源申请;设备注册;触摸屏初始化等工作
参数:
client:待驱动的设备结构体
id:设备ID
return:
执行结果码,0表示正常执行
********************************************************/
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct goodix_ts_data *ts;
int ret = 0;
int retry=0;
int count=0;
u8 testbuf[6] = {0, 0, 0, 0, 0};
struct goodix_i2c_rmi_platform_data *pdata;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
dev_err(&client->dev, "System need I2C function.\n");
ret = -ENODEV;
goto err_check_functionality_failed;
}
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (ts == NULL) {
ret = -ENOMEM;
goto err_alloc_data_failed;
}
//utv210_gpio_init();
/***wangyulu****/
ts->client = client;
i2c_set_clientdata(client, ts);
pdata = client->dev.platform_data;
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
dev_dbg(&client->dev,"Failed to allocate input device\n");
goto err_input_dev_alloc_failed;
}
ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
ret = input_register_device(ts->input_dev);
if (ret) {
dev_err(&client->dev,"Probe: Unable to register %s input device\n", ts->input_dev->name);
goto err_input_register_device_failed;
}
utv210_gpio_init();
goodix_init_key(ts);
#ifdef EINT29
///wangyulu 按键中断申请
ret = request_irq(EINT_KEY, goodix_key_irq_handler, IRQ_TYPE_EDGE_RISING, client->name, ts);
if( ret )
{
printk("Can't allocate touchscreen's interrupt\n");
dev_err(&client->dev,"Can't allocate touchscreen's interrupt!ERRNO:%d\n", ret);
goto Fail_utv210_int;
}
ts->use_irq = 1;
KEY_EINT_DIS;
#endif
printk("#############line =%d\n", __LINE__);
err_input_register_device_failed:
input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
i2c_set_clientdata(client, NULL);
Fail_utv210_int:
err_alloc_data_failed:
err_check_functionality_failed:
return ret;
}
/*******************************************************
功能:
驱动资源释放
参数:
client:设备结构体
return:
执行结果码,0表示正常执行
********************************************************/
static int goodix_ts_remove(struct i2c_client *client)
{
struct goodix_ts_data *ts = i2c_get_clientdata(client);
unregister_early_suspend(&ts->early_suspend);
dev_notice(&client->dev,"The driver is removing...\n");
i2c_set_clientdata(client, NULL);
input_unregister_device(ts->input_dev);
#ifdef EINT29
free_irq(EINT_KEY, ts);
#endif
if(ts->input_dev)
kfree(ts->input_dev);
kfree(ts);
return 0;
}
//停用设备
static int goodix_ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
int ret;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if(ts->bad_data)
return 0;
}
static int goodix_ts_resume(struct i2c_client *client)
{
int ret;
struct goodix_ts_data *ts = i2c_get_clientdata(client);
if(ts->bad_data)
return 0;
#ifdef EINT29
KEY_EINT_EN;
#else
if (ts->use_irq) {
enable_irq(client->irq);
}
#endif
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void goodix_ts_early_suspend(struct early_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
goodix_ts_suspend(ts->client, PMSG_SUSPEND);
}
static void goodix_ts_late_resume(struct early_suspend *h)
{
struct goodix_ts_data *ts;
ts = container_of(h, struct goodix_ts_data, early_suspend);
goodix_ts_resume(ts->client);
}
#endif
#undef GOODIX_I2C_NAME
#define GOODIX_I2C_NAME "Goodix-key-703" //boy
static const struct i2c_device_id goodix_ts_id[] = {
{ GOODIX_I2C_NAME, 0 },
{ }
};
//设备驱动结构体
struct i2c_driver goodix_ts_driver = {
.probe = goodix_ts_probe,
.remove = goodix_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = goodix_ts_suspend,
.resume = goodix_ts_resume,
#endif
.id_table = goodix_ts_id,
.driver = {
.name = GOODIX_I2C_NAME,
.owner = THIS_MODULE,
},
};
/*******************************************************
功能:
驱动加载函数
return:
执行结果码,0表示正常执行
********************************************************/
static int __devinit goodix_ts_init(void)
{
int ret;
ret=i2c_add_driver(&goodix_ts_driver);
return ret;
}
/*******************************************************
功能:
驱动卸载函数
参数:
client:设备结构体
********************************************************/
static void __exit goodix_ts_exit(void)
{
i2c_del_driver(&goodix_ts_driver);
}
late_initcall(goodix_ts_init);
module_exit(goodix_ts_exit);
MODULE_DESCRIPTION("Goodix Touchscreen Driver");
MODULE_LICENSE("GPL");
希望能够和大家分享,如有疑问可以给我留言,谢谢