0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

簡單聊一下多點觸控協(xié)議

嵌入式軟件開發(fā)交流 ? 來源:嵌入式軟件開發(fā)交流 ? 2023-04-17 09:20 ? 次閱讀

前言

前面簡單聊了一下多點觸控協(xié)議,接下來找個驅(qū)動來看看具體實現(xiàn)。目前市面上多點觸控芯片用得比較多的主要是匯頂和敦泰。我們找一款敦泰的芯片來看看。

多點觸控驅(qū)動分析

Linux版本:5.10

芯片:FT5436 (10點觸控芯片)

通信接口: I2C

(1)加載和卸載函數(shù)

static const struct i2c_device_id fts_ts_id[] = {
    {FTS_DRIVER_NAME, 0},
    {},
};


//設(shè)備樹匹配
static const struct of_device_id fts_dt_match[] = {
    {.compatible = "focaltech,ft5436", },
    {},
};
MODULE_DEVICE_TABLE(of, fts_dt_match);


static struct i2c_driver fts_ts_driver = {
    .probe = fts_ts_probe,
    .remove = fts_ts_remove,
    .driver = {
        .name = FTS_DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(fts_dt_match),
    },
    .id_table = fts_ts_id,
};


static int __init fts_ts_init(void)
{
    int ret = 0;


    FTS_FUNC_ENTER();
    //添加i2c設(shè)備驅(qū)動
    ret = i2c_add_driver(&fts_ts_driver);
    if ( ret != 0 ) {
        FTS_ERROR("Focaltech touch screen driver init failed!");
    }
    FTS_FUNC_EXIT();
    return ret;
}


static void __exit fts_ts_exit(void)
{
    i2c_del_driver(&fts_ts_driver);
}
module_init(fts_ts_init);
module_exit(fts_ts_exit);

FT5436使用I2C接口進(jìn)行通信,所以注冊i2c_driver。

(2)probe()函數(shù)

static int fts_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
    struct fts_ts_data *ts_data = NULL;


    FTS_INFO("Touch Screen(I2C BUS) driver prboe...");
    //檢查I2C功能
    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
        FTS_ERROR("I2C not supported");
        return -ENODEV;
    }


    //為結(jié)構(gòu)體分配內(nèi)存
    ts_data = (struct fts_ts_data *)kzalloc(sizeof(*ts_data), GFP_KERNEL);
    if (!ts_data) {
        FTS_ERROR("allocate memory for fts_data fail");
        return -ENOMEM;
    }


    //保存數(shù)據(jù),方便后面使用
    fts_data = ts_data;
    ts_data->client = client; //i2c設(shè)備
    ts_data->dev = &client->dev;
    ts_data->log_level = 1;
    ts_data->fw_is_running = 0;
    i2c_set_clientdata(client, ts_data);
    //進(jìn)入真正的probe流程
    ret = fts_ts_probe_entry(ts_data);
//......


    FTS_INFO("Touch Screen(I2C BUS) driver prboe successfully");
    return 0;
}

初始化結(jié)構(gòu)體,保存i2c設(shè)備,然后調(diào)用fts_ts_probe_entry進(jìn)入設(shè)備的初始化。

