linux下调试cst8xx触摸屏驱动
硬件描述:具体没找到硬件的描述,一般电容触摸屏关键就是4个引脚:i2c,rst,irq,调试中遇到的问题1.i2c没调通,读不到数据答:用示波器测量i2c波形不正常,硬件修改了下上拉电阻就可以了2.出现点击触摸屏会导致内核崩溃:经查是因为在中断中加锁了,但还用延时函数导致,但必须要加延时。追溯发现原驱动中使用request_irq在中断中有延时就会出现内核崩溃,后来改成request_thread
硬件描述:
具体没找到硬件的描述,一般电容触摸屏关键就是4个引脚:i2c,rst,irq,
调试中遇到的问题
1.i2c没调通,读不到数据
答:用示波器测量i2c波形不正常,硬件修改了下上拉电阻就可以了
2.出现点击触摸屏会导致内核崩溃:
经查是因为在中断中加锁了,但还用延时函数导致,但必须要加延时。追溯发现原驱动中使用request_irq在中断中有延时就会出现内核崩溃,后来改成request_threaded_irq就解决了这个问题
调试好的代码:
dts:
hynitron@15 {
compatible = “hynitron,cst8xx”;
reg = <0x15>;
/* interrupt-parent = <&tlmm>; /
interrupts = <65 0x2>;
/ vdd-supply = <&pm8916_l17>;
vcc_i2c-supply = <&pm8916_l5>; /
/ pins used by touchscreen /
pinctrl-names = “pmx_ts_active”,
“pmx_ts_suspend”,
“pmx_ts_release”;
/ pinctrl-0 = <&ts_int_active &ts_reset_active>;
pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
pinctrl-2 = <&ts_release>; */
hynitron,name = “hyn_ts”;
hynitron,family-id = <0x06>;
/*hynitron,reset-gpio = <&tlmm 64 0x0>;
hynitron,irq-gpio = <&tlmm 65 0x2008>; */
hynitron,reset-gpio = <&gpio4 GPIO_B6 GPIO_ACTIVE_LOW>;
hynitron,irq-gpio = <&gpio3 GPIO_C4 IRQ_TYPE_LEVEL_HIGH>;
hynitron,display-coords = <0 0 1024 768>;
hynitron,panel-coords = <0 0 1024 768>;
hynitron,button-map= <139 102 158>;
hynitron,no-force-update;
hynitron,i2c-pull-up;
hynitron,group-id = <1>;
hynitron,hard-reset-delay-ms = <20>;
hynitron,soft-reset-delay-ms = <200>;
hynitron,num-max-touches = <10>;
hynitron,fw-delay-aa-ms = <30>;
hynitron,fw-delay-55-ms = <30>;
hynitron,fw-upgrade-id1 = <0x79>;
hynitron,fw-upgrade-id2 = <0x08>;
hynitron,fw-delay-readid-ms = <10>;
hynitron,fw-delay-era-flsh-ms = <2000>;
hynitron,fw-auto-cal;
hynitron,ignore-id-check;
hynitron,resume-in-workqueue;
};
drivers:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#if defined(CONFIG_FB)
#include <linux/notifier.h>
#include <linux/fb.h>
#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#define FTS_SUSPEND_LEVEL 1 /* Early-suspend level /
#endif
#include “hyn_core.h”
#include “hyn_common.h”
/****************************************************************************
- Private constant and macro definitions using #define
****************************************************************************/
#define HYN_DRIVER_NAME “hyn_ts”
#define INTERVAL_READ_REG 200 / unit:ms /
#define TIMEOUT_READ_REG 1000 / unit:ms */
#if HYN_POWER_SOURCE_CUST_EN
#define HYN_VTG_MIN_UV 2800000
#define HYN_VTG_MAX_UV 3300000
#define HYN_I2C_VTG_MIN_UV 1800000
#define HYN_I2C_VTG_MAX_UV 1800000
#endif
#define HYN_I2C_ADDR 0x2A
/*****************************************************************************
- Global variable or extern global variabls/functions
*****************************************************************************/
struct hyn_ts_data *hyn_data;
/*****************************************************************************
- Static function prototypes
*****************************************************************************/
//static int hyn_ts_suspend(struct device *dev);
static int hyn_ts_resume(struct device *dev);
#if 0
//static int hyn_read(u8 *cmd, u32 cmdlen, u8 *data, u32 datalen)
static int hyn_read(u8 cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret=0;
#if 1
int retry;
struct i2c_client *client = hyn_data->client;
struct i2c_msg msg[2];
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = cmdlen;
msg[0].buf = &cmd;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
//msg[1].len = datalen;
msg[1].len = 1;
msg[1].buf = data;
#endif
printk("cmd ========= 0x%x,cmdlen ========= %d \r\n",cmd,cmdlen);
mutex_lock(&hyn_data->bus_lock);
#if 0
ret = cam_iic_buf_write(HYN_I2C_ADDR, cmd,cmdlen);
ret = cam_iic_buf_read(HYN_I2C_ADDR, data,datalen);
#else
for (retry = 0; retry < 3; retry++)
{
if (i2c_transfer(client->adapter, msg, 2) == 2)
break;
msleep(20);
}
//ret = i2c_transfer(client->adapter, msg, 2);
#endif
mutex_unlock(&hyn_data->bus_lock);
printk("datalen ==========2020.10.15============ %d \r\n",datalen);
//ret = ret;
return ret;
}
#else
#endif
#if 1
static int hyn_read_aa(struct i2c_client client,u8 cmd, u32 cmdlen, u8 *data, u32 datalen)
{
int ret=0;
int retry;
struct i2c_msg msg[2];
mutex_lock(&hyn_data->bus_lock);
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = cmd;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = datalen;
msg[1].buf = data;
for(retry = 0; retry < 2; retry++)
{
if ((ret=i2c_transfer(client->adapter, msg, 2)) == 2)
break;
msleep(20);
}
mutex_unlock(&hyn_data->bus_lock);
return ret;
}
#endif
#if 0
static int hyn_read_reg(u8 addr, u8 *value)
{
return hyn_read(&addr, 1, value, 1);
}
#else
static int hyn_read_reg_aa(struct i2c_client *client,u8 addr, u8 *value)
{
//return hyn_read_aa(client,addr, 1, value, 1);
return hyn_read_aa(client,&addr, 1, value, 1);
}
#endif
#if 0
static int hyn_write(u8 *writebuf, u32 writelen)
{
int ret;
mutex_lock(&hyn_data->bus_lock);
ret = cam_iic_buf_write(HYN_I2C_ADDR, writebuf,writelen);
mutex_unlock(&hyn_data->bus_lock);
return ret;
}
static int hyn_write_reg(u8 addr, u8 value)
{
u8 buf[2] = { 0 };
buf[0] = addr;
buf[1] = value;
return hyn_write(buf, sizeof(buf));
}
#endif
static int hyn_bus_init(struct hyn_ts_data *ts_data)
{
HYN_FUNC_ENTER();
ts_data->bus_buf = NULL;
HYN_FUNC_EXIT();
return 0;
}
static int hyn_bus_exit(struct hyn_ts_data *ts_data)
{
HYN_FUNC_ENTER();
HYN_FUNC_EXIT();
return 0;
}
static int hyn_reset_proc(int hdelayms)
{
HYN_DEBUG(“tp reset”);
//ak_gpio_setpin(hyn_data->pdata->reset_gpio, AK_GPIO_OUT_LOW);
gpio_set_value(hyn_data->pdata->reset_gpio, 0);
msleep(5);
//ak_gpio_setpin(hyn_data->pdata->reset_gpio, AK_GPIO_OUT_HIGH);
gpio_set_value(hyn_data->pdata->reset_gpio, 1);
if (hdelayms) {
msleep(hdelayms);
}
return 0;
}
/*****************************************************************************
-
Name: hyn_wait_tp_to_valid
-
Brief: Read chip id until TP FW become valid(Timeout: TIMEOUT_READ_REG),
-
need call when reset/power on/resume...
-
Input:
-
Output:
-
Return: return 0 if tp valid, otherwise return error code
*****************************************************************************/
static int hyn_wait_tp_to_valid(void)
{
int ret = 0;
int cnt = 0;
u8 reg_value = 0;
u8 chip_id = hyn_data->ic_info.ids.chip_idl;
struct i2c_client *client = hyn_data->client;do {
#if 0 ret = hyn_read_reg(HYN_REG_CHIP_ID, ®_value); #else ret = hyn_read_reg_aa(client,HYN_REG_CHIP_ID, ®_value); #endif if ((ret < 0) || (reg_value != chip_id))// { HYN_DEBUG("TP Not Ready, ReadData = 0x%x", reg_value); } else if (reg_value == chip_id) { HYN_INFO("TP Ready, Device ID = 0x%x", reg_value); return 0; } cnt++; msleep(INTERVAL_READ_REG);
} while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
return -EIO;
}
/*****************************************************************************
- Name: hyn_tp_state_recovery
- Brief: Need execute this function when reset
- Input:
- Output:
- Return:
*****************************************************************************/
static void hyn_tp_state_recovery(struct hyn_ts_data ts_data)
{
HYN_FUNC_ENTER();
/ wait tp stable */
hyn_wait_tp_to_valid();
HYN_FUNC_EXIT();
}
#if 0
static void hyn_irq_disable(void)
{
unsigned long irqflags;
HYN_FUNC_ENTER();
spin_lock_irqsave(&hyn_data->irq_lock, irqflags);
if (!hyn_data->irq_disabled) {
disable_irq_nosync(hyn_data->irq);
hyn_data->irq_disabled = true;
}
spin_unlock_irqrestore(&hyn_data->irq_lock, irqflags);
HYN_FUNC_EXIT();
}
#endif
static void hyn_irq_enable(void)
{
unsigned long irqflags = 0;
HYN_FUNC_ENTER();
spin_lock_irqsave(&hyn_data->irq_lock, irqflags);
if (hyn_data->irq_disabled) {
enable_irq(hyn_data->irq);
hyn_data->irq_disabled = false;
}
spin_unlock_irqrestore(&hyn_data->irq_lock, irqflags);
HYN_FUNC_EXIT();
}
/*****************************************************************************
-
Name: hyn_get_ic_information
-
Brief: read chip id to get ic information, after run the function, driver w-
-
ill know which IC is it.
-
If cant get the ic information, maybe not hyntrion's touch IC, need
-
unregister the driver
-
Input:
-
Output:
-
Return: return 0 if get correct ic information, otherwise return error code
*****************************************************************************/
static int hyn_get_ic_information(struct hyn_ts_data *ts_data)
{
int ret = 0;
int cnt = 0;
u8 chip_id[2] = { 0 };
struct i2c_client *client = ts_data->client;ts_data->ic_info.is_incell = HYN_CHIP_IDC;
ts_data->ic_info.hid_supported = HYN_HID_SUPPORTTED;do {
#if 0 ret = hyn_read_reg(HYN_REG_CHIP_ID, &chip_id[0]); ret = hyn_read_reg(HYN_REG_CHIP_ID2, &chip_id[1]); #else ret = hyn_read_reg_aa(client,HYN_REG_CHIP_ID, &chip_id[0]); ret = hyn_read_reg_aa(client,HYN_REG_CHIP_ID2, &chip_id[1]); #endif HYN_DEBUG("i2c read invalid, read:0x%02x%02x %d",chip_id[0], chip_id[1], ret); printk("i2c read invalid, read:0x%02x%02x %d \r\n",chip_id[0], chip_id[1], ret); if (ret < 0) { HYN_DEBUG("i2c read invalid, read:0x%02x%02x",chip_id[0], chip_id[1]); } else { ts_data->ic_info.ids.chip_idl = chip_id[0]; } cnt++; msleep(INTERVAL_READ_REG);
} while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
if ((cnt * INTERVAL_READ_REG) >= TIMEOUT_READ_REG) {
HYN_INFO(“fw is invalid, need read boot id”);
ts_data->ic_info.ids.chip_idl = 0xFF;
}HYN_INFO(“get ic information, chip id = 0x%02x%02x”,
ts_data->ic_info.ids.chip_idh, ts_data->ic_info.ids.chip_idl);return 0;
}
#if HYN_FW_UPDATA
#include “capacitive_hynitron_cst7xx_update.h”
extern unsigned char app_bin[];
static unsigned char *p_cst836u_upgrade_firmware;
#define REG_LEN_1B 1
#define REG_LEN_2B 2
static int hctp_write_bytes(unsigned short reg,unsigned char *buf,unsigned short len,unsigned char reg_len){
int ret;
unsigned char mbuf[600];
if (reg_len == 1){
mbuf[0] = reg;
memcpy(mbuf+1,buf,len);
}else{
mbuf[0] = reg>>8;
mbuf[1] = reg;
memcpy(mbuf+2,buf,len);
}
ret = hyn_write(mbuf, len+reg_len);
return ret;
}
/*
*
/
static int hctp_read_bytes(unsigned short reg,unsigned char buf,unsigned short len,unsigned char reg_len){
int ret;
unsigned char reg_buf[2];
struct i2c_client *client = hyn_data->client;
if (reg_len == 1){
reg_buf[0] = reg;
}else{
reg_buf[0] = reg>>8;
reg_buf[1] = reg;
}
#if 0
ret = hyn_read(reg_buf,reg_len,buf,len);
#else
ret = hyn_read_aa(client,reg_buf,reg_len,buf,len);
#endif
return ret;
}
static int cst78xx_enter_bootmode(void){
char retryCnt = 10;
hyn_reset_proc(5);
while(retryCnt--){
u8 cmd[3];
cmd[0] = 0xAA;
if (-1 == hctp_write_bytes(0xA001,cmd,1,REG_LEN_2B)){ // enter program mode
mdelay(2); // 4ms
continue;
}
if (-1 == hctp_read_bytes(0xA003,cmd,1,REG_LEN_2B)) { // read flag
mdelay(2); // 4ms
continue;
}else{
if (cmd[0] != 0x55){
msleep(2); // 4ms
continue;
}else{
return 0;
}
}
}
return -1;
}
static u32 cst78xx_read_checksum(u16 startAddr,u16 len){
union{
u32 sum;
u8 buf[4];
}checksum;
char cmd[3];
char readback[4] = {0};
if (cst78xx_enter_bootmode() == -1){
return -1;
}
cmd[0] = 0;
if (-1 == hctp_write_bytes(0xA003,cmd,1,REG_LEN_2B)){
return -1;
}
msleep(500);
if (-1 == hctp_read_bytes(0xA000,readback,1,REG_LEN_2B)){
return -1;
}
if (readback[0] != 1){
return -1;
}
if (-1 == hctp_read_bytes(0xA008,checksum.buf,4,REG_LEN_2B)){
return -1;
}
// chip_sumok_flag = 1;
return checksum.sum;
}
static int cst78xx_update(u16 startAddr,u16 len,u8* src){
u16 sum_len;
u8 cmd[10];
int ret;
ret = 0;
if (cst78xx_enter_bootmode() == -1){
return -1;
}
sum_len = 0;
#define PER_LEN 512
do{
if (sum_len >= len){
return -1;
}
// send address
cmd[1] = startAddr>>8;
cmd[0] = startAddr&0xFF;
hctp_write_bytes(0xA014,cmd,2,REG_LEN_2B);
#if HYN_MTK_IIC_TRANSFER_LIMIT
{
u8 temp_buf[8];
u16 j,iic_addr;
iic_addr=0;
for(j=0; j<128; j++){
temp_buf[0] = *((u8*)src+iic_addr+0);
temp_buf[1] = *((u8*)src+iic_addr+1);
temp_buf[2] = *((u8*)src+iic_addr+2);
temp_buf[3] = *((u8*)src+iic_addr+3);
hctp_write_bytes((0xA018+iic_addr),(u8* )temp_buf,4,REG_LEN_2B);
iic_addr+=4;
if(iic_addr==512) break;
}
}
#else
hctp_write_bytes(0xA018,src,PER_LEN,REG_LEN_2B);
#endif
cmd[0] = 0xEE;
hctp_write_bytes(0xA004,cmd,1,REG_LEN_2B);
mdelay(100);
{
u8 retrycnt = 50;
while(retrycnt--){
cmd[0] = 0;
hctp_read_bytes(0xA005,cmd,1,REG_LEN_2B);
if (cmd[0] == 0x55){
// success
break;
}
msleep(10);
}
if(cmd[0]!=0x55)
{
ret = -1;
}
}
startAddr += PER_LEN;
src += PER_LEN;
sum_len += PER_LEN;
}while(len);
// exit program mode
cmd[0] = 0x00;
hctp_write_bytes(0xA003,cmd,1,REG_LEN_2B);
return ret;
}
int hyn_ctpm_fw_upgrade_with_i_file(void)
{
unsigned short startAddr;
unsigned short length;
unsigned short checksum;
unsigned short chipchecksum;
startAddr = *(p_cst836u_upgrade_firmware+1);
length =*(p_cst836u_upgrade_firmware+3);
checksum = *(p_cst836u_upgrade_firmware+5);
startAddr <<= 8;
startAddr |= *(p_cst836u_upgrade_firmware+0);
length <<= 8;
length |= *(p_cst836u_upgrade_firmware+2);
checksum <<= 8;
checksum |= *(p_cst836u_upgrade_firmware+4);
cst78xx_update(startAddr, length, (p_cst836u_upgrade_firmware+6));
chipchecksum = cst78xx_read_checksum(startAddr, length);;
printk("\r\nCTP cst78xx update %s, checksum-0x%04x",((chipchecksum==checksum) ? "success" : "fail"),chipchecksum);
return 0;
}
unsigned char hyn_ctpm_get_upg_ver(void)
{
unsigned int ui_sz;
p_cst836u_upgrade_firmware=(unsigned char *)app_bin;
ui_sz = sizeof(app_bin);
if (ui_sz > 2)
{
return *(p_cst836u_upgrade_firmware+0x3BFC+6);
}
else
return 0;
}
#endif
/*****************************************************************************
-
Reprot related
*****************************************************************************/
static void hyn_show_touch_buffer(u8 *data, int datalen)
{
int i = 0;
int count = 0;
char *tmpbuf = NULL;tmpbuf = kzalloc(1024, GFP_KERNEL);
if (!tmpbuf) {
HYN_ERROR(“tmpbuf zalloc fail”);
return;
}for (i = 0; i < datalen; i++) {
count += snprintf(tmpbuf + count, 1024 - count, “%02X,”, data[i]);
if (count >= 1024)
break;
}
HYN_DEBUG(“point buffer:%s”, tmpbuf);if (tmpbuf) {
kfree(tmpbuf);
tmpbuf = NULL;
}
}
static void hyn_release_all_finger(void)
{
struct input_dev *input_dev = hyn_data->input_dev;
#if HYN_MT_PROTOCOL_B_EN
u32 finger_count = 0;
u32 max_touches = hyn_data->pdata->max_touch_number;
#endif
HYN_FUNC_ENTER();
mutex_lock(&hyn_data->report_mutex);
#if HYN_MT_PROTOCOL_B_EN
for (finger_count = 0; finger_count < max_touches; finger_count++) {
input_mt_slot(input_dev, finger_count);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
}
#else
input_mt_sync(input_dev);
#endif
input_report_key(input_dev, BTN_TOUCH, 0);
input_sync(input_dev);
hyn_data->touchs = 0;
hyn_data->key_state = 0;
mutex_unlock(&hyn_data->report_mutex);
HYN_FUNC_EXIT();
}
/*****************************************************************************
-
Name: fts_input_report_key
-
Brief: process key events,need report key-event if key enable.
-
if point's coordinate is in (x_dim-50,y_dim-50) ~ (x_dim+50,y_dim+50),
-
need report it to key event.
-
x_dim: parse from dts, means key x_coordinate, dimension:+-50
-
y_dim: parse from dts, means key y_coordinate, dimension:+-50
-
Input:
-
Output:
-
Return: return 0 if it’s key event, otherwise return error code
*****************************************************************************/
static int hyn_input_report_key(struct hyn_ts_data *data, int index)
{
int i = 0;
int x = data->events[index].x;
int y = data->events[index].y;
int *x_dim = &data->pdata->key_x_coords[0];
int *y_dim = &data->pdata->key_y_coords[0];if (!data->pdata->have_key) {
return -EINVAL;
}
for (i = 0; i < data->pdata->key_number; i++) {
if ((x >= x_dim[i] - HYN_KEY_DIM) && (x <= x_dim[i] + HYN_KEY_DIM) &&
(y >= y_dim[i] - HYN_KEY_DIM) && (y <= y_dim[i] + HYN_KEY_DIM)) {
if (EVENT_DOWN(data->events[index].flag)
&& !(data->key_state & (1 << i))) {
input_report_key(data->input_dev, data->pdata->keys[i], 1);
data->key_state |= (1 << i);
HYN_DEBUG(“Key%d(%d,%d) DOWN!”, i, x, y);
} else if (EVENT_UP(data->events[index].flag)
&& (data->key_state & (1 << i))) {
input_report_key(data->input_dev, data->pdata->keys[i], 0);
data->key_state &= ~(1 << i);
HYN_DEBUG(“Key%d(%d,%d) Up!”, i, x, y);
}
return 0;
}
}
return -EINVAL;
}
#if HYN_MT_PROTOCOL_B_EN
static int hyn_input_report_b(struct hyn_ts_data *data)
{
int i = 0;
int uppoint = 0;
int touchs = 0;
bool va_reported = false;
u32 max_touch_num = data->pdata->max_touch_number;
struct ts_event *events = data->events;
HYN_FUNC_ENTER();
for (i = 0; i < data->touch_point; i++) {
if (hyn_input_report_key(data, i) == 0) {
continue;
}
va_reported = true;
input_mt_slot(data->input_dev, events[i].id);
if (EVENT_DOWN(events[i].flag)) {
input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true);
#if HYN_REPORT_PRESSURE_EN
if (events[i].p <= 0) {
events[i].p = 0x3f;
}
input_report_abs(data->input_dev, ABS_MT_PRESSURE, events[i].p);
#endif
if (events[i].area <= 0) {
events[i].area = 0x09;
}
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y);
touchs |= BIT(events[i].id);
data->touchs |= BIT(events[i].id);
if ((data->log_level >= 2) ||
((1 == data->log_level) && (HYN_TOUCH_DOWN == events[i].flag))) {
HYN_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
events[i].id,
events[i].x, events[i].y,
events[i].p, events[i].area);
}
} else {
uppoint++;
input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false);
data->touchs &= ~BIT(events[i].id);
if (data->log_level >= 1) {
HYN_DEBUG("[B]P%d UP!", events[i].id);
}
}
}
printk("liqw--- tp_x =%d , tp_y = %d \n",events[i].x,events[i].y);
if (unlikely(data->touchs ^ touchs)) {
for (i = 0; i < max_touch_num; i++) {
if (BIT(i) & (data->touchs ^ touchs)) {
if (data->log_level >= 1) {
HYN_DEBUG("[B]P%d UP!", i);
}
va_reported = true;
input_mt_slot(data->input_dev, i);
input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, false);
}
}
}
data->touchs = touchs;
if (va_reported) {
/* touchs==0, there's no point but key */
if (EVENT_NO_DOWN(data) || (!touchs)) {
if (data->log_level >= 1) {
HYN_DEBUG("[B]Points All Up!");
}
input_report_key(data->input_dev, BTN_TOUCH, 0);
} else {
input_report_key(data->input_dev, BTN_TOUCH, 1);
}
}
input_sync(data->input_dev);
HYN_FUNC_EXIT();
return 0;
}
#else
static int hyn_input_report_a(struct hyn_ts_data *data)
{
int i = 0;
int touchs = 0;
bool va_reported = false;
struct ts_event *events = data->events;
for (i = 0; i < data->touch_point; i++) {
if (hyn_input_report_key(data, i) == 0) {
continue;
}
va_reported = true;
if (EVENT_DOWN(events[i].flag)) {
input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, events[i].id);
#if HYN_REPORT_PRESSURE_EN
if (events[i].p <= 0) {
events[i].p = 0x3f;
}
input_report_abs(data->input_dev, ABS_MT_PRESSURE, events[i].p);
#endif
if (events[i].area <= 0) {
events[i].area = 0x09;
}
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, events[i].area);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, events[i].x);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, events[i].y);
input_mt_sync(data->input_dev);
if ((data->log_level >= 2) ||
((1 == data->log_level) && (HYN_TOUCH_DOWN == events[i].flag))) {
HYN_DEBUG("[A]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
events[i].id,
events[i].x, events[i].y,
events[i].p, events[i].area);
}
touchs++;
}
}
/* last point down, current no point but key */
if (data->touchs && !touchs) {
va_reported = true;
}
data->touchs = touchs;
if (va_reported) {
if (EVENT_NO_DOWN(data)) {
if (data->log_level >= 1) {
HYN_DEBUG("[A]Points All Up!");
}
input_report_key(data->input_dev, BTN_TOUCH, 0);
input_mt_sync(data->input_dev);
} else {
input_report_key(data->input_dev, BTN_TOUCH, 1);
}
}
input_sync(data->input_dev);
return 0;
}
#endif
static int hyn_read_touchdata(struct hyn_ts_data *data)
{
//u8 value_1=0;
//u8 value_2=0;
//u8 value_3=0;
//u8 value_4=0;
//u8 value_5=0;
int ret = 0;
u8 *buf = data->point_buf;
struct i2c_client *client = data->client;
client = client;
memset(buf, 0xFF, data->pnt_buf_size);
#if 0
ret = hyn_read(buf, 1, buf, data->pnt_buf_size);
#else
#if 1
buf[0] = 0x00;
ret = hyn_read_aa(client,buf, 1, buf, data->pnt_buf_size);
#else
buf[0] = 0x00;
ret = hyn_read_aa(client,&buf[0], 1, &buf[0], data->pnt_buf_size);
printk("buf[0] =========0x00=========== 0x%x \r\n",buf[0]);
buf[1] = 0x01;
ret = hyn_read_aa(client,&buf[1], 1, &buf[1], data->pnt_buf_size);
printk("buf[1] =========0x00=========== 0x%x \r\n",buf[1]);
buf[2] = 0x02;
ret = hyn_read_aa(client,&buf[2], 1, &buf[2], data->pnt_buf_size);
printk("buf[2] =========0x02=========== 0x%x \r\n",buf[2]);
value_1 = buf[2];
buf[3] = 0x03;
ret = hyn_read_aa(client,&buf[3], 1, &buf[3], data->pnt_buf_size);
printk("buf[3] ==========0x03========== 0x%x \r\n",buf[3]);
value_2 = buf[3];
buf[4] = 0x04;
ret = hyn_read_aa(client,&buf[4], 1, &buf[4], data->pnt_buf_size);
printk("buf[4] ==========0x04========== 0x%x \r\n",buf[4]);
value_3 = buf[4];
buf[5] = 0x05;
ret = hyn_read_aa(client,&buf[5], 1, &buf[5], data->pnt_buf_size);
printk("buf[5] ==========0x05========== 0x%x \r\n",buf[5]);
value_4 = buf[5];
buf[6] = 0x06;
ret = hyn_read_aa(client,&buf[6], 1, &buf[6], data->pnt_buf_size);
printk("buf[6] ==========0x06========== 0x%x \r\n",buf[6]);
value_5 = buf[6];
buf[7] = 0x07;
ret = hyn_read_aa(client,&buf[7], 1, &buf[7], data->pnt_buf_size);
printk("buf[7] ==========0x06========== 0x%x \r\n",buf[7]);
buf[8] = 0x08;
ret = hyn_read_aa(client,&buf[8], 1, &buf[8], data->pnt_buf_size);
printk("buf[8] ==========0x06========== 0x%x \r\n",buf[8]);
printk("touch num status =================== %d \r\n",(value_2&0xc0)>>6);
printk("x ===================== %d \r\n",(((value_2&0x0f)<<8) | value_3));
printk("y ===================== %d \r\n",(((value_4&0x0f)<<8) | value_5));
#endif
#endif
if (ret < 0) {
HYN_ERROR("read touchdata failed, ret:%d", ret);
return ret;
}
if (data->log_level >= 3) {
hyn_show_touch_buffer(buf, data->pnt_buf_size);
}
return 0;
}
static int hyn_read_parse_touchdata(struct hyn_ts_data *data)
{
int ret = 0;
int i = 0;
u8 pointid = 0;
int base = 0;
struct ts_event *events = data->events;
int max_touch_num = data->pdata->max_touch_number;
u8 *buf = data->point_buf;
ret = hyn_read_touchdata(data);
//printk("ret ==============hyn_read_touchdata============== %d \r\n",ret);
if (ret) {
return ret;
}
data->point_num = buf[2] & 0x0F;
data->touch_point = 0;
if (data->point_num > max_touch_num) {
HYN_INFO("invalid point_num(%d)", data->point_num);
return -EIO;
}
for (i = 0; i < max_touch_num; i++) {
base = HYN_ONE_TCH_LEN * i;
pointid = (buf[5 + base]) >> 4;
if (pointid >= HYN_MAX_ID)
break;
//else if (pointid >= max_touch_num) {
// HYN_ERROR("ID(%d) beyond max_touch_number", pointid);
// return -EINVAL;
//}
//data->touch_point++;
events[i].x = ((buf[3 + base] & 0x0F) << 8) +
(buf[4 + base] & 0xFF);
events[i].y = ((buf[5 + base] & 0x0F) << 8) +
(buf[6 + base] & 0xFF);
events[i].flag = buf[3 + base] >> 6;
events[i].id = buf[5 + base] >> 4;
events[i].area = buf[8 + base] >> 4;
events[i].p = buf[7 + base];
//printk("events[%d].flag====%d,events[%d].x ==== %d,events[%d].y ==== %d \r\n",i,events[i].flag,i,events[i].x,i,events[i].y);
data->touch_point++;
}
if (data->touch_point == 0) {
HYN_INFO("no touch point information");
return -EIO;
}
return 0;
}
static void hyn_irq_read_report(void)
{
int ret = 0;
struct hyn_ts_data *ts_data = hyn_data;
ret = hyn_read_parse_touchdata(ts_data);
if (ret == 0) {
mutex_lock(&ts_data->report_mutex);
#if HYN_MT_PROTOCOL_B_EN
hyn_input_report_b(ts_data);
#else
hyn_input_report_a(ts_data);
#endif
mutex_unlock(&ts_data->report_mutex);
}
}
static irqreturn_t hyn_irq_handler(int irq, void *data)
{
hyn_irq_read_report();
return IRQ_HANDLED;
}
static int hyn_irq_registration(struct hyn_ts_data *ts_data)
{
int ret = 0;
struct hyn_ts_platform_data *pdata = ts_data->pdata;
#if 0
struct i2c_client *client = ts_data->client;
u8 value = 0;
u8 addr = 0xaa;
while(1)
{
ret=hyn_read_aa(client,&addr, 1, &value, 1);
printk(“value ==============0x%x \r\n”,value);
}
#endif
//ts_data->irq = ak_gpio_to_irq(pdata->irq_gpio);
ts_data->irq = gpio_to_irq(pdata->irq_gpio);
pdata->irq_gpio_flags = IRQ_TYPE_EDGE_FALLING /*| IRQ_TYPE_EDGE_RISING*/;
HYN_INFO("== irq:%d, flag:%x", ts_data->irq, pdata->irq_gpio_flags);
#if 0
ret = request_irq(ts_data->irq, hyn_irq_handler,pdata->irq_gpio_flags,HYN_DRIVER_NAME, ts_data);
#else
ret = request_threaded_irq(ts_data->irq, NULL, hyn_irq_handler,IRQF_TRIGGER_FALLING | IRQF_ONESHOT,HYN_DRIVER_NAME, ts_data);
#endif
HYN_INFO("request_irq: ret =%d ", ret);
return ret;
}
static int hyn_input_init(struct hyn_ts_data *ts_data)
{
int ret = 0;
int key_num = 0;
struct hyn_ts_platform_data *pdata = ts_data->pdata;
struct input_dev *input_dev;
HYN_FUNC_ENTER();
input_dev = input_allocate_device();
if (!input_dev) {
HYN_ERROR("Failed to allocate memory for input device");
return -ENOMEM;
}
/* Init and register Input device */
input_dev->name = HYN_DRIVER_NAME;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = ts_data->dev;
input_set_drvdata(input_dev, ts_data);
__set_bit(EV_SYN, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
if (pdata->have_key) {
HYN_INFO("set key capabilities");
for (key_num = 0; key_num < pdata->key_number; key_num++)
input_set_capability(input_dev, EV_KEY, pdata->keys[key_num]);
}
#if HYN_MT_PROTOCOL_B_EN
input_mt_init_slots(input_dev, pdata->max_touch_number, INPUT_MT_DIRECT);
#else
input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0F, 0, 0);
#endif
input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0);
#if HYN_REPORT_PRESSURE_EN
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0);
#endif
ret = input_register_device(input_dev);
if (ret) {
HYN_ERROR("Input device registration failed");
input_set_drvdata(input_dev, NULL);
input_free_device(input_dev);
input_dev = NULL;
return ret;
}
ts_data->input_dev = input_dev;
HYN_FUNC_EXIT();
return 0;
}
static int hyn_report_buffer_init(struct hyn_ts_data *ts_data)
{
int point_num = 0;
int events_num = 0;
point_num = ts_data->pdata->max_touch_number;
ts_data->pnt_buf_size = point_num * HYN_ONE_TCH_LEN + 3;
ts_data->point_buf = (u8 *)kzalloc(ts_data->pnt_buf_size + 1, GFP_KERNEL);
if (!ts_data->point_buf) {
HYN_ERROR("failed to alloc memory for point buf");
return -ENOMEM;
}
events_num = point_num * sizeof(struct ts_event);
ts_data->events = (struct ts_event *)kzalloc(events_num, GFP_KERNEL);
if (!ts_data->events) {
HYN_ERROR("failed to alloc memory for point events");
kfree_safe(ts_data->point_buf);
return -ENOMEM;
}
return 0;
}
#if HYN_POWER_SOURCE_CUST_EN
/*****************************************************************************
-
Power Control
*****************************************************************************/
#if HYN_PINCTRL_EN
static int hyn_pinctrl_init(struct hyn_ts_data *ts)
{
int ret = 0;ts->pinctrl = devm_pinctrl_get(ts->dev);
if (IS_ERR_OR_NULL(ts->pinctrl)) {
HYN_ERROR(“Failed to get pinctrl, please check dts”);
ret = PTR_ERR(ts->pinctrl);
goto err_pinctrl_get;
}ts->pins_active = pinctrl_lookup_state(ts->pinctrl, “pmx_ts_active”);
if (IS_ERR_OR_NULL(ts->pins_active)) {
HYN_ERROR(“Pin state[active] not found”);
ret = PTR_ERR(ts->pins_active);
goto err_pinctrl_lookup;
}ts->pins_suspend = pinctrl_lookup_state(ts->pinctrl, “pmx_ts_suspend”);
if (IS_ERR_OR_NULL(ts->pins_suspend)) {
HYN_ERROR(“Pin state[suspend] not found”);
ret = PTR_ERR(ts->pins_suspend);
goto err_pinctrl_lookup;
}ts->pins_release = pinctrl_lookup_state(ts->pinctrl, “pmx_ts_release”);
if (IS_ERR_OR_NULL(ts->pins_release)) {
HYN_ERROR(“Pin state[release] not found”);
ret = PTR_ERR(ts->pins_release);
}return 0;
err_pinctrl_lookup:
if (ts->pinctrl) {
devm_pinctrl_put(ts->pinctrl);
}
err_pinctrl_get:
ts->pinctrl = NULL;
ts->pins_release = NULL;
ts->pins_suspend = NULL;
ts->pins_active = NULL;
return ret;
}
static int hyn_pinctrl_select_normal(struct hyn_ts_data *ts)
{
int ret = 0;
if (ts->pinctrl && ts->pins_active) {
ret = pinctrl_select_state(ts->pinctrl, ts->pins_active);
if (ret < 0) {
HYN_ERROR("Set normal pin state error:%d", ret);
}
}
return ret;
}
static int hyn_pinctrl_select_suspend(struct hyn_ts_data *ts)
{
int ret = 0;
if (ts->pinctrl && ts->pins_suspend) {
ret = pinctrl_select_state(ts->pinctrl, ts->pins_suspend);
if (ret < 0) {
HYN_ERROR("Set suspend pin state error:%d", ret);
}
}
return ret;
}
static int hyn_pinctrl_select_release(struct hyn_ts_data *ts)
{
int ret = 0;
if (ts->pinctrl) {
if (IS_ERR_OR_NULL(ts->pins_release)) {
devm_pinctrl_put(ts->pinctrl);
ts->pinctrl = NULL;
} else {
ret = pinctrl_select_state(ts->pinctrl, ts->pins_release);
if (ret < 0)
HYN_ERROR("Set gesture pin state error:%d", ret);
}
}
return ret;
}
#endif /* HYN_PINCTRL_EN */
static int hyn_power_source_ctrl(struct hyn_ts_data *ts_data, int enable)
{
int ret = 0;
if (IS_ERR_OR_NULL(ts_data->vdd)) {
HYN_ERROR("vdd is invalid");
return -EINVAL;
}
HYN_FUNC_ENTER();
if (enable) {
if (ts_data->power_disabled) {
HYN_DEBUG("regulator enable !");
gpio_direction_output(ts_data->pdata->reset_gpio, 0);
msleep(1);
ret = regulator_enable(ts_data->vdd);
if (ret) {
HYN_ERROR("enable vdd regulator failed,ret=%d", ret);
}
if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) {
ret = regulator_enable(ts_data->vcc_i2c);
if (ret) {
HYN_ERROR("enable vcc_i2c regulator failed,ret=%d", ret);
}
}
ts_data->power_disabled = false;
}
} else {
if (!ts_data->power_disabled) {
HYN_DEBUG("regulator disable !");
gpio_direction_output(ts_data->pdata->reset_gpio, 0);
msleep(1);
ret = regulator_enable(ts_data->vdd);
HYN_DEBUG("0000---regulator enable vdd for lcd !");
if (ret) {
HYN_ERROR("disable vdd regulator failed,ret=%d", ret);
}
if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) {
ret = regulator_disable(ts_data->vcc_i2c);
if (ret) {
HYN_ERROR("disable vcc_i2c regulator failed,ret=%d", ret);
}
}
ts_data->power_disabled = true;
}
}
HYN_FUNC_EXIT();
return ret;
}
/*****************************************************************************
-
Name: hyn_power_source_init
-
Brief: Init regulator power:vdd/vcc_io(if have), generally, no vcc_io
-
vdd---->vdd-supply in dts, kernel will auto add "-supply" to parse
-
Must be call after hyn_gpio_configure() execute,because this function
-
will operate reset-gpio which request gpio in hyn_gpio_configure()
-
Input:
-
Output:
-
Return: return 0 if init power successfully, otherwise return error code
*****************************************************************************/
static int hyn_power_source_init(struct hyn_ts_data *ts_data)
{
int ret = 0;HYN_FUNC_ENTER();
ts_data->vdd = regulator_get(ts_data->dev, “vdd”);
if (IS_ERR_OR_NULL(ts_data->vdd)) {
ret = PTR_ERR(ts_data->vdd);
HYN_ERROR(“get vdd regulator failed,ret=%d”, ret);
return ret;
}if (regulator_count_voltages(ts_data->vdd) > 0) {
ret = regulator_set_voltage(ts_data->vdd, HYN_VTG_MIN_UV,
HYN_VTG_MAX_UV);
if (ret) {
HYN_ERROR(“vdd regulator set_vtg failed ret=%d”, ret);
regulator_put(ts_data->vdd);
return ret;
}
}ts_data->vcc_i2c = regulator_get(ts_data->dev, “vcc_i2c”);
if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) {
if (regulator_count_voltages(ts_data->vcc_i2c) > 0) {
ret = regulator_set_voltage(ts_data->vcc_i2c,
HYN_I2C_VTG_MIN_UV,
HYN_I2C_VTG_MAX_UV);
if (ret) {
HYN_ERROR(“vcc_i2c regulator set_vtg failed,ret=%d”, ret);
regulator_put(ts_data->vcc_i2c);
}
}
}
#if HYN_PINCTRL_EN
hyn_pinctrl_init(ts_data);
hyn_pinctrl_select_normal(ts_data);
#endif
ts_data->power_disabled = true;
ret = hyn_power_source_ctrl(ts_data, ENABLE);
if (ret) {
HYN_ERROR("fail to enable power(regulator)");
}
HYN_FUNC_EXIT();
return ret;
}
static int hyn_power_source_exit(struct hyn_ts_data *ts_data)
{
#if HYN_PINCTRL_EN
hyn_pinctrl_select_release(ts_data);
#endif
hyn_power_source_ctrl(ts_data, DISABLE);
if (!IS_ERR_OR_NULL(ts_data->vdd)) {
if (regulator_count_voltages(ts_data->vdd) > 0)
regulator_set_voltage(ts_data->vdd, 0, HYN_VTG_MAX_UV);
regulator_put(ts_data->vdd);
}
if (!IS_ERR_OR_NULL(ts_data->vcc_i2c)) {
if (regulator_count_voltages(ts_data->vcc_i2c) > 0)
regulator_set_voltage(ts_data->vcc_i2c, 0, HYN_I2C_VTG_MAX_UV);
regulator_put(ts_data->vcc_i2c);
}
return 0;
}
static int hyn_power_source_suspend(struct hyn_ts_data *ts_data)
{
int ret = 0;
#if HYN_PINCTRL_EN
hyn_pinctrl_select_suspend(ts_data);
#endif
ret = hyn_power_source_ctrl(ts_data, DISABLE);
if (ret < 0) {
HYN_ERROR("power off fail, ret=%d", ret);
}
return ret;
}
static int hyn_power_source_resume(struct hyn_ts_data *ts_data)
{
int ret = 0;
#if HYN_PINCTRL_EN
hyn_pinctrl_select_normal(ts_data);
#endif
ret = hyn_power_source_ctrl(ts_data, ENABLE);
if (ret < 0) {
HYN_ERROR("power on fail, ret=%d", ret);
}
return ret;
}
#endif /* HYN_POWER_SOURCE_CUST_EN */
static int hyn_gpio_configure(struct hyn_ts_data *data)
{
int ret = 0;
HYN_FUNC_ENTER();
/* request irq gpio */
if (gpio_is_valid(data->pdata->irq_gpio)) {
//ret = ak_setpin_as_gpio(data->pdata->irq_gpio);
ret = gpio_request(data->pdata->irq_gpio, "hynitron_irq_gpio");
if (ret) {
HYN_ERROR("[GPIO]irq gpio request failed");
goto err_irq_gpio_req;
}
//ret = ak_gpio_dircfg(data->pdata->irq_gpio, AK_GPIO_DIR_INPUT);
ret = gpio_direction_input(data->pdata->irq_gpio);
if (ret) {
HYN_ERROR("[GPIO]set_direction for irq gpio failed");
goto err_irq_gpio_dir;
}
}
/* request reset gpio */
if (gpio_is_valid(data->pdata->reset_gpio)) {
//ret = ak_setpin_as_gpio(data->pdata->reset_gpio);
ret = gpio_request(data->pdata->reset_gpio, "hynitron-reset");
if (ret) {
HYN_ERROR("[GPIO]reset gpio request failed");
goto err_irq_gpio_dir;
}
//ret = ak_gpio_dircfg(data->pdata->reset_gpio, AK_GPIO_DIR_OUTPUT);
ret = gpio_direction_output(data->pdata->reset_gpio, 0);
if (ret) {
HYN_ERROR("[GPIO]set_direction for reset gpio failed");
goto err_reset_gpio_dir;
}
}
HYN_FUNC_EXIT();
return 0;
err_reset_gpio_dir:
// if (gpio_is_valid(data->pdata->reset_gpio))
// gpio_free(data->pdata->reset_gpio);
err_irq_gpio_dir:
// if (gpio_is_valid(data->pdata->irq_gpio))
// gpio_free(data->pdata->irq_gpio);
err_irq_gpio_req:
HYN_FUNC_EXIT();
return ret;
}
#if 0
static int hyn_get_dt_coords(char *name,
struct hyn_ts_platform_data *pdata)
{
//int ret = 0;
//u32 coords[HYN_COORDS_ARR_SIZE] = { 0 };
// struct property *prop;
// int coords_size;
{
HYN_ERROR(“Unable to read %s, please check dts”, name);
pdata->x_min = HYN_X_MIN_DISPLAY_DEFAULT;
pdata->y_min = HYN_Y_MIN_DISPLAY_DEFAULT;
pdata->x_max = HYN_X_MAX_DISPLAY_DEFAULT;
pdata->y_max = HYN_Y_MAX_DISPLAY_DEFAULT;
pdata->max_touch_number = 2;
return -ENODATA;
}
return 0;
}
#endif
static int hyn_parse_dt(struct hyn_ts_data *ts_data,struct hyn_ts_platform_data *pdata)
{
//int ret = 0;
//int error = -1;
int rc, coords_size = 0;
uint32_t coords[4] = {0};
struct property *prop;
struct device_node *dt = ts_data->client->dev.of_node;
HYN_FUNC_ENTER();
#if 0
ret = hyn_get_dt_coords("hynitron,display-coords", pdata);
if (ret < 0)
HYN_ERROR("Unable to get display-coords");
#else
#if 0
prop = of_find_property(dt, "hynitron,panel-coords", NULL);
if (prop)
{
coords_size = prop->length / sizeof(u32);
if (coords_size != 4)
D(" %s:Invalid panel coords size %d", __func__, coords_size);
}
if (of_property_read_u32_array(dt, "hynitron,panel-coords", coords, coords_size) == 0)
{
pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1];
pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3];
I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min,
pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max);
}
#endif
prop = of_find_property(dt, "hynitron,display-coords", NULL);
if (prop)
{
coords_size = prop->length / sizeof(u32);
if (coords_size != 4)
printk(" %s:Invalid display coords size %d", __func__, coords_size);
}
rc = of_property_read_u32_array(dt, "hynitron,display-coords", coords, coords_size);
if (rc && (rc != -EINVAL))
{
printk(" %s:Fail to read display-coords %d\n", __func__, rc);
}
pdata->x_min = coords[0];
pdata->x_max = coords[2];
pdata->y_min = coords[1];
pdata->y_max = coords[3];
pdata->max_touch_number = 2;
printk(" DT-%s:display-coords = (%d, %d)", __func__, pdata->x_max,pdata->y_max);
#endif
#if 0
/* reset, irq gpio info */
pdata->reset_gpio = HYN_RST_PORT;
if (pdata->reset_gpio < 0)
HYN_ERROR("Unable to get reset_gpio");
pdata->irq_gpio = HYN_INT_PORT;
if (pdata->irq_gpio < 0)
HYN_ERROR("Unable to get irq_gpio");
#else
pdata->irq_gpio = of_get_named_gpio(dt, "hynitron,irq-gpio", 0);
if (!gpio_is_valid(pdata->irq_gpio))
{
printk(" DT:gpio_irq value is not valid\n");
}
pdata->reset_gpio = of_get_named_gpio(dt, "hynitron,reset-gpio", 0);
if (!gpio_is_valid(pdata->reset_gpio))
{
printk(" DT:gpio_rst value is not valid\n");
}
#endif
HYN_FUNC_EXIT();
return 0;
}
#if defined(CONFIG_FB)
static void hyn_resume_work(struct work_struct *work)
{
struct hyn_ts_data *ts_data = container_of(work, struct hyn_ts_data,
resume_work);
hyn_ts_resume(ts_data->dev);
}
static int fb_notifier_callback(struct notifier_block *self,
unsigned long event, void *data)
{
struct fb_event *evdata = data;
int *blank = NULL;
//struct hyn_ts_data *ts_data = container_of(self, struct hyn_ts_data,fb_notif);
if (!( event == FB_EVENT_BLANK)) {
HYN_INFO("event(%lu) do not need process\n", event);
return 0;
}
blank = evdata->data;
HYN_INFO("FB event:%lu,blank:%d", event, *blank);
switch (*blank) {
case FB_BLANK_UNBLANK:
if (FB_EVENT_BLANK == event) {
queue_work(hyn_data->ts_workqueue, &hyn_data->resume_work);
}
break;
case FB_BLANK_POWERDOWN:
if (FB_EVENT_BLANK == event) {
HYN_INFO("suspend: event = %lu, not care\n", event);
}
break;
default:
HYN_INFO("FB BLANK(%d) do not need process\n", *blank);
break;
}
return 0;
}
#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void hyn_ts_early_suspend(struct early_suspend *handler)
{
struct hyn_ts_data *ts_data = container_of(handler, struct hyn_ts_data,
early_suspend);
hyn_ts_suspend(ts_data->dev);
}
static void hyn_ts_late_resume(struct early_suspend *handler)
{
struct hyn_ts_data *ts_data = container_of(handler, struct hyn_ts_data,
early_suspend);
hyn_ts_resume(ts_data->dev);
}
#endif
static int hyn_ts_probe_entry(struct hyn_ts_data *ts_data)
{
#if HYN_FW_UPDATA
int dev_addr;
#endif
//unsigned char value111;
int ret = 0;
int pdata_size = sizeof(struct hyn_ts_platform_data);
struct i2c_client *client = NULL;
client = hyn_data->client;
HYN_FUNC_ENTER();
ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL);
printk("==================hyn_ts_probe_entry=======2======\r\n");
ret = hyn_parse_dt(ts_data,ts_data->pdata);
if (ret)
HYN_ERROR("device-tree parse fail");
printk("hyn_ts_probe_entry 1\n");
ts_data->ts_workqueue = create_singlethread_workqueue("hyn_wq");
if (!ts_data->ts_workqueue) {
HYN_ERROR("create fts workqueue fail");
}
printk("hyn_ts_probe_entry 2\n");
spin_lock_init(&ts_data->irq_lock);
mutex_init(&ts_data->report_mutex);
mutex_init(&ts_data->bus_lock);
printk("hyn_ts_probe_entry 3\n");
/* Init communication interface */
hyn_bus_init(ts_data);
printk("hyn_ts_probe_entry 4\n");
ret = hyn_input_init(ts_data);
if (ret) {
HYN_ERROR("input initialize fail");
goto err_input_init;
}
printk("hyn_ts_probe_entry 5\n");
ret = hyn_report_buffer_init(ts_data);
if (ret) {
HYN_ERROR("report buffer init fail");
goto err_report_buffer;
}
printk("hyn_ts_probe_entry 6\n");
ret = hyn_gpio_configure(ts_data);
if (ret) {
HYN_ERROR("configure the gpios fail");
goto err_gpio_config;
}
printk("hyn_ts_probe_entry 7\n");
#if HYN_POWER_SOURCE_CUST_EN
ret = hyn_power_source_init(ts_data);
if (ret) {
HYN_ERROR("fail to get power(regulator)");
goto err_power_init;
}
#endif
printk("hyn_ts_probe_entry 8\n");
hyn_reset_proc(200);
printk("hyn_ts_probe_entry 9 %d\n",ts_data->ic_info.ids.chip_idl);
ret = hyn_get_ic_information(ts_data);
if (ret) {
HYN_ERROR("not focal IC, unregister driver");
goto err_irq_req;
}
//默认不进行升级
#if HYN_FW_UPDATA
if(hyn_ctpm_get_upg_ver() > ts_data->ic_info.ids.chip_idl)
{
HYN_DEBUG("[TSP] start upgrade new verison 0x%2x\n", fts_ctpm_get_upg_ver());
dev_addr = client->addr;
client->addr = 0x6A;
hyn_ctpm_fw_upgrade_with_i_file();
client->addr = dev_addr;
hyn_reset_proc(200);
}
#endif
printk("hyn_ts_probe_entry 10\n");
ret = hyn_irq_registration(ts_data);
if (ret) {
HYN_ERROR("request irq failed");
goto err_irq_req;
}
#if defined(CONFIG_FB)
if (ts_data->ts_workqueue) {
INIT_WORK(&ts_data->resume_work, hyn_resume_work);
}
ts_data->fb_notif.notifier_call = fb_notifier_callback;
ret = fb_register_client(&ts_data->fb_notif);
if (ret) {
HYN_ERROR("[FB]Unable to register fb_notifier: %d", ret);
}
#elif defined(CONFIG_HAS_EARLYSUSPEND)
ts_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL;
ts_data->early_suspend.suspend = hyn_ts_early_suspend;
ts_data->early_suspend.resume = hyn_ts_late_resume;
register_early_suspend(&ts_data->early_suspend);
#endif
printk(“hyn_ts_probe_entry 11\n”);
HYN_FUNC_EXIT();
return 0;
err_irq_req:
#if HYN_POWER_SOURCE_CUST_EN
err_power_init:
hyn_power_source_exit(ts_data);
#endif
if (gpio_is_valid(ts_data->pdata->reset_gpio))
gpio_free(ts_data->pdata->reset_gpio);
if (gpio_is_valid(ts_data->pdata->irq_gpio))
gpio_free(ts_data->pdata->irq_gpio);
err_gpio_config:
kfree_safe(ts_data->point_buf);
kfree_safe(ts_data->events);
err_report_buffer:
input_unregister_device(ts_data->input_dev);
err_input_init:
if (ts_data->ts_workqueue)
destroy_workqueue(ts_data->ts_workqueue);
kfree_safe(ts_data->bus_buf);
kfree_safe(ts_data->pdata);
HYN_FUNC_EXIT();
return ret;
}
static int hyn_ts_remove_entry(struct hyn_ts_data *ts_data)
{
HYN_FUNC_ENTER();
hyn_bus_exit(ts_data);
free_irq(ts_data->irq, ts_data);
input_unregister_device(ts_data->input_dev);
if (ts_data->ts_workqueue)
destroy_workqueue(ts_data->ts_workqueue);
#if defined(CONFIG_FB)
if (fb_unregister_client(&ts_data->fb_notif))
HYN_ERROR(“Error occurred while unregistering fb_notifier.”);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&ts_data->early_suspend);
#endif
if (gpio_is_valid(ts_data->pdata->reset_gpio))
gpio_free(ts_data->pdata->reset_gpio);
if (gpio_is_valid(ts_data->pdata->irq_gpio))
gpio_free(ts_data->pdata->irq_gpio);
#if HYN_POWER_SOURCE_CUST_EN
hyn_power_source_exit(ts_data);
#endif
kfree_safe(ts_data->point_buf);
kfree_safe(ts_data->events);
kfree_safe(ts_data->pdata);
kfree_safe(ts_data);
HYN_FUNC_EXIT();
return 0;
}
#if 0
static int hyn_ts_suspend(struct device *dev)
{
int ret = 0;
struct hyn_ts_data *ts_data = hyn_data;
HYN_FUNC_ENTER();
if (ts_data->suspended) {
HYN_INFO("Already in suspend state");
return 0;
}
if (ts_data->fw_loading) {
HYN_INFO("fw upgrade in process, can't suspend");
return 0;
}
hyn_irq_disable();
/* TP enter sleep mode */
ret = hyn_write_reg(HYN_REG_POWER_MODE, HYN_REG_POWER_MODE_SLEEP_VALUE);
if (ret < 0)
HYN_ERROR("set TP to sleep mode fail, ret=%d", ret);
if (!ts_data->ic_info.is_incell) {
#if HYN_POWER_SOURCE_CUST_EN
ret = hyn_power_source_suspend(ts_data);
if (ret < 0) {
HYN_ERROR(“power enter suspend fail”);
}
#endif
}
ts_data->suspended = true;
HYN_FUNC_EXIT();
return 0;
}
#endif
static int hyn_ts_resume(struct device *dev)
{
struct hyn_ts_data *ts_data = hyn_data;
HYN_FUNC_ENTER();
if (!ts_data->suspended) {
HYN_DEBUG("Already in awake state");
return 0;
}
hyn_release_all_finger();
//if (!ts_data->ic_info.is_incell)
if(1){
#if HYN_POWER_SOURCE_CUST_EN
hyn_power_source_resume(ts_data);
#endif
hyn_reset_proc(200);
}
hyn_tp_state_recovery(ts_data);
hyn_irq_enable();
ts_data->suspended = false;
HYN_FUNC_EXIT();
return 0;
}
/*****************************************************************************
- TP Driver
*****************************************************************************/
static int hyn_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret = 0;
struct hyn_ts_data *ts_data = NULL;
printk("====2020.10.14========hyn_ts_probe======1======\r\n");
//init_cam_iic();
//Check I2C functionality
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
printk("%s: ====2020.10.14==== i2c check functionality error\n", __func__);
return -1;
}
printk("====2020.10.14========hyn_ts_probe=======2=====\r\n");
/* malloc memory for global struct variable */
ts_data = (struct hyn_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL);
if (!ts_data) {
HYN_ERROR("allocate memory for hyn_data fail");
return -ENOMEM;
}
hyn_data = ts_data;
i2c_set_clientdata(client, ts_data);
ts_data->client = client;
ts_data->dev = &client->dev;
ts_data->log_level = 4;
ts_data->fw_is_running = 0;
ret = hyn_ts_probe_entry(ts_data);
if (ret) {
HYN_ERROR("Touch Screen(I2C BUS) driver probe fail");
kfree_safe(ts_data);
return ret;
}
HYN_INFO("Touch Screen(I2C BUS) driver prboe successfully");
return 0;
}
static int hyn_ts_remove(struct i2c_client *client)
{
return hyn_ts_remove_entry(hyn_data);
}
static const struct i2c_device_id hyn_ts_id[] = {
{HYN_DRIVER_NAME, 0},
{},
};
static const struct of_device_id hyn_dt_match[] = {
{.compatible = “hynitron,cst8xx”, },
{},
};
MODULE_DEVICE_TABLE(of, hyn_dt_match);
#if 1
static struct i2c_driver hyn_ts_driver = {
.probe = hyn_ts_probe,
.remove = hyn_ts_remove,
.driver = {
.name = HYN_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(hyn_dt_match),
},
.id_table = hyn_ts_id,
};
#endif
static int __init hyn_ts_init(void)
{
int ret = 0;
printk("==hyn_ts_init\r\n");
HYN_FUNC_ENTER();
//ret = hyn_ts_probe(0, 0);
ret = i2c_add_driver(&hyn_ts_driver);
if ( ret != 0 ) {
HYN_ERROR("Focaltech touch screen driver init failed!");
}
HYN_FUNC_EXIT();
return ret;
}
static void __exit hyn_ts_exit(void)
{
hyn_ts_remove(0);
//i2c_del_driver(&hyn_ts_driver);
}
module_init(hyn_ts_init);
module_exit(hyn_ts_exit);
MODULE_AUTHOR(“hyn Driver Team”);
MODULE_DESCRIPTION(“hyn Touchscreen Driver”);
MODULE_LICENSE(“GPL v2”);
更多推荐
所有评论(0)