GTP968(ic)触摸屏调试实际代码的分析

触摸屏驱动

一.probe函数中处理

 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))

//若有中断事件,则调用中断处理函数---》调用队列工作--》调用工作函数goodix_ts_work_func

//此处是初始化队列工作,即将ts->work加入到goodix->wq队列中。

 INIT_WORK(&ts->work, goodix_ts_work_func);

 i2c_set_clientdata(client, ts);

//1.io 端口初始化

 ret = gtp_request_io_port(ts);

 ret = gtp_i2c_test(client);

 ret = gtp_read_version(client, &version_info);

//2.触摸屏初始化调用(每个触摸屏都会由厂商提供初始化代码)

 ret = gtp_init_panel(ts);

properties_kobj = kobject_create_and_add("board_properties", NULL);
 if (properties_kobj)
//3.gt9xx_properties_attr_group 节点处理虚拟按键(遇到过节点使用前未初始化,造成节点使用错误)

 ret = sysfs_create_group(properties_kobj,&gt9xx_properties_attr_group);

//4.输入设备初始化

gtp_request_input_dev(ts);

//5.中断初始化

ret = gtp_request_irq(ts);

二.深入分析细节

//1.io 端口初始化

void gtp_reset_guitar(struct i2c_client *client, s32 ms)
{
    GTP_INFO("Guitar reset");
    GTP_GPIO_OUTPUT(GTP_RST_PORT, 0);   // begin select I2C slave addr
    msleep(ms);                         // T2: > 10ms
    // HIGH: 0x28/0x29, LOW: 0xBA/0xBB
    GTP_GPIO_OUTPUT(GTP_INT_PORT, client->addr == 0x14);

    msleep(2);                          // T3: > 100us
    GTP_GPIO_OUTPUT(GTP_RST_PORT, 1);
   
    msleep(6);                          // T4: > 5ms

    GTP_GPIO_AS_INPUT(GTP_RST_PORT);    // end select I2C slave addr

    gtp_int_sync(50); 
}

 

static s8 gtp_request_io_port(struct goodix_ts_data *ts)
{
    s32 ret = 0;

//中断端口
    ret = GTP_GPIO_REQUEST(GTP_INT_PORT, "GTP_INT_IRQ");

//reset端口

    ret = GTP_GPIO_REQUEST(GTP_RST_PORT, "GTP_RST_PORT");

//reset端口设置为输入

    GTP_GPIO_AS_INPUT(GTP_RST_PORT);

//选择i2c地址

    gtp_reset_guitar(ts->client, 20);
   
    if(ret < 0)
    {
        GTP_GPIO_FREE(GTP_RST_PORT);
        GTP_GPIO_FREE(GTP_INT_PORT);
    }

    return ret;
}

2.输入设备初始化

/*******************************************************
Function:
    Request input device Function.
Input:
    ts:private data.
Output:
    Executive outcomes.
        0: succeed, otherwise: failed.
*******************************************************/
static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
{
    s8 ret = -1;
    s8 phys[32];
#if GTP_HAVE_TOUCH_KEY
    u8 index = 0;
#endif
    ts->input_dev = input_allocate_device();
    if (ts->input_dev == NULL)
    {
        GTP_ERROR("Failed to allocate input device.");
        return -ENOMEM;
    }

//设置输入设备属于哪类事件

    ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
#if GTP_ICS_SLOT_REPORT
    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
    input_mt_init_slots(ts->input_dev, 16);     // in case of "out of memory"
#else
    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
    ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
#endif

#if GTP_HAVE_TOUCH_KEY
    for (index = 0; index < GTP_MAX_KEY_NUM; index++)
    {
        input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]); 
    }
#endif

#if GTP_SLIDE_WAKEUP
    input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
#endif

#if GTP_WITH_PEN
    // pen support
    __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
    __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
    //__set_bit(INPUT_PROP_POINTER, ts->input_dev->propbit);
#endif

#if GTP_CHANGE_X2Y
    GTP_SWAP(ts->abs_x_max, ts->abs_y_max);
