MT6737 平台TP driver分析(二)

tp厂商驱动文件分析
\kernel-3.18\drivers\input\touchscreen\mediatek\NT11206
这里写图片描述
\kernel-3.18\drivers\input\touchscreen\mediatek\NT11206\NVTtouch_206.c

static int __init nvt_driver_init(void)
{
    int32_t ret = 0;

    NVT_INFO("NVT touch panel driver init!\n");
    tpd_get_dts_info();//获得dts中的配置信息
    ret = tpd_driver_add(&nvt_device_driver);//将tp厂商的驱动文件添加到tp驱动链表中tpd_driver_list
    if ( ret < 0){
        NVT_ERROR("add generic driver failed\n");
        goto err_driver;
    }
    NVT_INFO("nvt_driver_init finished\n");

err_driver:
    return ret;
}

nvt_device_driver

static struct tpd_driver_t nvt_device_driver =
{
    .tpd_device_name = NVT_I2C_NAME,
    .tpd_local_init = nvt_local_init,//之前分析mtk_tpd.c文件中遇到的tpd_local_init函数
    .suspend = nvt_ts_suspend,//tp休眠函数
    .resume = nvt_ts_resume,//tp唤醒函数
};
static int nvt_local_init(void)
{
   NVT_INFO("nvt_local_init");
   NVT_INFO("Device Tree get regulator!");
   tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");
#if I2C_DMA_SUPPORT
    tpd->dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);

    gpDMABuf_va = (uint8_t *)dma_alloc_coherent(&tpd->dev->dev, DMA_MAX_TRANSACTION_LENGTH, &gpDMABuf_pa, GFP_KERNEL);
    if(!gpDMABuf_va){
        NVT_ERROR("Allocate DMA I2C Buffer failed!\n");
        NVT_INFO("ate DMA I2C Buffer failed!\n");
    }
    memset(gpDMABuf_va, 0, DMA_MAX_TRANSACTION_LENGTH);
#endif

    if (i2c_add_driver(&nvt_i2c_driver) != 0)//注册i2c从设备驱动
    {
        NVT_ERROR("unable to add i2c driver.\n");
        return -1;
    }

    if (tpd_load_status == 0)
    {
        NVT_ERROR("add error touch panel driver.\n");
        i2c_del_driver(&nvt_i2c_driver);
        return -1;
    }

    NVT_INFO("%s: finished\n", __func__);

    tpd_type_cap = 1;

    return 0;
}

nvt_local_init函数中主要是注册了i2c从设备驱动nvt_i2c_driver

static struct i2c_driver nvt_i2c_driver =
{
    .probe = nvt_i2c_probe,
    .remove = nvt_i2c_remove,
    .detect = nvt_i2c_detect,
    .driver.name = NVT_I2C_NAME,//driver名字NVT-ts
    .driver = {
           .name = NVT_I2C_NAME,
           .of_match_table = tpd_of_match,
           },
    .id_table = nvt_ts_id,
    .address_list = (const unsigned short *)forces,
};
static int nvt_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int32_t ret = 0;
    int32_t err = 0;


#if ((TOUCH_KEY_NUM > 0) || WAKEUP_GESTURE)
    int32_t retry = 0;
#endif

    NVT_INFO("tpd_i2c_probe start...");
    ts = kmalloc(sizeof(struct nvt_ts_data), GFP_KERNEL);
    if (ts == NULL) {
        dev_err(&client->dev, "%s: failed to allocated memory for nvt ts data\n", __func__);
        return -ENOMEM;
    }
    ts->client = client;
    i2c_set_clientdata(client, ts);

    if (tpd_power_switch(SWITCH_ON) < 0)//tp上电操作
    {
        NVT_ERROR("tpd_power_switch error !!!\n");
    }


    thread = kthread_run(touch_event_handler, 0, TPD_DEVICE);//tp触摸事件处理函数
    if (IS_ERR(thread))
    {
        err = PTR_ERR(thread);
        NVT_INFO(TPD_DEVICE "failed to create kernel thread: %d\n", err);
    }

    //---request INT-pin---
    tpd_gpio_as_int(GTP_INT_PORT);//申请触摸中断
    msleep(50);

    nvt_hw_reset();//TP reset
    //msleep(500);

    //---check i2c func.---
    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
        dev_err(&client->dev, "i2c_check_functionality failed. (no I2C_FUNC_I2C)\n");
        ret = -ENODEV;
        goto err_check_functionality_failed;
    }

    // need 10ms delay after POR(power on reset)
    msleep(10);

    //---check chip id---
    ret = nvt_ts_read_chipid();//读取tp chip id
    if (ret != 0x26) {
        NVT_INFO("nvt_ts_read_chipid is not 0x26. ret=0x%02X\n", ret);
        dev_err(&client->dev, "nvt_ts_read_chipid is not 0x26. ret=0x%02X\n", ret);
        ret = -EINVAL;
        goto err_chipid_failed;
    }


    //---check chip version---
    ret = nvt_ts_chip_version();//读取tp chip version

    mutex_init(&ts->lock);

    //---allocate input device---
    ts->input_dev = input_allocate_device();//分配input device结构体
    if (ts->input_dev == NULL) {
        dev_err(&client->dev, "%s: allocate input device failed\n", __func__);
        ret = -ENOMEM;
        goto err_input_dev_alloc_failed;
    }