static int fts_ts_probe_entry(struct fts_ts_data *ts_data)
{
    int ret = 0;
    int pdata_size = sizeof(struct fts_ts_platform_data);
    struct device_node *np = ts_data->dev->of_node;


    FTS_FUNC_ENTER();
    FTS_INFO("%s", FTS_DRIVER_VERSION);
    ts_data->pdata = kzalloc(pdata_size, GFP_KERNEL);
    if (!ts_data->pdata) {
        FTS_ERROR("allocate memory for platform_data fail");
        return -ENOMEM;
    }
    //獲取平臺數(shù)據(jù)
    if (ts_data->dev->of_node) {
        //dts解析
        ret = fts_parse_dt(ts_data->dev, ts_data->pdata);
        if (ret)
            FTS_ERROR("device-tree parse fail");
    } else {
        if (ts_data->dev->platform_data) {
            memcpy(ts_data->pdata, ts_data->dev->platform_data, pdata_size);
        } else {
            FTS_ERROR("platform_data is null");
            return -ENODEV;
        }
    }
    //創(chuàng)建工作隊列
    ts_data->ts_workqueue = create_singlethread_workqueue("fts_wq");
    //.....


    //在輸入子系統(tǒng)中注冊設(shè)備
    ret = fts_input_init(ts_data);
    if (ret) {
        FTS_ERROR("input initialize fail");
        goto err_input_init;
    }
    //......
    //gpio配置(中斷,復(fù)位)
    ret = fts_gpio_configure(ts_data);
    if (ret) {
        FTS_ERROR("configure the gpios fail");
        goto err_gpio_config;
    }


    //.....
    //創(chuàng)建proc調(diào)試接口
    ret = fts_create_apk_debug_channel(ts_data);
    if (ret) {
        FTS_ERROR("create apk debug node fail");
    }
    //創(chuàng)建sys調(diào)試接口
    ret = fts_create_sysfs(ts_data);
    if (ret) {
        FTS_ERROR("create sysfs node fail");
    }


#if FTS_POINT_REPORT_CHECK_EN
    //初始化work(用于處理中斷數(shù)據(jù))
    ret = fts_point_report_check_init(ts_data);
    if (ret) {
        FTS_ERROR("init point report check fail");
    }
#endif
    //.....
    //注冊中斷
    ret = fts_irq_registration(ts_data);
    //.....
    //初始化固件更新功能(用于為Touch模組更新固件)
    ret = fts_fwupg_init(ts_data);
    if (ret) {
        FTS_ERROR("init fw upgrade fail");
    }
    //配置休眠喚醒
#if defined(CONFIG_FB)
    if (ts_data->ts_workqueue) {
        INIT_WORK(&ts_data->resume_work, fts_resume_work);
    }
    ts_data->tp.tp_resume = fts_ts_late_resume;
    ts_data->tp.tp_suspend = fts_ts_early_suspend;
    //通過LCD屏亮滅來決定喚醒
    tp_register_fb(&ts_data->tp);
#elif defined(CONFIG_HAS_EARLYSUSPEND)
    ts_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + FTS_SUSPEND_LEVEL;
    ts_data->early_suspend.suspend = fts_ts_early_suspend;
    ts_data->early_suspend.resume = fts_ts_late_resume;
    register_early_suspend(&ts_data->early_suspend);
#endif
    //使能中斷喚醒
    if (of_property_read_bool(np, "wakeup-source"))
    {
        device_init_wakeup(&ts_data->client->dev, 1);
        enable_irq_wake(ts_data->irq);
    }


    FTS_FUNC_EXIT();
    return 0;
    //......
}

上面主要完成如下工作:

1.解析dts

2.創(chuàng)建工作隊列(處理中斷下半部)

3.注冊輸入子系統(tǒng)設(shè)備

4.初始化GPIO(中斷和復(fù)位)

5.創(chuàng)建proc和sys調(diào)試接口

6.注冊中斷

7.初始化固件更新功能(用于升級Touch芯片上的固件)

8.配置休眠喚醒

(3)注冊輸入設(shè)備

static int fts_input_init(struct fts_ts_data *ts_data)
{
    int ret = 0;
    int key_num = 0;
    struct fts_ts_platform_data *pdata = ts_data->pdata;
    struct input_dev *input_dev;


    FTS_FUNC_ENTER();
    //分配輸入設(shè)備(input_dev)
    input_dev = input_allocate_device();
    if (!input_dev) {
        FTS_ERROR("Failed to allocate memory for input device");
        return -ENOMEM;
    }


    /* Init and register Input device */
    input_dev->name = FTS_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); //絕對坐標(biāo)事件(比如X,Y坐標(biāo)信息)
    __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) {
        FTS_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 FTS_MT_PROTOCOL_B_EN
    //Type B協(xié)議
    //初始化SLOT(最大觸點數(shù))
    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
    //設(shè)置X,Y,接觸軸
    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 FTS_REPORT_PRESSURE_EN
    //設(shè)置壓力值
    input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0);
