我是靠谱客的博主 饱满香氛,这篇文章主要介绍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>;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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];

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 };

复制代码
1
2
3
4
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);
}

复制代码
1
2
return 0;

}

/*****************************************************************************

  • Name: hyn_wait_tp_to_valid

  • Brief: Read chip id until TP FW become valid(Timeout: TIMEOUT_READ_REG),

  • 复制代码
    1
    2
    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 {

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
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-

  • 复制代码
    1
    2
    ill know which IC is it.
  • 复制代码
    1
    2
    If cant get the ic information, maybe not hyntrion's touch IC, need
  • 复制代码
    1
    2
    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 {

    复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #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);
}

复制代码
1
2
3
4
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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};

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;

复制代码
1
2
return checksum.sum;

}

static int cst78xx_update(u16 startAddr,u16 len,u8* src){
u16 sum_len;
u8 cmd[10];
int ret;

复制代码
1
2
3
4
5
6
7
ret = 0; if (cst78xx_enter_bootmode() == -1){ return -1; } sum_len = 0;

#define PER_LEN 512
do{
if (sum_len >= len){
return -1;
}

复制代码
1
2
3
4
5
// 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++){

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
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);

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;

复制代码
1
2
3
4
5
6
7
8
9
10
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

复制代码
1
2
3
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);

复制代码
1
2
3
4
5
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.

  • 复制代码
    1
    2
    if point's coordinate is in (x_dim-50,y_dim-50) ~ (x_dim+50,y_dim+50),
  • 复制代码
    1
    2
    need report it to key event.
  • 复制代码
    1
    2
    x_dim: parse from dts, means key x_coordinate, dimension:+-50
  • 复制代码
    1
    2
    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;
}

复制代码
1
2
3
4
5
6
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);

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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;

复制代码
1
2
3
4
5
6
7
8
9
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);

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;

复制代码
1
2
3
4
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
//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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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;

复制代码
1
2
3
4
5
6
7
8
9
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;

复制代码
1
2
3
4
5
6
7
8
9
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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

  • 复制代码
    1
    2
    vdd---->vdd-supply in dts, kernel will auto add "-supply" to parse
  • 复制代码
    1
    2
    Must be call after hyn_gpio_configure() execute,because this function
  • 复制代码
    1
    2
    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

复制代码
1
2
3
4
5
6
7
8
9
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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

复制代码
1
2
3
4
5
6
7
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

复制代码
1
2
3
4
5
6
7
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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;
}

复制代码
1
2
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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);

复制代码
1
2
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);

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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);

复制代码
1
2
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);

复制代码
1
2
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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);

复制代码
1
2
3
4
5
6
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();

复制代码
1
2
3
4
5
6
7
8
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

复制代码
1
2
3
4
5
6
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

复制代码
1
2
3
4
5
6
7
8
9
10
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
}

复制代码
1
2
3
4
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;

复制代码
1
2
3
4
5
6
7
8
9
10
11
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);
}

复制代码
1
2
3
4
5
6
7
8
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)
{

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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();

复制代码
1
2
3
4
5
6
7
8
//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触摸屏驱动内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部