OK6410的觸摸屏驅動分析

来源:http://www.cnblogs.com/chd-zhangbo/archive/2016/01/31/5173980.html
-Advertisement-
Play Games

一. device的註冊1.0 兩個註冊//在smdk6410_machine_init中既註冊了touchscreen的私有信息也註冊了ts資源 在arch/arm/mach-s3c64xx/mach-smdk6410.c中 static void __init smdk6410_machine_


 

一. device的註冊
1.0 兩個註冊
//在smdk6410_machine_init中既註冊了touchscreen的私有信息也註冊了ts資源

  1. 在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  2. static void __init smdk6410_machine_init(void)
  3. {
  4.     //在arch/arm/mach-s3c64xx/dev-ts.c中
  5.     s3c_ts_set_platdata(&s3c_ts_platform);                                  //1.設備私有信息的註冊
  6.     //在driver/base/platform.c中
  7.     platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));   //2.設備資源的註冊
  8. }

1.1 ts私有信息的註冊
在arch/arm/mach-s3c64xx/mach-smdk6410.c中

  1. static struct s3c_ts_mach_info s3c_ts_platform __initdata = {
  2.     .delay               = 10000,                    //延時
  3.     .presc               = 49,                       //分頻
  4.     .oversampling_shift  = 2,                        //分頻
  5.     .resol_bit           = 12,                       //精度     
  6.     .s3c_adc_con         = ADC_TYPE_2,               //分頻     
  7. };
  8. smdk6410_machine_init
  9. {
  10.     //下麵這個函數在arch/arm/mach-s3c64xx/dev-ts.c中
  11.     s3c_ts_set_platdata(&s3c_ts_platform);
  12. }

1.2 ts設備資源的註冊

  1. //在arch/arm/mach-s3c64xx/dev-ts.c中
  2. static struct resource s3c_ts_resource[] = {
  3.     [0] = {
  4.         .start = SAMSUNG_PA_ADC,                        //0x7E00B000
  5.         .end = SAMSUNG_PA_ADC + SZ_256 - 1,             //0x7E00B100    
  6.         .flags = IORESOURCE_MEM,
  7.     },
  8.     [1] = {
  9.         .start = IRQ_PENDN,                             //0x5e=94
  10.         .end = IRQ_PENDN,
  11.         .flags = IORESOURCE_IRQ,
  12.     },
  13.     [2] = {
  14.         .start = IRQ_ADC,                                //0x5f=95
  15.         .end = IRQ_ADC,
  16.         .flags = IORESOURCE_IRQ,
  17.     }
  18. };
  19. struct platform_device s3c_device_ts = {
  20.     .name         = "s3c-ts",
  21.     .id         = -1,
  22.     .num_resources     = ARRAY_SIZE(s3c_ts_resource),
  23.     .resource     = s3c_ts_resource,
  24. };
  25. //在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  26. static struct platform_device *smdk6410_devices[] __initdata = {
  27.     &s3c_device_ts,                //把ts放入到總的ts列表中
  28. }
  29. //在arch/arm/mach-s3c64xx/mach-smdk6410.c中
    static void __init smdk6410_machine_init(void)
    {
        //在driver/base/platform.c中一起註冊
        platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
    }

