我是靠谱客的博主 饱满香氛,最近开发中收集的这篇文章主要介绍linux下调试cst8xx触摸屏驱动,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

硬件描述:
具体没找到硬件的描述,一般电容触摸屏关键就是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 rn",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 rn",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, &reg_value);
     #else      
     ret = hyn_read_reg_aa(client,HYN_REG_CHIP_ID, &reg_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 rn",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("rnCTP 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 rn",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 rn",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 rn",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 rn",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 rn",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 rn",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 rn",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 rn",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 rn",buf[8]);

printk("touch num status =================== %d rn",(value_2&0xc0)>>6);
printk("x ===================== %d rn",(((value_2&0x0f)<<8) | value_3));
printk("y ===================== %d rn",(((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 rn",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 rn",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 rn”,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, %dn", __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 %dn", __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 validn");
}

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 validn");
}

#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 processn", 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 caren", event);
    }
    break;
default:
    HYN_INFO("FB BLANK(%d) do not need processn", *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======rn");

ret = hyn_parse_dt(ts_data,ts_data->pdata);
if (ret)
    HYN_ERROR("device-tree parse fail");

printk("hyn_ts_probe_entry 1n");

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 2n");
spin_lock_init(&ts_data->irq_lock);
mutex_init(&ts_data->report_mutex);
mutex_init(&ts_data->bus_lock);
printk("hyn_ts_probe_entry 3n");
/* Init communication interface */
hyn_bus_init(ts_data);
printk("hyn_ts_probe_entry 4n");
ret = hyn_input_init(ts_data);
if (ret) {
    HYN_ERROR("input initialize fail");
    goto err_input_init;
}
printk("hyn_ts_probe_entry 5n");
ret = hyn_report_buffer_init(ts_data);
if (ret) {
    HYN_ERROR("report buffer init fail");
    goto err_report_buffer;
}
printk("hyn_ts_probe_entry 6n");
ret = hyn_gpio_configure(ts_data);
if (ret) {
    HYN_ERROR("configure the gpios fail");
    goto err_gpio_config;
}
printk("hyn_ts_probe_entry 7n");
#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 8n");
hyn_reset_proc(200);

printk("hyn_ts_probe_entry 9 %dn",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%2xn", 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 10n");
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 11n”);
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======rn");

//init_cam_iic();
//Check I2C functionality
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
{
     printk("%s: ====2020.10.14==== i2c check functionality errorn", __func__);
	 return -1;
}

printk("====2020.10.14========hyn_ts_probe=======2=====rn");

/* 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_initrn");
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”);

最后

以上就是饱满香氛为你收集整理的linux下调试cst8xx触摸屏驱动的全部内容,希望文章能够帮你解决linux下调试cst8xx触摸屏驱动所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部