#endif
    //注冊輸入設(shè)備
    ret = input_register_device(input_dev);
    //.....


    ts_data->input_dev = input_dev;


    FTS_FUNC_EXIT();
    return 0;
}

設(shè)置支持的輸入事件,然后注冊到輸入子系統(tǒng)中。

(4)中斷處理

static irqreturn_t fts_irq_handler(int irq, void *data)
{
    struct fts_ts_data *ts_data = (struct fts_ts_data *)data;


    if (!ts_data) {
        FTS_ERROR("[INTR]: Invalid fts_ts_data");
        return IRQ_HANDLED;
    }


    if (device_can_wakeup(&ts_data->client->dev))
        pm_stay_awake(&ts_data->client->dev);        
    //讀取數(shù)據(jù)
    fts_irq_read_report();
    if (device_can_wakeup(&ts_data->client->dev))
        pm_relax(&ts_data->client->dev);


    return IRQ_HANDLED;
}
static void fts_irq_read_report(void)
{
    int ret = 0;
    struct fts_ts_data *ts_data = fts_data;
    //.....


#if FTS_POINT_REPORT_CHECK_EN
    //添加work到工作隊列中(延遲)
    fts_prc_queue_work(ts_data);
#endif
    //讀取touch數(shù)據(jù)
    ret = fts_read_parse_touchdata(ts_data);
    if (ret == 0) {
        mutex_lock(&ts_data->report_mutex);
        //上報數(shù)據(jù)
#if FTS_MT_PROTOCOL_B_EN
        fts_input_report_b(ts_data); //Type B
#else
        fts_input_report_a(ts_data); //Type A
#endif
        mutex_unlock(&ts_data->report_mutex);
    }
    //......
}

讀取touch數(shù)據(jù)并解析,然后進(jìn)行事件上報。

(5)讀取和解析數(shù)據(jù)

static int fts_read_parse_touchdata(struct fts_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;
    //通過I2C讀取芯片數(shù)據(jù)
    ret = fts_read_touchdata(data);
    if (ret) {
        return ret;
    }


    //對讀取到的數(shù)據(jù)進(jìn)行解析
    data->point_num = buf[FTS_TOUCH_POINT_NUM] & 0x0F;
    data->touch_point = 0;


    if (data->ic_info.is_incell) {
        if ((data->point_num == 0x0F) && (buf[2] == 0xFF) && (buf[3] == 0xFF)
            && (buf[4] == 0xFF) && (buf[5] == 0xFF) && (buf[6] == 0xFF)) {
            FTS_DEBUG("touch buff is 0xff, need recovery state");
            fts_release_all_finger();
            fts_tp_state_recovery(data);
            return -EIO;
        }
    }
    //.....
    for (i = 0; i < max_touch_num; i++) {
        base = FTS_ONE_TCH_LEN * i;
        pointid = (buf[FTS_TOUCH_ID_POS + base]) >> 4;
        if (pointid >= FTS_MAX_ID)
            break;
        else if (pointid >= max_touch_num) {
            FTS_ERROR("ID(%d) beyond max_touch_number", pointid);
            return -EINVAL;
        }


        data->touch_point++;
        events[i].x = ((buf[FTS_TOUCH_X_H_POS + base] & 0x0F) << 8) +
                      (buf[FTS_TOUCH_X_L_POS + base] & 0xFF);
        events[i].y = ((buf[FTS_TOUCH_Y_H_POS + base] & 0x0F) << 8) +
                      (buf[FTS_TOUCH_Y_L_POS + base] & 0xFF);
        events[i].flag = buf[FTS_TOUCH_EVENT_POS + base] >> 6;
        events[i].id = buf[FTS_TOUCH_ID_POS + base] >> 4;
        events[i].area = buf[FTS_TOUCH_AREA_POS + base] >> 4;
        events[i].p =  buf[FTS_TOUCH_PRE_POS + base];


        if (EVENT_DOWN(events[i].flag) && (data->point_num == 0)) {
            FTS_INFO("abnormal touch data from fw");
            return -EIO;
        }
    }


    if (data->touch_point == 0) {
        FTS_INFO("no touch point information");
        return -EIO;
    }


    return 0;
}

