am335x觸摸屏驅動簡要分析

 TI文檔node

綜述

AM335x觸摸屏控制器支持以下四種工做模式:linux

• 8路通用的ADCgit

• 4路做爲4線觸摸屏鏈接,4路做爲通用ADC數組

• 5路做爲5線觸摸屏鏈接,3路做爲通用ADCide

• 8路做爲8線觸摸屏鏈接函數

ADC採用的是12位SAR ADC, 採樣速率爲每秒200k次. AD採樣模擬信號是從start of conversion爲高時開始並在降低沿後的1個時鐘週期內繼續採樣. 它在採樣週期結束時捕獲模擬信號並啓動轉換. 它在12個時鐘週期內將採樣數據數字化,當end of conversion信號被使能爲高時, 代表數據ADCOUT<11:0>已可讀. 當之前的數據被讀取後一個新的轉換週期就能夠開始了。 請注意,ADC輸出的是加權的二進制數據oop

一 硬件鏈接:

4線觸摸屏的鏈接測試

5線觸摸屏鏈接ui

8線觸摸屏鏈接編碼

二 Linux driver

2.1 配置使能

Device Drivers  --->
         [*]  Staging drivers  --->
                  [*]  Industrial I/O support  ---> 
                  [*]  Enable buffer support within IIO
                  <*>     Industrial I/O lock free software ring                                                              
                  < >     Industrial I/O buffering based on kfifo
                  -*-  Enable triggered sampling support                                                                     
                  (2)     Maximum number of consumers per trigger
                       Analog to digital converters  --->
                                <*>   TI's ADC driver

這裏<*> TI's ADC driver 是直接編譯進內核, 若是隻是想編譯爲模塊則能夠點擊空格更改成<M>

2.2 設置驅動的平臺數據(platform_data)

在arch/arm/mach-omap2/board-am335xevm.c(個人板子是board-com335x.c)裏添加以下代碼:

#include <linux/platform_data/ti_adc.h>
static struct adc_data am335x_adc_data = {
        .adc_channels = 4,
};

static struct mfd_tscadc_board tscadc = {
        .tsc_init = &am335x_touchscreen_data,
        .adc_init = &am335x_adc_data,
};

若是你要同時使用adc和觸摸屏的話照上邊這樣設置便可.

若是隻使用adc則要移除觸摸屏的平臺數據(platform data),以下所示:

static struct adc_data am335x_adc_data = {
        .adc_channels = 8,
};

/*     
static struct tsc_data am335x_touchscreen_data  = {
        .wires  = 4,
        .x_plate_resistance = 200,
        .steps_to_configure = 5,
};  
*/

static struct mfd_tscadc_board tscadc = {
        /*   .tsc_init = &am335x_touchscreen_data, */
        .adc_init = &am335x_adc_data,
};

三 測試

將直流電壓鏈接到AIN0到AIN7的引腳上(你使用了哪一個就接在哪一個引腳),千萬注意測試電壓只能在0~1.8v之間

3.1 查看IIO設備

root@arago-armv7:~# ls -al /sys/bus/iio/devices/iio\:device0/
drwxr-xr-x    5 root     root            0 Jan  1 00:00 .
drwxr-xr-x    4 root     root            0 Jan  1 00:00 ..
drwxr-xr-x    2 root     root            0 Jan  1 00:00 buffer
-r--r--r--    1 root     root         4096 Jan  1 00:00 dev
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage0_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage1_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage2_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage3_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage4_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage5_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage6_raw
-r--r--r--    1 root     root         4096 Jan  1 00:00 in_voltage7_raw
-rw-r--r--    1 root     root         4096 Jan  1 00:00 mode
-r--r--r--    1 root     root         4096 Jan  1 00:00 name
drwxr-xr-x    2 root     root            0 Jan  1 00:00 power
drwxr-xr-x    2 root     root            0 Jan  1 00:00 scan_elements
lrwxrwxrwx    1 root     root            0 Jan  1 00:00 subsystem -> ../../../../../../bus/iio
-rw-r--r--    1 root     root         4096 Jan  1 00:00 uevent