二. device_driver
2.0 兩個巨集

  1. #define WAIT4INT(x)              //只是針對於S3C_ADCTSC寄存器
  2.         (((x)<<8) |              //<bit8> 0->down 1->up interrupt signal
  3.         S3C_ADCTSC_YM_SEN |      //<bit7> 1 = Switch enable (YM = VSSA_ADC)
  4.         S3C_ADCTSC_YP_SEN |      //<bit6> 1 = Switch disable (YP=AIN5, Hi-z) 
  5.         //XM_SEN                //<bit5> 0 = Switch disable (XM = AIN6, Hi-z)
  6.         S3C_ADCTSC_XP_SEN |      //<bit4> 1 = Switch disable (XP=AIN7, Hi-z)
  7.         //PULL_UP               //<bit3> 0 = XP Pull-up Enable.
  8.         //AUTO_PST              //<bit2> 0 = Normal ADC conversion.         
  9.         S3C_ADCTSC_XY_PST(3))    //<bit1-0> 3: Waiting for Interrupt Mode 
  10. #define AUTOPST     
  11.     (S3C_ADCTSC_YM_SEN |        //1 = Switch enable (YM = VSSA_ADC)
  12.     S3C_ADCTSC_YP_SEN |         //1 = Switch disable (YP=AIN5, Hi-z) 
  13.     S3C_ADCTSC_XP_SEN |         //1 = Switch disable (XP=AIN7, Hi-z) 
  14.     S3C_ADCTSC_AUTO_PST |       //1 = Auto Sequential measurement of X-position, Y-position
  15.     S3C_ADCTSC_XY_PST(0))       //0 = No operation mode

WAIT4INT(x) :
            當x=0時,設為等侍down中斷
             當x=1時,設為等侍up中斷
2.1 初始化
ok6410的touchscreen在內核源碼的位置:driver/input/touchscreen/s3c-ts.c
device 與 device_driver按名字s3c-ts匹配之後,就進入s3c_ts_probe函數

  1. static struct platform_driver s3c_ts_driver = {
  2.     .probe = s3c_ts_probe,
  3.     .remove = s3c_ts_remove,
  4.     .suspend = s3c_ts_suspend,
  5.     .resume = s3c_ts_resume,
  6.     .driver        = {
  7.         .owner    = THIS_MODULE,
  8.         .name    = "s3c-ts",
  9.     },
  10. };
  11. static int __init s3c_ts_init(void)
  12. {
  13.     return platform_driver_register(&s3c_ts_driver);
  14. }
  15. static void __exit s3c_ts_exit(void)
  16. {
  17.     platform_driver_unregister(&s3c_ts_driver);
  18. }
  19. module_init(s3c_ts_init);
  20. module_exit(s3c_ts_exit);