#if BOOT_UPDATE_FIRMWARE
    nvt_fwu_wq = create_singlethread_workqueue("nvt_fwu_wq");
    if (!nvt_fwu_wq) {
        dev_err(&client->dev, "%s: nvt_fwu_wq create workqueue failed\n", __func__);
        ret = -ENOMEM;
        goto err_create_nvt_fwu_wq_failed;
    }
    INIT_DELAYED_WORK(&ts->nvt_fwu_work, Boot_Update_Firmware);//固件升级相关操作
    queue_delayed_work(nvt_fwu_wq, &ts->nvt_fwu_work, msecs_to_jiffies(4000));
#endif

    ts->abs_x_max = TOUCH_MAX_WIDTH;//最大像素宽度720
    ts->abs_y_max = TOUCH_MAX_HEIGHT;//最大像素高度1280
    ts->max_touch_num = TOUCH_MAX_FINGER_NUM;

#if TOUCH_KEY_NUM > 0
    ts->max_button_num = TOUCH_KEY_NUM;
#endif

    ts->int_trigger_type = INT_TRIGGER_TYPE;//中断触发类型.上升沿触发


    //---set input device info.---设置 input device结构体属性和参数
    ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
    ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    ts->input_dev->propbit[0] = BIT(INPUT_PROP_DIRECT);

#if MT_PROTOCOL_B
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
    input_mt_init_slots(ts->input_dev, ts->max_touch_num, 0);
#else
    input_mt_init_slots(ts->input_dev, ts->max_touch_num);
#endif
#endif

    input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);    //pressure = 255

#if TOUCH_MAX_FINGER_NUM > 1
    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);    //area = 255

    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);
#if MT_PROTOCOL_B
    // no need to set ABS_MT_TRACKING_ID, input_mt_init_slots() already set it
#else
    input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, ts->max_touch_num, 0, 0);
#endif
#endif

#if TOUCH_KEY_NUM > 0//是否支持触摸按键
    for (retry = 0; retry < TOUCH_KEY_NUM; retry++) {
        input_set_capability(ts->input_dev, EV_KEY, touch_key_array_1[retry]);
    }
#endif

#if WAKEUP_GESTURE //是否支持唤醒手势
    for (retry = 0; retry < (sizeof(gesture_key_array) / sizeof(gesture_key_array[0])); retry++) {
        input_set_capability(ts->input_dev, EV_KEY, gesture_key_array[retry]);
    }
    wake_lock_init(&gestrue_wakelock, WAKE_LOCK_SUSPEND, "poll-wake-lock");
#endif

    sprintf(ts->phys, "input/ts");
    ts->input_dev->name = NVT_TS_NAME;
    ts->input_dev->phys = ts->phys;
    ts->input_dev->id.bustype = BUS_I2C;


    //---register input device---
    ret = input_register_device(ts->input_dev);//注册tp input设备
    if (ret) {
        dev_err(&client->dev, "register input device (%s) failed. ret=%d\n", ts->input_dev->name, ret);
        goto err_input_register_device_failed;
    } 

    ret = tpd_irq_registration();// 注册tp触摸中断
    if(ret != 0){
        NVT_ERROR("tpd register irq failed!\n");
        goto err_int_request_failed;
    }

    mutex_lock(&ts->lock);
    nvt_hw_reset();
    msleep(5);
    nvt_bootloader_reset();
    nvt_check_fw_reset_state(RESET_STATE_INIT);
    mutex_unlock(&ts->lock);

    //---set device node---
#if NVT_TOUCH_PROC
    ret = nvt_flash_proc_init();
    if (ret != 0) {
        dev_err(&client->dev, "nvt flash proc init failed. ret=%d\n", ret);
        goto err_init_NVT_ts;
    }