3.2 單次模式

檢查ADC模式, 以下所示即爲單次模式

cat /sys/bus/iio/devices/iio\:device0/mode
oneshot

若是不是單次模式可使用以下命令更改

Echo onesht > /sys/bus/iio/devices/iio\:device0/mode

從某一端口讀取ADC輸出數據:

in_voltageX_raw: raw value of the channel X of the ADC

從如下命令可知in_voltageX_raw裏保存的就是ADC的原始數據, 4095即滿量程數據

root@arago:~# cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
4095

四 計算結果

D = Vin * (2^n - 1) / Vref

好比讀取回來ADC的數據是2298那麼輸入電壓就是

Vin = D / ((2^n - 1) / Vref)

Vin = 2298 / ((2^12 – 1) / 1.8)

Vin = 1.01V

相關資料:

1 AM335x ADC Driver's Guide http://www.deyisupport.com/question_answer/w/faq/469.am335x-linux.aspx

2 AM335X 觸摸屏的硬件鏈接及Linux驅動

http://ti.eetop.cn/viewnews-4453

3 Using resistive touch screens for human/machine interface

http://www.ti.com/lit/an/slyt209a/slyt209a.pdf

input子系統

由於觸摸屏使用的是input子系統因此要講解觸摸屏以前首先要講解一下input子系統, 它的核心文件是input.c

Input子系統結構與功能實現

1 Input子系統是分層結構的,總共分爲三層: 硬件驅動層,子系統核心層,事件處理層。 

(1)其中硬件驅動層負責操做具體的硬件設備,這層的代碼是針對具體的驅動程序的,須要驅動程序的做者來編寫

(2)子系統核心層是連接其餘兩個層之間的紐帶與橋樑,向下提供驅動層的接口,向上提供事件處理層的接口

(3)事件處理層負責與用戶程序打交道,將硬件驅動層傳來的事件報告給用戶程序

2各層之間通訊的基本單位就是事件,任何一個輸入設備的動做均可以抽象成一種事件,如鍵盤的按下,觸摸屏的按下,鼠標的移動等。事件有三種屬性:類型(type),編碼(code),值(value),Input子系統支持的全部事件都定義在input.h中,包括全部支持的類型,所屬類型支持的編碼等。事件傳送的方向是 硬件驅動層-->子系統核心-->事件處理層-->用戶空間

3 以觸摸屏爲例說明輸入子系統的工做流程:

     注:am335x sdk6的觸摸屏驅動所用驅動層對應的模塊文件爲:ti_tsc.c,事件處理層對應的模塊文件爲 evdev.c

    (1)ti_tsc模塊初始化函數中將觸摸屏註冊到了輸入子系統中,於此同時,註冊函數在事件處理層鏈表中尋找事件處理器,這裏找到的是evdev,而且將驅動與事件處理器掛載。而且在/dev/input中生成設備文件event0,之後咱們訪問這個文件就會找的咱們的觸摸屏驅動程序。

    (2)應用程序打開設備文件/dev/input/event0,讀取設備文件,調用evdev模塊中read,若是沒有事件,進程就會睡眠。  

    (3)當觸摸屏按下,驅動層經過input子系統核心層將事件(就是X,Y座標, 壓感, 按下/鬆開)傳給事件處理層也就是evdev,evdev喚醒睡眠的進程,將事件傳給進程處理。

下邊看下代碼流程:

input_init()
         class_register
register_chrdev(INPUT_MAJOR, "input", &input_fops);
能夠看到input子系統幫咱們寫了以上兩個函數, 那麼這個input_fops是否是就是咱們要填充的file_operations呢?
static const struct file_operations input_fops = {
         .owner = THIS_MODULE,
         .open = input_open_file,
         .llseek = noop_llseek,
};