2.2 probe函數

  1. static int __init s3c_ts_probe(struct platform_device *pdev)
  2. {
  3.     struct resource *res;
  4.     struct device *dev;
  5.     struct input_dev *input_dev;
  6.     struct s3c_ts_mach_info * s3c_ts_cfg;
  7.     int ret, size;
  8.     dev = &pdev->dev;
  9.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                //獲取ts寄存器地址
  10.     size = (res->end - res->start) + 1;
  11.     ts_mem = request_mem_region(res->start, size, pdev->name);           //申請I/O記憶體
  12.     ts_base = ioremap(res->start, size);                                 //request_mem_region申請的記憶體在使用前要調用ioremap
  13.     ts_clock = clk_get(&pdev->dev, "adc");                               //獲取clock    
  14.     clk_enable(ts_clock);                                                //在初始化時disable了ts_clock,這個地方要enable
  15.     
  16.                                                                 //下麵這幾行是要把ts的配置信息寫到寄存器中去
  17.     s3c_ts_cfg = s3c_ts_get_platdata(&pdev->dev);                        //獲取ts的配置信息,
  18.                                                                          //ts的私有信息:在arch/arm/mach-s3c64xx/mach-smdk6410.c中
  19.     //enable prescaler && 設置prescaler_value=s3c_ts_cfg->presc
  20.     writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(s3c_ts_cfg->presc&0xff), ts_base+S3C_ADCCON);
  21.    
  22.    //s3c_ts_cfg->delay=0x10000 --> External input clock 
  23.     writel(s3c_ts_cfg->delay & 0xffff, ts_base+S3C_ADCDLY);
  24.     
  25.     //A/D converter resolution selection--> 12-bit A/D conversion
  26.     writel(readl(ts_base+S3C_ADCCON)|S3C_ADCCON_RESSEL_12BIT, ts_base+S3C_ADCCON);
  27.     //設為等侍down中斷模式
  28.     writel(WAIT4INT(0), ts_base+S3C_ADCTSC);
  1.     ts = kzalloc(sizeof(struct s3c_ts_info), GFP_KERNEL);           //下麵這幾行是要初始化s3c_ts_info結構體
  2.     input_dev = input_allocate_device();
  3.    
  4.     ts->dev = input_dev;
  5.     ts->dev->evbit[0] = ts->dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
  6.     ts->dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
  7.     if (s3c_ts_cfg->resol_bit==12) {
  8.         input_set_abs_params(ts->dev, ABS_X, 0, 0xFFF, 0, 0);                //設置x軸的最大最小值
  9.         input_set_abs_params(ts->dev, ABS_Y, 0, 0xFFF, 0, 0);                //設置y軸的最大最小值
  10.     } 
  11.     input_set_abs_params(ts->dev, ABS_PRESSURE, 0, 1, 0, 0);                 //設置Press狀態的最大最小值(按下或空閑)   
  12.     sprintf(ts->phys, "input(ts)");
  13.     ts->dev->name = s3c_ts_name;
  14.     ts->dev->phys = ts->phys;
  15.     ts->dev->id.bustype = BUS_RS232;
  16.     ts->dev->id.vendor = 0xDEAD;
  17.     ts->dev->id.product = 0xBEEF;
  18.     ts->dev->id.version = S3C_TSVERSION;
  19.     ts->shift = s3c_ts_cfg->oversampling_shift;
  20.     ts->resol_bit = s3c_ts_cfg->resol_bit;
  21.     ts->s3c_adc_con = s3c_ts_cfg->s3c_adc_con;
  22.     /* For IRQ_PENDUP */
  23.     ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);                //獲取中斷號
  24.     //申請中斷,RANDOM表示設備可以看作隨機的發生源
  25.     ret = request_irq(ts_irq->start, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c_updown", ts); //申請中斷
  26.    
  27.     /* For IRQ_ADC */
  28.     ts_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 1);               //獲取中斷號
  29.     ret = request_irq(ts_irq->start, stylus_action, IRQF_SAMPLE_RANDOM | IRQF_SHARED, "s3c_action", ts); //申請共用中斷
  30.     
  31.     /* All went ok, so register to the input system */
  32.     ret = input_register_device(ts->dev);                                    //把這個input_dev添加到input系統中
  33. }

ts底板圖:

ts連到核心板圖:

TSXP --> AIN7
TSYP --> AIN5





2.3 IRQ_PENDN

  1. static irqreturn_t stylus_updown(int irqno, void *param)
  2. {
  3.     unsigned long data0;
  4.     unsigned long data1;
  5.     if (!ADC_locked4TS())                              //進入中斷函數,如果沒有加鎖,則加上鎖
  6.         if (s3c_ts_adc_lock(LOCK_TS))                  //如果加鎖失敗,則直接返回       
  7.             return IRQ_HANDLED;        
  8.     data0 = readl(ts_base+S3C_ADCDAT0);
  9.     data1 = readl(ts_base+S3C_ADCDAT1);
  10.     touch_timer_fire(0);
  11.     if(ts->s3c_adc_con==ADC_TYPE_2) {
  12.          //ADCCLRINTPNDNUPINT_PNDNUP interrupt clear
  13.         __raw_writel(0x0, ts_base+S3C_ADCCLRWK);    
  14.         //ADCCLRINTClear ADC Interrupt
  15.         __raw_writel(0x0, ts_base+S3C_ADCCLRINT);   
  16.     }
  17.     return IRQ_HANDLED;
  18. }