#endif

#if NVT_TOUCH_EXT_PROC
    ret = nvt_extra_proc_init();
    if (ret != 0) {
        dev_err(&client->dev, "nvt extra proc init failed. ret=%d\n", ret);
        goto err_init_NVT_ts;
    }
#endif

#if NVT_TOUCH_MP
    ret = nvt_mp_proc_init();
    if (ret != 0) {
        dev_err(&client->dev, "nvt mp proc init failed. ret=%d\n", ret);
        goto err_init_NVT_ts;
    }
#endif

    dev_info(&client->dev, "%s: finished\n", __func__);
    NVT_INFO("%s: finished\n",  __func__);
    tpd_load_status = 1;
    return 0;

err_init_NVT_ts:
    free_irq(touch_irq,ts);
err_int_request_failed:
err_input_register_device_failed:
#if BOOT_UPDATE_FIRMWARE
err_create_nvt_fwu_wq_failed:
#endif
    input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
    mutex_destroy(&ts->lock);
err_chipid_failed:
err_check_functionality_failed:
    i2c_set_clientdata(client, NULL);
    kfree(ts);
    return ret; 
}

Tp中断注册函数

static int tpd_irq_registration(void)
{
    struct device_node *node = NULL;
    int ret = 0;

    NVT_INFO("Device Tree tpd_irq_registration!");

    node = of_find_matching_node(node, touch_of_match);

    if (node) {
        /*touch_irq = gpio_to_irq(tpd_int_gpio_number);*/
        touch_irq = irq_of_parse_and_map(node, 0);
        NVT_INFO("touch_irq number %d\n", touch_irq);

        ret = request_irq(touch_irq, tpd_eint_handler, IRQF_TRIGGER_FALLING,
                    TPD_DEVICE, NULL);//申请TP中断,中断处理函数tpd_eint_handler
        if (ret > 0){
            ret = -1;
            NVT_ERROR("tpd request_irq IRQ LINE NOT AVAILABLE!.");
        }
    } else {
        NVT_INFO("tpd request_irq can not find touch eint device node!.");
    }

    return ret;
}

Tp中断处理函数

static irqreturn_t tpd_eint_handler(int irq, void *dev_id)
{
    TPD_DEBUG_PRINT_INT;

    tpd_flag = 1;//中断标记

    wake_up_interruptible(&waiter);//中断触发,唤醒进程

    return IRQ_HANDLED;
}

Tp触摸事件处理函数touch_event_handler