這個file_operations並無read/write等接口, 由此咱們可知該結構體只是一個鏈接上下層的做用, 這是一種分層的思想. 那麼他就是經過open成員來鏈接上下層, 咱們來看下open成員作了什麼事情:

input_open_file
        handler = input_table[iminor(inode) >> 5];//使用此設備號拿到handler結構體
        new_fops = fops_get(handler->fops);      //獲取新的file_operations
        file->f_op = new_fops;                             //使用handler的fops成員來做爲新的file_operations
        new_fops->open(inode, file);                   //handler->fops->open(indoe, file)

由此可知: 經過次設備號拿到數組中的handler成員, 就完成了上層的input_fops到底層的真實handler->fops的轉換,

底層的handler->fops->open(indoe, file) 就是真實的open, 對應的read/write也是

如今最關鍵的就是input_table[]數組是怎麼來的呢?  

經過查找代碼發如今 input_register_handler裏使用了它, 那麼誰調用了這個函數呢? 在input子系統的下邊有不少驅動都用到了這個函數, 他們首先查找有沒有能匹配的硬件,若是有就調用這個函數將input_handler放入數組裏邊.

這些驅動在如下的軟件部分能夠看到:

軟件部分

Evdev.c  Joydev.c Keyboard.c Mousedev.c等這些就是input子系統向上註冊input_handler

input_register_handler
         input_attach_handler  判斷硬件的id_table可否與本身的id_table匹配, 若是匹配這創建鏈接

硬件部分:

input_register_device
         input_attach_handler   判斷軟件的id_table可否與本身的id_table匹配, 若是匹配這創建鏈接

device和handler在註冊的時候都會查找對方是否有能夠與本身匹配的, 若是有就調用connect函數來鏈接彼此.

下邊以evdev.c爲例來講明軟硬件兩部分是如何創建鏈接的:

evdev_connect()
         evdev->handle.dev = input_get_device(dev);
         evdev->handle.handler = handler;

在evdev.c中又建立了一個handle結構體他分別指向device和handler, 這樣軟硬件兩邊經過這個結構體找到對方.

 

Am335x的sdk6中觸摸屏的驅動文件

一 arch/arm/mach-omap2/board-com335x.c        板級初始化

static struct tsc_data am335x_touchscreen_data  = {
         .wires  = 4,                            //4線觸摸屏
         .x_plate_resistance = 200,     //阻抗200歐姆
         .steps_to_configure = 5,        //在產生中斷以前在fifo中的樣本個數, 最大16
};

二 drivers/input/touchscreen/ti_tsc.c         驅動文件

ti_tsc_init
         platform_driver_register (&ti_tsc_driver);
tscadc_probe
         input_allocate_device  //分配

request_irq
         input_dev->name = "ti-tsc";  //設置
         input_dev->dev.parent = &pdev->dev;
         input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);//能夠產生按鍵類事件/絕對位移類事件
         input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);//觸摸屏觸摸屏事件
         input_register_device//註冊

中斷處理函數

tscadc_interrupt
         tscadc_readl 讀取中斷狀態寄存器, adc與tsc共用一箇中斷源
         判斷中斷緣由而後上報事件
         input_report_abs(input_dev, ABS_X, val_x);//x座標
         input_report_abs(input_dev, ABS_Y, val_y);//y座標
         input_report_abs(input_dev, ABS_PRESSURE, z);//壓感
         input_report_key(input_dev, BTN_TOUCH, 1);//按下/鬆開
         input_sync(input_dev);

         檢查是不是擡起中斷
         status = tscadc_readl(ts_dev, TSCADC_REG_RAWIRQSTATUS);
         if (status & TSCADC_IRQENB_PENUP)
             input_report_key(input_dev, BTN_TOUCH, 0);
             input_report_abs(input_dev, ABS_PRESSURE, 0);
             input_sync(input_dev);
相關文章
相關標籤/搜索