/*
* drivers/input/touchscreen/ft5x0x_ts.c
*
* FocalTech ft5x0x TouchScreen driver.
*
* 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.
*
*
* note: only support mulititouch Wenfs 2010-10-01
*/
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio.h>
#ifdef CONFIG_OF
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#endif
#ifdef CONFIG_FB
#include <linux/notifier.h>
#include <linux/fb.h>
#endif
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include <linux/i2c.h>
#include <linux/input.h>
//#include <linux/ft5x0x_ts.h>
#include "ft5x0x_ts.h"
//#include <linux/earlysuspend.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
//#include <asm/jzsoc.h>
#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))
#define GTP_RST_PORT GPIO_TO_PIN(1, 24)
#define GTP_INT_PORT GPIO_TO_PIN(3, 20)
#define GTP_INT_IRQ gpio_to_irq(GTP_INT_PORT)
static struct i2c_client *this_client;
static struct ft5x0x_ts_platform_data *pdata;
//#define CONFIG_FT5X0X_MULTITOUCH 0
struct ts_event {
u16 x1;
u16 y1;
u16 x2;
u16 y2;
u16 x3;
u16 y3;
u16 x4;
u16 y4;
u16 x5;
u16 y5;
u16 pressure;
u8 touch_point;
};
struct ft5x0x_ts_data {
struct input_dev *input_dev;
struct ts_event event;
struct work_struct pen_event_work;
struct workqueue_struct *ts_workqueue;
// struct early_suspend early_suspend;
#if defined(CONFIG_FB)
struct notifier_block notifier;
#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
};
static int ft5x0x_i2c_rxdata(char *rxdata, int length)
{
printk("start enter ft5x0x_i2c_rxdata--\n");
int ret;
struct i2c_msg msgs[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = 1,
.buf = rxdata,
},
{
.addr = this_client->addr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
//msleep(1);
ret = i2c_transfer(this_client->adapter, msgs, 2);
if (ret < 0)
printk("msg %s i2c read error: %d\n", __func__, ret);
return ret;
}
static int ft5x0x_i2c_txdata(char *txdata, int length)
{
printk("start enter ft5x0x_i2c_txdata--\n");
int ret;
struct i2c_msg msg[] = {
{
.addr = this_client->addr,
.flags = 0,
.len = length,
.buf = txdata,
},
};
//msleep(1);
ret = i2c_transfer(this_client->adapter, msg, 1);
if (ret < 0)
printk("%s i2c write error: %d\n", __func__, ret);
return ret;
}
static int ft5x0x_set_reg(u8 addr, u8 para)
{
printk("start enter ft5x0x_set_reg--\n");
u8 buf[3];
int ret = -1;
buf[0] = addr;
buf[1] = para;
ret = ft5x0x_i2c_txdata(buf, 2);
if (ret < 0) {
printk("write reg failed! %#x ret: %d", buf[0], ret);
return -1;
}
return 0;
}
static void ft5x0x_ts_release(void)
{
printk("start enter ft5x0x_ts_release--\n");
struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
#ifdef CONFIG_FT5X0X_MULTITOUCH
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, 0);
#else
printk("start enter ft5x0x_ts_release--now\n");
input_report_abs(data->input_dev, ABS_PRESSURE, 0);
input_report_key(data->input_dev, BTN_TOUCH, 0);
#endif
input_sync(data->input_dev);
}
static int ft5x0x_read_data(void)
{
printk("start enter ft5x0x_read_data--\n");
struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
// u8 buf[14] = {0};
u8 buf[32] = {0};
int ret = -1;
#ifdef CONFIG_FT5X0X_MULTITOUCH
// ret = ft5x0x_i2c_rxdata(buf, 13);
ret = ft5x0x_i2c_rxdata(buf, 31);
#else
ret = ft5x0x_i2c_rxdata(buf, 7);
#endif
if (ret < 0) {
printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
return ret;
}
memset(event, 0, sizeof(struct ts_event));
// event->touch_point = buf[2] & 0x03;// 0000 0011
event->touch_point = buf[2] & 0x07;// 000 0111
if (event->touch_point == 0) {
ft5x0x_ts_release();
return 1;
}
#ifdef CONFIG_FT5X0X_MULTITOUCH
switch (event->touch_point) {
case 5:
event->x5 = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
event->y5 = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
case 4:
event->x4 = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
event->y4 = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
case 3:
event->x3 = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
event->y3 = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
case 2:
event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10];
event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12];
case 1:
event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
break;
default:
return -1;
}
#else
if (event->touch_point == 1) {
event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
}
#endif
event->pressure = 200;
dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
event->x1, event->y1, event->x2, event->y2);
//printk("%d (%d, %d), (%d, %d)\n", event->touch_point, event->x1, event->y1, event->x2, event->y2);
return 0;
}
static void ft5x0x_report_value(void)
{
printk("start enter ft5x0x_report_value--\n");
struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
struct ts_event *event = &data->event;
// printk("==ft5x0x_report_value =\n");
#ifdef CONFIG_FT5X0X_MULTITOUCH
switch(event->touch_point) {
case 5:
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x5);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y5);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(data->input_dev);
// printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
case 4:
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x4);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y4);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(data->input_dev);
// printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
case 3:
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x3);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y3);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(data->input_dev);
// printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
case 2:
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x2);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_sync(data->input_dev);
// printk("===x2 = %d,y2 = %d ====\n",event->x2,event->y2);
case 1:
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->x1);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
input_mt_syn