2.3.1 fire

  1. static void touch_timer_fire(unsigned long data)
  2. {
  3.     unsigned long data0;
  4.     unsigned long data1;
  5.     int pendown;
  6.     if (!ADC_locked4TS())                       //如果當前狀態是free,說明加鎖失敗,直接返回
  7.         return;
  8.     
  9.     //這兒的數據讀取,是為了判斷是down還是up狀態
  10.     data0 = readl(ts_base+S3C_ADCDAT0);         //讀
  11.     data1 = readl(ts_base+S3C_ADCDAT1);         //讀   
  12.     //data0的bit15: 0->按下狀態; 1->鬆開狀態
  13.     //如果data0與data1都不為鬆開狀態,就是按下狀態
  14.     pendown = (!(data0 & S3C_ADCDAT0_UPDOWN)) && (!(data1 & S3C_ADCDAT1_UPDOWN));
  15.     if (pendown) {           //在按下狀態,如果有數據則提交數據,      
  16.         if (ts->count) {     //這個ts->count是在IRQ_ADC中改變的  
  17.             input_report_abs(ts->dev, ABS_X, ts->xp);     //提交
  18.             input_report_abs(ts->dev, ABS_Y, ts->yp);     //提交
  19.             input_report_key(ts->dev, BTN_TOUCH, 1);       //提交
  20.             input_report_abs(ts->dev, ABS_PRESSURE, 1);    //提交  
  21.             input_sync(ts->dev);                           //提交
  22.         }                      //ts->count>0,說明ADC己經轉化過數據了,就提交完數據,  
  23.         ts->xp = 0;            //然後把所有數據歸零
  24.         ts->yp = 0;
  25.         ts->count = 0;
  26.         //設ADC的模式為自動轉換 
  27.         writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);
  28.         //ADCCON bit0 --> A/D conversion starts: 啟動adc轉換,產生一個IRQ_ADC中斷
  29.         //註意:這兒是要啟動ADC中斷,但具體是down還是up中斷
  30.         writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);  
  31.     }
  32.     else {                    //如果是鬆開
  33.         ts->count = 0;
  34.         input_report_key(ts->dev, BTN_TOUCH, 0);        //提交
  35.         input_report_abs(ts->dev, ABS_PRESSURE, 0);     //提交
  36.         input_sync(ts->dev);
  37.         writel(WAIT4INT(0), ts_base+S3C_ADCTSC);    //等侍按下中斷
  38.         if (ADC_locked4TS())                       //如果還處於鎖定狀態
  39.             s3c_ts_adc_unlock();                   //釋放鎖,表示一次按鍵結束
  40.     }
  41. }

註意: 
在按下狀態,先提交數據,產生ADC中斷,
在鬆開狀態,先提交數據,切換為按下中斷

2.4 IRQ_ADC
在進入IRQ_ADC中斷之前,己經定義了一個時間定時器,它的處理函數是 touch_timer_fire

  1. static struct timer_list touch_timer =
  2.         TIMER_INITIALIZER(touch_timer_fire, 0, 0);

IRQ_ADC中斷處理函數:

  1. static irqreturn_t stylus_action(int irqno, void *param)
  2. {
  3.     unsigned long data0;
  4.     unsigned long data1;
  5.     if (!ADC_locked4TS()) {                        //如果處於未鎖定狀態,說明出錯
  6.         if (ADC_free())                            //鎖是在IRQ_TS中加上的  
  7.             __raw_writel(0x0, ts_base + S3C_ADCCLRINT);
  8.         return IRQ_HANDLED;
  9.     }
  10.     data0 = readl(ts_base+S3C_ADCDAT0);            //讀
  11.     data1 = readl(ts_base+S3C_ADCDAT1);            //讀
  12.     if(ts->resol_bit==12) {
  13.         ts->xp += data0 & S3C_ADCDAT0_XPDATA_MASK_12BIT;     //怎麼能讓我相信這是在求平均值呢?
  14.         ts->yp += data1 & S3C_ADCDAT1_YPDATA_MASK_12BIT;
  15.     }    
  16.     ts->count++;
  17.     if (ts->count < (1<<ts->shift)) {        //小於4次,ts->shift=2
  18.         writel(S3C_ADCTSC_PULL_UP_DISABLE | AUTOPST, ts_base+S3C_ADCTSC);
  19.         writel(readl(ts_base+S3C_ADCCON) | S3C_ADCCON_ENABLE_START, ts_base+S3C_ADCCON);
  20.     } else {                                 //超過4次,則    
  21.         //啟動定時器,把超時時間設為jiffies+1,調用touch_timer_fire
  22.         mod_timer(&touch_timer, jiffies+1);
  23.         //等侍鬆開            
  24.         writel(WAIT4INT(1), ts_base+S3C_ADCTSC);
  25.     }
  26.     if(ts->s3c_adc_con==ADC_TYPE_2) {
  27.         //ADCCLRINTPNDNUPINT_PNDNUP interrupt clear
  28.         __raw_writel(0x0, ts_base+S3C_ADCCLRWK);
  29.         //ADCCLRINTClear ADC Interrupt
  30.         __raw_writel(0x0, ts_base+S3C_ADCCLRINT);
  31.     }
  32.     return IRQ_HANDLED;
  33. }