static int touch_event_handler(void *unused)
{
    struct sched_param param = { .sched_priority = 4 }; /*RTPM_PRIO_TPD*/
    struct i2c_client *client = ts->client;

    int32_t ret = -1;
    uint8_t point_data[64] = {0};
    uint32_t position = 0;
    uint32_t input_x = 0;
    uint32_t input_y = 0;
    uint32_t input_w = 0;

    uint8_t point_data1[64] = {0};

    uint8_t input_id = 0;
    uint8_t press_id[TOUCH_MAX_FINGER_NUM] = {0};

    int32_t i = 0;
    int32_t finger_cnt = 0;

    sched_setscheduler(current, SCHED_RR, &param);
    do
    {
        set_current_state(TASK_INTERRUPTIBLE);

        while (tpd_halt_1)
        {
        #if WAKEUP_GESTURE
            //if (bTouchInGesture == 1)
            if (bTouchIsAwake== 0)
            {
                break;
            }
        #endif
            tpd_flag = 0;
            msleep(20);
        }

        wait_event_interruptible(waiter, tpd_flag != 0);//等待触摸中断触发
        tpd_flag = 0;
        TPD_DEBUG_SET_TIME;
        set_current_state(TASK_RUNNING);

        mutex_lock(&ts->lock);
        memset(point_data,0,64);
        ret = CTP_I2C_READ(ts->client, I2C_FW_Address, point_data, 62 + 1);
        if (ret < 0) {
            dev_err(&client->dev, "%s: CTP_I2C_READ failed.(%d)\n", __func__, ret);
            goto XFER_ERROR;
        }

        finger_cnt = 0;
        input_id = (uint8_t)(point_data[1] >> 3);

        memset(press_id,0,10);//0826

        #if WAKEUP_GESTURE
            //if (bTouchInGesture == 1)
            if (bTouchIsAwake== 0){
                nvt_ts_wakeup_gesture_report(input_id);
                mutex_unlock(&ts->lock);
                continue;
            }
        #endif

        #if MT_PROTOCOL_B
            for (i = 0; i < ts->max_touch_num; i++) {
                position = 1 + 6 * i;
                input_id = (uint8_t)(point_data[position + 0] >> 3);
                if (input_id > TOUCH_MAX_FINGER_NUM)
                    continue;

                if (((point_data[position] & 0x07) == 0x01) || ((point_data[position] & 0x07) == 0x02)) {   //finger down (enter & moving)
                    input_x = (uint32_t)(point_data[position + 1] << 4) + (uint32_t) (point_data[position + 3] >> 4);
                    input_y = (uint32_t)(point_data[position + 2] << 4) + (uint32_t) (point_data[position + 3] & 0x0F);
                    input_w = (uint32_t)(point_data[position + 4]) + 10;
                    if (input_w > 255)
                        input_w = 255;

                    if ((input_x < 0) || (input_y < 0))
                        continue;
                    if ((input_x > ts->abs_x_max)||(input_y > ts->abs_y_max))
                        continue;

                    press_id[input_id - 1] = 1;
                    input_mt_slot(ts->input_dev, input_id - 1);
                    input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);

                    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
                    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
                    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
                    input_report_abs(ts->input_dev, ABS_MT_PRESSURE, input_w);
                //  NVT_INFO("report abs:x=%d, y=%d\n",input_x,input_y);
                    finger_cnt++;
                }
            }

            for (i = 0; i < ts->max_touch_num; i++) {
                if (press_id[i] != 1) {
                    input_mt_slot(ts->input_dev, i);
                    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
                    input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
                    input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);
                }
            }

            input_report_key(ts->input_dev, BTN_TOUCH, (finger_cnt > 0));

        #else

            for (i = 0; i < ts->max_touch_num; i++) {
                position = 1 + 6 * i;
                input_id = (uint8_t)(point_data[position + 0] >> 3);

                if ((point_data[position] & 0x07) == 0x03) {    // finger up (break)
                    continue;//input_report_key(ts->input_dev, BTN_TOUCH, 0);
                } else if (((point_data[position] & 0x07) == 0x01) || ((point_data[position] & 0x07) == 0x02)) {    //finger down (enter & moving)
                    input_x = (uint32_t)(point_data[position + 1] << 4) + (uint32_t) (point_data[position + 3] >> 4);
                    input_y = (uint32_t)(point_data[position + 2] << 4) + (uint32_t) (point_data[position + 3] & 0x0F);
                    input_w = (uint32_t)(point_data[position + 4]) + 10;
                    if (input_w > 255)
                        input_w = 255;

                    if ((input_x < 0) || (input_y < 0))
                        continue;
                    if ((input_x > ts->abs_x_max)||(input_y > ts->abs_y_max))
                        continue;

                    press_id[input_id - 1] = 1;
                    input_report_key(ts->input_dev, BTN_TOUCH, 1);
                    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
                    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
                    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
                    input_report_abs(ts->input_dev, ABS_MT_PRESSURE, input_w);
                    input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, input_id - 1);
                //  NVT_INFO("report abs:x=%d, y=%d\n",input_x,input_y);
                    input_mt_sync(ts->input_dev); //上报事件

                    finger_cnt++;
                }
            }
            if (finger_cnt == 0) {
                input_report_key(ts->input_dev, BTN_TOUCH, 0);

                input_mt_sync(ts->input_dev);//上报事件
            }
        #endif


        #if TOUCH_KEY_NUM > 0
          //  NVT_INFO("point_data[61]=0x%x, point_data[62]=0x%x\n",point_data[61],point_data[62]);
            if (point_data[61] == 0xF8) {

                if(point_data1[62] == point_data[62])
                {

                }
                else
                {
                    point_data1[61] = point_data[61];
                    point_data1[62] = point_data[62];
                    NVT_INFO("point_data[61]=0x%x, point_data[62]=0x%x\n",point_data[61],point_data[62]);
                }  

                for (i = 0; i < TOUCH_KEY_NUM; i++) {
                    input_report_key(ts->input_dev, touch_key_array_1[i], ((point_data[62] >> i) & 0x01));//上报触摸按键事件
                }
            } else {
                for (i = 0; i < TOUCH_KEY_NUM; i++) {
                    input_report_key(ts->input_dev, touch_key_array_1[i], 0);
                }
            }
        #endif

        input_sync(ts->input_dev);//上报事件

XFER_ERROR:
        mutex_unlock(&ts->lock);

    } while (!kthread_should_stop());

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值