fts_read_touchdata()從芯片中讀出數(shù)據(jù),然后對數(shù)據(jù)進(jìn)行解析。

(6)事件上報

static int fts_input_report_b(struct fts_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;


    for (i = 0; i < data->touch_point; i++) {
        if (fts_input_report_key(data, i) == 0) {
            continue;
        }


        va_reported = true;
        //上報ABS_MT_SLOT事件
        input_mt_slot(data->input_dev, events[i].id);


        //按下/抬起手指
        if (EVENT_DOWN(events[i].flag)) {
            //上報手指按下和坐標(biāo)等信息


            //使用MT_TOOL_FINGER來確定按下和抬起,
            //就不需要使用ABS_MT_TRACKING_ID來控制觸點的生命周期了
            input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true);


#if FTS_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);
            //上報X,Y坐標(biāo)
            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);
            //......
        } 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) {
                FTS_DEBUG("[B]P%d UP!", events[i].id);
            }
        }
    }


    if (unlikely(data->touchs ^ touchs)) {
        for (i = 0; i < max_touch_num; i++)  {
            if (BIT(i) & (data->touchs ^ touchs)) {
                if (data->log_level >= 1) {
                    FTS_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;
    //上報Touch按鍵事件
    if (va_reported) {
        /* touchs==0, there's no point but key */
        if (EVENT_NO_DOWN(data) || (!touchs)) {
            //所有觸點都抬起了
            if (data->log_level >= 1) {
                FTS_DEBUG("[B]Points All Up!");
            }
            input_report_key(data->input_dev, BTN_TOUCH, 0);
        } else {
            input_report_key(data->input_dev, BTN_TOUCH, 1);
        }
    }
    //同步(告訴上層本次上報結(jié)束)
    input_sync(data->input_dev);
    return 0;
}

上報各種事件(MT_TOOL_FINGER/ABS_MT_POSITION_X/ABS_MT_POSITION_Y等 )給上層。

總結(jié)

整體分析下來,會發(fā)現(xiàn)多點觸控驅(qū)動并不難,主要就是注冊為輸入子系統(tǒng),然后中斷觸發(fā)后讀取觸控數(shù)據(jù),最后通過輸入子系統(tǒng)上報數(shù)據(jù)。所有輸入子系統(tǒng)的驅(qū)動基本都是這個套路。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21608
  • I2C接口
    +關(guān)注

    關(guān)注

    1

    文章

    124

    瀏覽量

    25106
  • 觸控芯片
    +關(guān)注

    關(guān)注

    2

    文章

    66

    瀏覽量

    21624
  • FFTs
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    5360

原文標(biāo)題:Linux驅(qū)動分析之多點觸控驅(qū)動

文章出處:【微信號:嵌入式軟件開發(fā)交流,微信公眾號:嵌入式軟件開發(fā)交流】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    一下IGBT驅(qū)動中的參考電位問題

    大家好,今天一下IGBT驅(qū)動中的**參考電位**問題。我們都知道IGBT的驅(qū)動參考電平都是基于 **器件自身的發(fā)射極** ,當(dāng)柵極相對于發(fā)射極電位 **超過閾值電壓時,器件就會開通** , **小于閾值電壓后,器件就會關(guān)斷** 。
    的頭像 發(fā)表于 11-09 15:19 ?1056次閱讀
    <b class='flag-5'>聊</b><b class='flag-5'>一下</b>IGBT驅(qū)動中的參考電位問題

    FPGA板和多點控屏之間的連接?

    大家好??!我是FPGA(套件)及其接口的新手。我將參與個項目。這個項目的部分是連接/驅(qū)動至少10+“對角線的多點控電容式觸摸屏。任何人都可以幫助我指導(dǎo)我需要開始的東西。就像有幾種
    發(fā)表于 07-13 16:53

    什么是多點控技術(shù)?多點控是怎么實現(xiàn)的?

    什么是多點控技術(shù)?多點控是怎么實現(xiàn)的?多點控技術(shù)的用途有哪些?
    發(fā)表于 06-17 07:47

    請問一下RK3288 ubuntu系統(tǒng)支持多點控嗎

    請問一下RK3288 ubuntu支持多點控嗎?求大神解答一下
    發(fā)表于 09-21 17:33

    全面解析多點控技術(shù)

    全面解析多點控技術(shù)
    發(fā)表于 01-14 12:30 ?15次下載

    多點控技術(shù)的全解析

    輸入設(shè)備(如:鼠標(biāo)、鍵盤等。)進(jìn)行計算機(jī)的人機(jī)交互操作。多點觸摸技術(shù),能構(gòu)成個觸摸屏(屏幕,桌面,墻壁等)或觸控板,都能夠同時接受來自屏幕上多個點進(jìn)行計算機(jī)的人機(jī)交互操作。 多點
    發(fā)表于 11-06 14:53 ?17次下載

    單點控和多點控區(qū)別是什么?原理分析

    導(dǎo)語:屏手機(jī)、平板電腦等新型的智能設(shè)備的崛起,除了因為像安卓和ios這樣的智能系統(tǒng)誕生的原因外,不可或缺的個條件就是觸摸屏幕的更新?lián)Q代和多點控技術(shù)的出現(xiàn)。下面我們就來介紹單點
    發(fā)表于 11-08 09:03 ?1.9w次閱讀

    多點懸浮控技術(shù)將掀起場新革命

    智能手機(jī)可用手指在空中操作的時代即將來臨。蘋果正在準(zhǔn)備在遠(yuǎn)離畫面的非接觸狀態(tài)即可用手指進(jìn)行輸入的“多點懸浮控(Multi hovering)”技術(shù)。曾憑借多點
    的頭像 發(fā)表于 09-04 08:38 ?5247次閱讀

    多點控應(yīng)用的模擬多點控模擬環(huán)境搭建

    隨著手機(jī),平板電腦的普及和流行,越來越多的應(yīng)用程序使用多點控進(jìn)行操作。隨著Windows7系統(tǒng)增加了多點控,WPF4.0和Windows Phone中相關(guān)的類庫也使得
    發(fā)表于 11-18 10:52 ?3085次閱讀
    <b class='flag-5'>多點</b><b class='flag-5'>觸</b>控應(yīng)用的模擬<b class='flag-5'>多點</b><b class='flag-5'>觸</b>控模擬環(huán)境搭建

    Bada系統(tǒng)學(xué)習(xí)-使用多點

    an existing point結(jié)束多點控要結(jié)束多點控,松開?CTRL?鍵. 模擬器上的控點將失效,下
    發(fā)表于 04-02 14:35 ?284次閱讀

    簡單DPT技術(shù)-double pattern technology

    今天想來簡單DPT技術(shù)-double pattern technology,也就是雙層掩模版技術(shù),在目前先進(jìn)工藝,這項技術(shù)已經(jīng)應(yīng)用的
    的頭像 發(fā)表于 12-05 14:26 ?1488次閱讀

    芯片設(shè)計的NDR是什么?

    今天突然想route相關(guān)的問題,講講NDR是什么,我也梳理總結(jié)一下我對NDR的認(rèn)識。
    的頭像 發(fā)表于 12-06 15:14 ?1700次閱讀

    多點控和單點控區(qū)別

     多點控和單點控是觸摸屏技術(shù)的兩種主要類型,它們在功能、應(yīng)用場景以及用戶體驗等方面存在顯著差異。以下是對這兩種控技術(shù)的詳細(xì)比較:
    的頭像 發(fā)表于 10-21 15:35 ?487次閱讀

    多點控和單點控哪個好

    多點控和單點控各有其優(yōu)缺點,具體哪個更好取決于應(yīng)用場景和用戶需求。以下是對兩者的詳細(xì)比較:
    的頭像 發(fā)表于 10-21 15:36 ?332次閱讀

    多點控是觸摸屏嗎_多點控功能

    多點控是觸摸屏的種技術(shù)。多點控(Multipoint Touch)是種人機(jī)交互技術(shù),它允
    的頭像 發(fā)表于 10-21 15:47 ?422次閱讀