註意: 
在按下狀態,先提交數據,產生ADC中斷,
在鬆開狀態,先提交數據,切換為按下中斷


三.總結
3.1 按下到鬆開時的流程如下:


3.2 文字說明
初始化時設為等侍down中斷模式
    當有觸摸筆按下時:        
        a.觸發中斷,進入stylus_updown函數
            stylus_updown:判斷是down中斷, 如果ts->count,觸發adc中斷
        
        b.觸發ADC中斷,進入stylus_action函數
        stylus_action: ts->count小於4次, 觸發adc中斷; 
            繼續自動檢測,直到満足4次
        stylus_action:    時間定時器觸發touch_timer_fire,並切換到等侍up中斷模式
        c. touch_timer_fire:
                判斷是down中斷,彙報坐標信息,觸發adc中斷,與b進入迴圈
                持繼彙報觸摸筆按下信息
    當有觸摸筆鬆開時:
        a. touch_timer_fire:
                判斷是up中斷,彙報坐標信息,切換到等侍按下中斷


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文節選自《Android Studio實用指南》 第4章第27節 作者: 畢小朋 目前本書已上傳到百度閱讀, 在百度中搜索[Anroid Studio實用指南]便可以找到本書. 什麼是演示模式? 顧名思義,當你想給別人演示你的代碼時就會用到這個演示模式. 演示模式的特點就是全屏,開啟免打擾模式,
  • <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_
  • 如圖是效果圖 我用的是SlidingMenu-master框架來實現的 左邊的是側滑界面是一個fragment,右邊是一個主界面fragment,在主界面中用的是一個ViewPager來進行切換,自定義個NoScrollViewPager(不能左右劃的ViewPager) 如下是主界面的代碼 pac
  • 本文將從四個方面對IOS開發中JSON格式數據的生成與解析進行講解: 一、JSON是什麼? 二、我們為什麼要用JSON格式的數據? 三、如何生成JSON格式的數據? 四、如何解析JSON格式的數據? JSON格式取代了xml給網路傳輸帶來了很大的便利,但是卻沒有了xml的一目瞭然,尤其是json數據
  • 函數SUBSTRING: 1、從左開始截取字元串 left(str, length) 說明:left(被截取欄位,截取長度) 例:select left(content,200) as abstract from my_content_t 2、從右開始截取字元串 right(str, length)
  • 前段時間實現某一個功能,涉及到對數據表的查詢操作,經本地與測試環境測試過後都沒問題,這一過程貌似都很順利,想想是不是要下班了啦(雖然時間好像也不早了),接著推入正式環境下進行最後的測試(心想應該不會有什麼問題吧,畢竟就只是對數據的查詢,而且都已經測試過了,數據也完好的輸出);
  • 編譯內核: 安裝內核源碼: 選擇內核:如gentoo sources 手動編譯內核: 必須啟用的選項: Most information can be gathered by emerging "sys apps/pciutils" which contains the command: 顯卡: "
  • ubuntu下安裝shadowsocks軟體不如windows下那麼直接,本文詳細介紹了在ubuntu系統下的ss伺服器端,客戶端,和瀏覽器插件配置。
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...