rt-thread/bsp/x1000/drivers/touch/focaltech_ts.c

618 lines
19 KiB
C

/*
* File : focaltech_ts.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Change Logs:
* Date Author Notes
* 2017-01-01 Urey first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <drv_gpio.h>
#include <rtgui/event.h>
#include <rtgui/rtgui_server.h>
#include <string.h>
#ifdef RT_USING_FT6x06
#include "focaltech_ts.h"
#ifndef BIT
#define BIT(n) (0x01u << (n))
#endif
static int fts_init_success = 0;
#define TP_DEBUG 0
#if TP_DEBUG
#define TP_DBG(...) rt_kprintf("[TP]"),rt_kprintf(__VA_ARGS__)
#else
#define TP_DBG(...)
#endif
/*ic update info*/
static struct Upgrade_Info fts_updateinfo[] =
{
{0x55,"FT5x06",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 30, 0x79, 0x03, 10, 2000},
{0x08,"FT5606",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 10, 0x79, 0x06, 100, 2000},
{0x0a,"FT5x16",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 30, 0x79, 0x07, 10, 1500},
{0x06,"FT6x06",TPD_MAX_POINTS_2,AUTO_CLB_NONEED,100, 30, 0x79, 0x08, 10, 2000},
{0x36,"FT6x36",TPD_MAX_POINTS_2,AUTO_CLB_NONEED,10, 10, 0x79, 0x18, 10, 2000},
{0x55,"FT5x06i",TPD_MAX_POINTS_5,AUTO_CLB_NEED,50, 30, 0x79, 0x03, 10, 2000},
{0x14,"FT5336",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000},
{0x13,"FT3316",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000},
{0x12,"FT5436i",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000},
{0x11,"FT5336i",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 30, 0x79, 0x11, 10, 2000},
{0x54,"FT5x46",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,2, 2, 0x54, 0x2c, 20, 2000},
{0x58,"FT5x22",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,2, 2, 0x58, 0x2c, 20, 2000},
{0x59,"FT5x26",TPD_MAX_POINTS_5,AUTO_CLB_NONEED,30, 50, 0x79, 0x10, 1, 2000},
};
static struct Upgrade_Info fts_updateinfo_curr;
static int touch_down_up_status = 0;
#ifndef TOUCH_MAX_X
# define TOUCH_MAX_X 480
#endif
#ifndef TOUCH_MAX_Y
# define TOUCH_MAX_Y 320
#endif
#define ANDROID_INPUT_PROTOCOL_B
#define FTS_RESET_PIN_NAME "ft3417-rst"
#define FTS_INT_PIN_NAME "ft3417-int"
static uint8_t buf_addr[2] = { 0 };
static uint8_t buf_value[2] = { 0 };
/************************************************************************
* Name: fts_i2c_Read
* Brief: i2c read
* Input: i2c info, write buf, write len, read buf, read len
* Output: get data in the 3rd buf
* Return: fail <0
***********************************************************************/
static int fts_i2c_Read(struct fts_ts_data *fts_ts, char *writebuf, int writelen, char *readbuf, int readlen)
{
struct rt_i2c_msg msgs[2];
int ret;
if (writelen > 0)
{
msgs[0].addr = fts_ts->addr;
msgs[0].flags = RT_I2C_WR;
msgs[0].len = writelen;
msgs[0].buf = writebuf;
msgs[1].addr = fts_ts->addr;
msgs[1].flags = RT_I2C_RD;
msgs[1].len = readlen;
msgs[1].buf = readbuf;
ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 2);
if (ret < 0)
{
TP_DBG("f%s: i2c read error. error code = %d \n", __func__, ret);
}
}
else
{
msgs[0].addr = fts_ts->addr;
msgs[0].flags = RT_I2C_RD;
msgs[0].len = readlen;
msgs[0].buf = readbuf;
ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 1);
if (ret < 0)
{
TP_DBG("%s:i2c read error. error code = %d \n", __func__, ret);
}
}
return ret;
}
/************************************************************************
* Name: fts_i2c_Write
* Brief: i2c write
* Input: i2c info, write buf, write len
* Output: no
* Return: fail <0
***********************************************************************/
static int fts_i2c_Write(struct fts_ts_data *fts_ts, char *writebuf, int writelen)
{
struct rt_i2c_msg msgs[2];
int ret;
msgs[0].addr = fts_ts->addr;
msgs[0].flags = RT_I2C_WR;
msgs[0].len = writelen;
msgs[0].buf = writebuf;
ret = rt_i2c_transfer(fts_ts->i2c_bus, msgs, 1);
if (ret < 0)
{
TP_DBG("%s i2c write error.\n", __func__);
}
return ret;
}
/************************************************************************
* Name: fts_read_Touchdata
* Brief: report the point information
* Input: event info
* Output: get touch data in pinfo
* Return: success is zero
***********************************************************************/
static unsigned int buf_count_add=0;
static unsigned int buf_count_neg=0;
//unsigned int buf_count_add1;
//unsigned int buf_count_neg1;
static uint8_t buf_touch_data[30 * POINT_READ_BUF] = { 0 }; //0xFF
static int fts_read_Touchdata(struct fts_ts_data *fts_ts)
{
struct fts_event *event = &fts_ts->event;
uint8_t buf[POINT_READ_BUF] = { 0 }; //0xFF
int ret = -1;
int i = 0;
uint8_t pointid = FTS_MAX_ID;
//uint8_t pt00f=0;
ret = fts_i2c_Read(fts_ts, buf, 1, buf, POINT_READ_BUF);
if (ret < 0)
{
TP_DBG("%s read touchdata failed.\n", __func__);
return ret;
}
buf_count_add++;
//buf_count_add1=buf_count_add;
rt_memcpy(buf_touch_data + (((buf_count_add - 1) % 30) * POINT_READ_BUF),
buf, sizeof(uint8_t) * POINT_READ_BUF);
return 0;
}
/************************************************************************
* Name: fts_report_value
* Brief: report the point information
* Input: event info
* Output: no
* Return: success is 0(RT_EOK)
***********************************************************************/
static struct rtgui_event_mouse emouse = {0};
static int xx = 0, yy = 0, zz = 0;
static int fts_report_value(struct fts_ts_data *fts_ts)
{
struct fts_event *event = &fts_ts->event;
int i,result;
int uppoint = 0;
int touchs = 0;
uint8_t pointid = FTS_MAX_ID;
uint8_t buf[POINT_READ_BUF] = { 0 };//0xFF
//struct rtgui_event_mouse emouse;
static int touch_down = 0;
buf_count_neg++;
//buf_count_neg1=buf_count_neg;
rt_memcpy(buf,
buf_touch_data + (((buf_count_neg - 1) % 30) * POINT_READ_BUF),
sizeof(uint8_t) * POINT_READ_BUF);
rt_memset(event, 0, sizeof(struct fts_event));
event->touch_point_num = buf[FT_TOUCH_POINT_NUM] & 0x0F;
event->touch_point = 0;
for (i = 0; i < fts_updateinfo_curr.TPD_MAX_POINTS; i++)
{
pointid = (buf[FTS_TOUCH_ID_POS + FTS_TOUCH_STEP * i]) >> 4;
if (pointid >= FTS_MAX_ID)
break;
else
event->touch_point++;
#if TOUCH_SWAP_XY
event->au16_y[i] = (((int16_t) buf[FTS_TOUCH_X_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8
| (((int16_t) buf[FTS_TOUCH_X_L_POS + FTS_TOUCH_STEP * i])& 0xFF);
event->au16_x[i] = (((int16_t) buf[FTS_TOUCH_Y_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8
| (((int16_t) buf[FTS_TOUCH_Y_L_POS + FTS_TOUCH_STEP * i]) & 0xFF);
#else
event->au16_x[i] = (((int16_t) buf[FTS_TOUCH_X_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8
| (((int16_t) buf[FTS_TOUCH_X_L_POS + FTS_TOUCH_STEP * i])& 0xFF);
event->au16_y[i] = (((int16_t) buf[FTS_TOUCH_Y_H_POS + FTS_TOUCH_STEP * i]) & 0x0F) << 8
| (((int16_t) buf[FTS_TOUCH_Y_L_POS + FTS_TOUCH_STEP * i]) & 0xFF);
#endif
#if TOUCH_SWAP_Y
event->au16_y[i] = TOUCH_MAX_Y - event->au16_y[i];
#endif
TP_DBG("event->au16_x[%d] = %04x\n",i,event->au16_x[i]);
TP_DBG("event->au16_y[%d] = %04x\n",i,event->au16_y[i]);
event->au8_touch_event[i] = buf[FTS_TOUCH_EVENT_POS + FTS_TOUCH_STEP * i] >> 6;
event->au8_finger_id[i] = (buf[FTS_TOUCH_ID_POS + FTS_TOUCH_STEP * i]) >> 4;
event->pressure[i] = (buf[FTS_TOUCH_XY_POS + FTS_TOUCH_STEP * i]);//cannot constant value
event->area[i] = (buf[FTS_TOUCH_MISC + FTS_TOUCH_STEP * i]) >> 4;
if((event->au8_touch_event[i]==0 || event->au8_touch_event[i]==2)&&((event->touch_point_num==0)||(event->pressure[i]==0 && event->area[i]==0 )))
return 1;
#ifdef DEBUG
TP_DBG("id=%d event=%d x=%d y=%d pressure=%d area=%d\n",
event->au8_finger_id[i],
event->au8_touch_event[i],
event->au16_x[i],
event->au16_y[i],
event->pressure[i],
event->area[i]);
#endif
}
/*protocol B*/
for (i = 0; i < event->touch_point; i++)
{
if (event->au8_touch_event[i]== 0 || event->au8_touch_event[i] == 2)
{
// input_mt_report_slot_state(fts_ts->input_dev, MT_TOOL_FINGER, true);
// input_report_abs(fts_ts->input_dev, ABS_MT_PRESSURE, event->pressure[i]);
// input_report_abs(fts_ts->input_dev, ABS_MT_TOUCH_MAJOR, event->area[i]);
// input_report_abs(fts_ts->input_dev, ABS_MT_POSITION_X, event->au16_x[i]);
// input_report_abs(fts_ts->input_dev, ABS_MT_POSITION_Y, event->au16_y[i]);
touchs |= BIT(event->au8_finger_id[i]);
fts_ts->touchs |= BIT(event->au8_finger_id[i]);
TP_DBG("finger true\n");
TP_DBG("report_abs_X = %d, report_abs_Y = %d !\n", event->au16_x[i], event->au16_y[i]);
if(touch_down_up_status == 1)
{
//send mouse motion event;
emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION;
emouse.x = event->au16_x[0] > 479 ? 479 : event->au16_x[0];
emouse.y = event->au16_y[0];
emouse.ts = rt_tick_get();
if (xx != 0 || yy != 0 || (xx == 0 && yy == 0))
{
if (xx != emouse.x || emouse.y != yy)
{
rtgui_server_post_event(&emouse.parent, sizeof(emouse));
TP_DBG("RTGUI_EVENT_MOUSE_MOTION x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]);
zz = 0;
}
else
{
zz ++;
}
}
xx = emouse.x;
yy = emouse.y;
if (zz >= 10)
{
xx = 0;
yy = 0;
}
}
}
else
{
uppoint++;
// input_mt_report_slot_state(fts_ts->input_dev, MT_TOOL_FINGER, false);
fts_ts->touchs &= ~BIT(event->au8_finger_id[i]);
}
}
if (0 == (fts_ts->touchs ^ touchs))
{
for (i = 0; i < CFG_MAX_TOUCH_POINTS; i++)
{
if (BIT(i) & (fts_ts->touchs ^ touchs))
{
// input_mt_slot(fts_ts->input_dev, i);
// input_mt_report_slot_state(fts_ts->input_dev, MT_TOOL_FINGER, false);
TP_DBG("finger false\n");
}
}
}
fts_ts->touchs = touchs;
if(event->touch_point == uppoint && touch_down_up_status == 1)
{
// input_report_key(fts_ts->input_dev, BTN_TOUCH, 0);
touch_down_up_status = 0;
TP_DBG("touch up !\n");
/* Always send touch up event. */
emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_UP;
emouse.x = event->au16_x[0] > 479 ? 479 : event->au16_x[0];
emouse.y = event->au16_y[0];
emouse.ts = rt_tick_get();
do
{
result = rtgui_server_post_event(&emouse.parent, sizeof(emouse));
if (result != RT_EOK)
{
rt_thread_delay(RT_TICK_PER_SECOND / 10);
}
}
while (result != RT_EOK);
TP_DBG("RTGUI_MOUSE_BUTTON_UP x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]);
}
else
{
// input_report_key(fts_ts->input_dev, BTN_TOUCH, event->touch_point > 0);
if (touch_down_up_status == 0)
{
touch_down_up_status = 1;
TP_DBG("touch down !\n");
//send mouse down event
emouse.parent.sender = RT_NULL;
emouse.wid = RT_NULL;
emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
emouse.button = RTGUI_MOUSE_BUTTON_LEFT | RTGUI_MOUSE_BUTTON_DOWN;
emouse.x = event->au16_x[0] > 479 ? 479 : event->au16_x[0];
emouse.y = event->au16_y[0];
emouse.ts = rt_tick_get();
emouse.id = emouse.ts;
do
{
result = rtgui_server_post_event(&emouse.parent, sizeof(emouse));
if (result != RT_EOK)
{
rt_thread_delay(RT_TICK_PER_SECOND / 10);
}
}
while (result != RT_EOK);
TP_DBG("RTGUI_MOUSE_BUTTON_DOWN x=%d,y=%d\n",event->au16_x[0],event->au16_y[0]);
}
}
return 0;
}
/************************************************************************
* Name: fts_get_upgrade_array
* Brief: decide which ic
* Input: no
* Output: get ic info in fts_updateinfo_curr
* Return: no
***********************************************************************/
static void fts_get_upgrade_array(struct fts_ts_data *fts_ts)
{
uint8_t reg_ofs;
uint8_t chip_id;
uint32_t i;
reg_ofs = FTS_REG_CHIP_ID;
fts_i2c_Read(fts_ts,&reg_ofs,1,&chip_id,1);
TP_DBG("%s chip_id = %x\n", __func__, chip_id);
for (i = 0; i < sizeof(fts_updateinfo) / sizeof(struct Upgrade_Info); i++)
{
if (chip_id == fts_updateinfo[i].CHIP_ID)
{
memcpy(&fts_updateinfo_curr, &fts_updateinfo[i], sizeof(struct Upgrade_Info));
break;
}
}
if(i >= sizeof(fts_updateinfo)/sizeof(struct Upgrade_Info))
{
memcpy(&fts_updateinfo_curr, &fts_updateinfo[0], sizeof(struct Upgrade_Info));
}
}
/************************************************************************
* Name: fts_ts_probe
* Brief: driver entrance function for initial/power on/create channel
* Input: i2c info, device id
* Output: no
* Return: 0
***********************************************************************/
int fts_ts_probe(struct fts_ts_data *fts_ts,struct rt_i2c_bus_device *i2c_bus, const uint8_t addr)
{
int err = 0;
uint8_t uc_reg_value;
uint8_t uc_reg_addr;
TP_DBG("FT device prob process Start !\n");
fts_ts->i2c_bus = i2c_bus;
fts_ts->addr = addr;
fts_ts->init_success = 0;
if (fts_ts->x_max > TOUCH_MAX_X)
fts_ts->x_max = TOUCH_MAX_X;
if (fts_ts->y_max > TOUCH_MAX_Y)
fts_ts->y_max = TOUCH_MAX_Y;
fts_get_upgrade_array(fts_ts);
/*get some register information */
uc_reg_addr = FTS_REG_FW_VER;
err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1);
if (err < 0)
{
fts_ts->init_success = 0;
fts_ts->fw_ver = 0xff;
}
else
{
fts_ts->init_success = 1;
TP_DBG("Firmware version = 0x%x\n", uc_reg_value);
fts_ts->fw_ver = uc_reg_value;
}
uc_reg_addr = FTS_REG_POINT_RATE;
err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1);
if (err < 0)
fts_ts->init_success = 0;
else
{
fts_ts->init_success = 1;
TP_DBG("report rate is %dHz.\n", uc_reg_value * 10);
}
uc_reg_addr = FTS_REG_THGROUP;
err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1);
if (err < 0)
fts_ts->init_success = 0;
else
{
fts_ts->init_success = 1;
TP_DBG("touch threshold is %d.\n", uc_reg_value * 4);
}
uc_reg_addr = FTS_REG_VENDOR_ID;
err = fts_i2c_Read(fts_ts, &uc_reg_addr, 1, &uc_reg_value, 1);
if (err < 0)
fts_ts->init_success = 0;
else
{
fts_ts->init_success = 1;
TP_DBG("VENDOR ID = 0x%x\n", uc_reg_value);
}
if (fts_ts->init_success == 1)
fts_init_success = 1;
return 0;
}
/************************************************************************
* Name: fts_ts_interrupt
* Brief: the focaltech device will signal the host about TRIGGER_FALLING, and processed when the interrupt is asserted.
* Input: irq, device id
* Output: no
* Return: irq handle
***********************************************************************/
static void fts_ts_interrupt(struct fts_ts_data *fts_ts)
{
rt_sem_release(&fts_ts->sem);
return ;
}
static void thread_fts_ts_service(void *param)
{
struct fts_ts_data *fts_ts = (struct fts_ts_data *)param;
int ret = 0;
while(rt_sem_take(&fts_ts->sem,RT_WAITING_FOREVER) == RT_EOK)
{
#ifdef FTS_GESTRUE
i2c_smbus_read_i2c_block_data(fts_ts->client, 0xd0, 1, &state);
/*TP_DBG("tpd fts_read_Gestruedata state=%d\n", state);*/
if (state == 1)
{
fts_read_Gestruedata(fts_ts);
rt_hw_interrupt_umask(fts_ts->irq);
/*continue;*/
}
else
{
#endif
//disable_irq_nosync(fts_ts->irq);
ret = fts_read_Touchdata(fts_ts);
if (ret == 0)
fts_report_value(fts_ts);
rt_thread_delay(RT_TICK_PER_SECOND / 30);
#ifdef FTS_GESTRUE
}
#endif
}
}
static struct fts_ts_data g_fts_ts =
{
.addr = 0,
.fw_ver = 0, //firmware version
.x_min = 0,
.x_max = 480,
.y_min = 0,
.y_max = 320,
.touchs = 0,
.init_success = 0,
};
int rt_hw_touch_init(void)
{
struct rt_i2c_bus_device *i2c_bus;
#define TP_INT_PORT GPIO_PORT_C
#define TP_INT_PIN GPIO_Pin_25
/* init IO */
gpio_direction_input(TP_INT_PORT,TP_INT_PIN);
gpio_enable_pull(TP_INT_PORT,TP_INT_PIN);
/* register irq */
gpio_mask_irq(TP_INT_PORT,TP_INT_PIN);
gpio_set_func(TP_INT_PORT,TP_INT_PIN,GPIO_INPUT_PULL | GPIO_INT_FE);
gpio_set_irq_callback(TP_INT_PORT,TP_INT_PIN,fts_ts_interrupt, (void*)&g_fts_ts);
/* try to probe device */
i2c_bus = rt_i2c_bus_device_find("i2c0");
if (i2c_bus == RT_NULL)
{
rt_kprintf("[TP]:can't find the i2c bus:%s\n", "i2c0");
return -RT_EIO;
}
fts_ts_probe(&g_fts_ts,i2c_bus,FTS_SLAVE_ADDR);
if(g_fts_ts.init_success == 1)
{
rt_thread_t tid;
/* init semaphore wakeup thread... */
rt_sem_init(&g_fts_ts.sem,"tp_sem",0,RT_IPC_FLAG_FIFO);
/* create thread for fts device */
tid = rt_thread_create("tp_srv",
thread_fts_ts_service, (void *) &g_fts_ts,
2048,
RT_TOUCH_THREAD_PRIORITY,
10);
if(tid != RT_NULL)
rt_thread_startup(tid);
/* enable interrupt */
gpio_unmask_irq(TP_INT_PORT,TP_INT_PIN);
return RT_EOK;
}
return -RT_EIO;
}
INIT_DEVICE_EXPORT(rt_hw_touch_init);
#endif /* RT_USING_FT6x06 */