#endif

//设置输入设备:绝对位移事件ABS的具体值

    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);

    sprintf(phys, "input/ts");
    ts->input_dev->name = goodix_ts_name;
    ts->input_dev->phys = phys;
    ts->input_dev->id.bustype = BUS_I2C;
    ts->input_dev->id.vendor = 0xDEAD;
    ts->input_dev->id.product = 0xBEEF;
    ts->input_dev->id.version = 10427;
   
    ret = input_register_device(ts->input_dev);
    if (ret)
    {
        GTP_ERROR("Register %s input device failed", ts->input_dev->name);
        return -ENODEV;
    }
   
#ifdef CONFIG_HAS_EARLYSUSPEND
    ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
    ts->early_suspend.suspend = goodix_ts_early_suspend;
    ts->early_suspend.resume = goodix_ts_late_resume;
    register_early_suspend(&ts->early_suspend);
#endif

    return 0;
}

3.中断初始化

static s8 gtp_request_irq(struct goodix_ts_data *ts)
{
    s32 ret = -1;
    const u8 irq_table[] = GTP_IRQ_TAB;

    GTP_DEBUG_FUNC();
    GTP_DEBUG("INT trigger type:%x", ts->int_trigger_type);

//请求中断,并设定中断触发方式

    ret  = request_irq(ts->client->irq,
                       goodix_ts_irq_handler,
                       irq_table[ts->int_trigger_type],
                       ts->client->name,
                       ts);
    if (ret)
    {
        GTP_ERROR("Request IRQ failed!ERRNO:%d.", ret);
        GTP_GPIO_AS_INPUT(GTP_INT_PORT);
        GTP_GPIO_FREE(GTP_INT_PORT);

        hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        ts->timer.function = goodix_ts_timer_handler;
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
        return -1;
    }
    else
    {
        gtp_irq_disable(ts);
        ts->use_irq = 1;
        return 0;
    }
}

三.当有中断发生时,调用中断处理函数

/*******************************************************
Function:
    Timer interrupt service routine for polling mode.
Input:
    timer: timer struct pointer
Output:
    Timer work mode.
        HRTIMER_NORESTART: no restart mode
*********************************************************/
static enum hrtimer_restart goodix_ts_timer_handler(struct hrtimer *timer)
{
    struct goodix_ts_data *ts = container_of(timer, struct goodix_ts_data, timer);

    GTP_DEBUG_FUNC();

//调用goodix_wq队列中的ts->work工作

    queue_work(goodix_wq, &ts->work);
    hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME+6)*1000000), HRTIMER_MODE_REL);
    return HRTIMER_NORESTART;
}

四.调用ts->work的工作函数goodix_ts_work_func

此函数主要是读取手指数及各个手指的坐标,并上报event事件。

static void goodix_ts_work_func(struct work_struct *work)
{
    u8  end_cmd[3] = {GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF, 0};
    u8  point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1]={GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF};
    u8  touch_num = 0;
    u8  finger = 0;
    static u16 pre_touch = 0;
    static u8 pre_key = 0;
    u8  key_value = 0;
    u8* coor_data = NULL;
    s32 input_x = 0;
    s32 input_y = 0;
    s32 input_w = 0;
    s32 id = 0;
    s32 i  = 0;
    s32 ret = -1;
    struct goodix_ts_data *ts = NULL;

    GTP_DEBUG_FUNC();
    ts = container_of(work, struct goodix_ts_data, work);
    if (ts->enter_update)
    {
        return;
    }

//从触摸屏I2C 读取数据

    ret = gtp_i2c_read(ts->client, point_data, 12);
    if (ret < 0)
    {
        GTP_ERROR("I2C transfer error. errno:%d\n ", ret);
        goto exit_work_func;
    }
    finger = point_data[GTP_ADDR_LENGTH];   

    if((finger & 0x80) == 0)
    {
        goto exit_work_func;
    }

//对手指数的判断

    touch_num = finger & 0x0f;
    if (touch_num > GTP_MAX_TOUCH)
    {
        goto exit_work_func;
    }

    if (touch_num > 1)
    {
        u8 buf[8 * GTP_MAX_TOUCH] = {(GTP_READ_COOR_ADDR + 10) >> 8, (GTP_READ_COOR_ADDR + 10) & 0xff};

        ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1));
        memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
    }

//上报虚拟按键的值(虚拟按键上报有两种方式:1.按键上报,2.坐标上报,所以才有判断)

#if GTP_HAVE_TOUCH_KEY
    key_value = point_data[3 + 8 * touch_num];
    if(key_value || pre_key)
    {
    #ifndef VKEY_SYS
        for (i = 0; i < GTP_MAX_KEY_NUM; i++)
        {
            input_report_key(ts->input_dev, touch_key_array[i], key_value & (0x01<<i));  
        }
 #else
  if (key_value == 1) {
   input_x = 80;
   input_y = 898;
  }else if (key_value == 2) {
   input_x = 240;
   input_y = 898;
  }else if (key_value == 4) {
   input_x = 400;
   input_y = 898;
  }
  blocking_notifier_call_chain(&touch_key_notifier, 0, NULL);
  input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
  input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
  if(key_value) {
   input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 8);
   input_report_key(ts->input_dev, BTN_TOUCH, 1);
   //printk("lht--%s--touch key_value=%d----touch_num=%d----down\n", __func__, key_value, touch_num);
  }else {
   input_report_abs(ts, ABS_MT_TOUCH_MAJOR, 0);
   input_report_key(ts->input_dev, BTN_TOUCH, 0);
   //printk("lht--%s--touch key_value=%d----touch_num=%d----up\n", __func__, key_value, touch_num);
  }
  input_mt_sync(ts->input_dev);
 #endif
        touch_num = 0;
        pre_touch = 0;
    }
    pre_key = key_value;

    GTP_DEBUG("pre_touch:%02x, finger:%02x.", pre_touch, finger);
    input_report_key(ts->input_dev, BTN_TOUCH, (touch_num || key_value));
 //printk("lht--%s---touch_num=%d---key_value=%d--\n", __func__, touch_num, key_value);
 down_up_flag = touch_num || key_value;
//各个手指坐标的读取   

 if (touch_num)
    {
        for (i = 0; i < touch_num; i++)
        {
            coor_data = &point_data[i * 8 + 3];

            id = coor_data[0] & 0x0F;
            input_x  = coor_data[1] | (coor_data[2] << 8);
            input_y  = coor_data[3] | (coor_data[4] << 8);
            input_w  = coor_data[5] | (coor_data[6] << 8);

//上报坐标值及w值
            gtp_touch_down(ts, id, input_x, input_y, input_w);
        }
    }
    else if (pre_touch)
    {
        GTP_DEBUG("Touch Release!");

//释放手指
        gtp_touch_up(ts, 0);
    }

    pre_touch = touch_num;
#endif

    input_sync(ts->input_dev);

exit_work_func:
    if(!ts->gtp_rawdiff_mode)
    {
        ret = gtp_i2c_write(ts->client, end_cmd, 3);
        if (ret < 0)
        {
            GTP_INFO("I2C write end_cmd error!");
        }
    }
    if (ts->use_irq)
    {
        gtp_irq_enable(ts);
    }
}
五.上报及释放

static void gtp_touch_down(struct goodix_ts_data* ts,s32 id,s32 x,s32 y,s32 w)
{
    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
    input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
    input_mt_sync(ts->input_dev);

    GTP_DEBUG("ID:%d, X:%d, Y:%d, W:%d", id, x, y, w);
}

/*******************************************************
Function:
    Report touch release event
Input:
    ts: goodix i2c_client private data
Output:
    None.
*********************************************************/
static void gtp_touch_up(struct goodix_ts_data* ts, s32 id)
{
    //input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
    //input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
    input_mt_sync(ts->input_dev);
}

 

 

 

你可能感兴趣的:(GTP968(ic)触摸屏调试实际代码的分析)