linux驅動開發—基於Device tree機制的驅動編寫__linux

來源:互聯網
上載者:User
前言

Device Tree是一種用來描述硬體的資料結構,類似板級描述語言,起源於OpenFirmware(OF)。在目前廣泛使用的Linux kernel 2.6.x版本中,對於不同平台、不同硬體,往往存在著大量的不同的、移植性差的板級描述代碼,以達到對這些不同平台和不同硬體特殊適配的需求。但是過多的平台、過的的不同硬體導致了這樣的代碼越來越多,最終引發了Linux創始人Linus的不滿,以及強烈呼籲改變。Device Tree的引入給驅動適配帶來了很大的方便,一套完整的Device Tree可以將一個PCB擺在你眼前。Device Tree可以描述CPU,可以描述時鐘、中斷控制器、IO控制器、SPI匯流排控制器、I2C控制器、存放裝置等任何現有驅動單位。對具體器件能夠描述到使用哪個中斷,記憶體映射空間是多少等等。

關於Device Tree的資料結構和詳細使用方法,請大家查看宋寶華老師的一篇部落格:

http://blog.csdn.net/airk000/article/details/2 1 基於Device Tree機制核心的驅動開發—執行個體講解

這個章節,作者來講講基於Linux-3.2.X之後使用device tree機制的核心的驅動開發案例。本文的驅動開發案例是作者工作期間親自寫的鍵盤驅動代碼。CPU平台使用的是NXP(freescale)的i.MX6ul。概要資訊描述如下:

            硬體平台:NXP(freescale)—i.MX6ul

            軟體開發平台:Ubuntu-12.04

           核心版本:Linux-3.14.38

            編譯環境:yocto project 1.1 基於Device Tree機制的驅動開發—系統如何載入和解析dtb檔案

基於Device Tree機制的驅動開發,在驅動當中所使用到的硬體資源都在對應的CPU平台的dts檔案上進行配置,然後編譯產生dtb檔案,放在u-boot分區之後,核心分區之前。這裡順便講一下,核心是如何解析dtb檔案的。其大致過程如下:

系統上電啟動之後,u-boot載入dtb,通過u-boot和Linux核心之間的傳參操作將dtb檔案傳給核心,然後核心解析dtb檔案,根據device tree中的配置(dtb檔案)去初始化裝置的CPU管腳、各個外設的狀態。device tree中的配置主要是起到了初始化硬體資源的作用,後期可以在驅動中修改裝置的硬體資源的狀態,比如在device tree中初始化某個GPIO的管腳為上拉狀態,可以在驅動載入之後修改這個管腳的狀態。 1.2 基於Device Tree機制的驅動開發—dts檔案的配置和編譯

本節開始以具體的驅動例子講解如何在驅動開發中配置dts檔案。這裡使用i.MX6ul平台下的矩陣鍵盤驅動中使用到的幾個GPIO口講解如何配置dts檔案和編譯。本次講解案例用於編譯驅動的核心是Linux-3.14.38。首先我們先來看看如何在核心中找到自己相應CPU平台的dts檔案:

1.dts檔案位於核心的arch/arm/boot/dts/$(board).dts,其中的$(board)指的是對應的CPU平台,比如i.MX6ul平台的dts檔案如下:

imx6ul/linux-3.14.38-v2$ vim arch/arm/boot/dts/imx6ul-14x14-evk.dts(部分內容)

#include <dt-bindings/input/input.h>#include "imx6ul.dtsi"/ {model = "Freescale i.MX6 UltraLite NewLand Board";compatible = "fsl,imx6ul-14x14-evk", "fsl,imx6ul";chosen {stdout-path = &uart1;};memory {reg = <0x80000000 0x20000000>;};pxp_v4l2 {compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";status = "okay";};keyboard {              compatible = "max-keypad";              pinctrl-names = "default";              pinctrl-0 = <&pinctrl_keypad>;              in-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>,      //key_in0                         <&gpio2 4 GPIO_ACTIVE_HIGH>,      //key_in1                         <&gpio2 5 GPIO_ACTIVE_HIGH>;      //key_in2              out-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>,    //key_out0                          <&gpio2 2 GPIO_ACTIVE_HIGH>,    //key_out1                          <&gpio2 7 GPIO_ACTIVE_HIGH>,    //key_out2                          <&gpio4 25 GPIO_ACTIVE_HIGH>,   //key_out3                          <&gpio4 26 GPIO_ACTIVE_HIGH>;   //key_out4                          status = "okay";          };};&cpu0 {arm-supply = <&reg_arm>;soc-supply = <&reg_soc>;};&clks {assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;assigned-clock-rates = <786432000>;};&tsc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_tsc>;status = "okay";xnur-gpio = <&gpio1 3 0>;measure_delay_time = <0xffff>;pre_charge_time = <0xfff>;};&gpmi {pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpmi_nand_1>;status = "okay";nand-on-flash-bbt;};&lcdif {pinctrl-names = "default";pinctrl-0 = <&pinctrl_lcdif_dat     &pinctrl_lcdif_ctrl>;    lcd_reset = <&gpio3 14 GPIO_ACTIVE_HIGH>;display = <&display0>;status = "okay";display0: display {bits-per-pixel = <16>;bus-width = <8>;display-timings {native-mode = <&timing0>;timing0: timing0 {clock-frequency = <9200000>;hactive = <240>;vactive = <320>;hfront-porch = <8>;hback-porch = <4>;hsync-len = <41>;vback-porch = <2>;vfront-porch = <4>;vsync-len = <10>;hsync-active = <0>;vsync-active = <0>;de-active = <1>;pixelclk-active = <0>;};};};};&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart1>;imx6ul-evk {pinctrl_uart1: uart1grp {fsl,pins = <MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1>;};pinctrl_tsc: tscgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO01__GPIO1_IO010xb0MX6UL_PAD_GPIO1_IO02__GPIO1_IO020xb0MX6UL_PAD_GPIO1_IO03__GPIO1_IO030xb0MX6UL_PAD_GPIO1_IO04__GPIO1_IO040xb0>;};pinctrl_lcdif_dat: lcdifdatgrp {fsl,pins = <MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79>;};pinctrl_lcdif_ctrl: lcdifctrlgrp {fsl,pins = <MX6UL_PAD_LCD_CLK__LCDIF_WR_RWN    0x79MX6UL_PAD_LCD_ENABLE__LCDIF_RD_E    0x79MX6UL_PAD_LCD_HSYNC__LCDIF_RS       0x79MX6UL_PAD_LCD_RESET__LCDIF_CS       0x79/* used for lcd reset */MX6UL_PAD_LCD_DATA09__GPIO3_IO14    0x79>;};pinctrl_keypad: keypadgrp {             fsl,pins = <                MX6UL_PAD_ENET1_RX_EN__GPIO2_IO02       0x70a0                MX6UL_PAD_ENET1_TX_DATA0__GPIO2_IO03    0x70a0                MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04    0x70a0                MX6UL_PAD_ENET1_TX_EN__GPIO2_IO05       0x70a0                MX6UL_PAD_ENET1_TX_CLK__GPIO2_IO06      0x70a0                MX6UL_PAD_ENET1_RX_ER__GPIO2_IO07       0x70a0                MX6UL_PAD_CSI_DATA04__GPIO4_IO25        0x70a0                MX6UL_PAD_CSI_DATA05__GPIO4_IO26        0x70a0            >;     };pinctrl_gpmi_nand_1: gpmi-nand-1 {fsl,pins = <MX6UL_PAD_NAND_CLE__RAWNAND_CLE         0xb0b1MX6UL_PAD_NAND_ALE__RAWNAND_ALE         0xb0b1MX6UL_PAD_NAND_WP_B__RAWNAND_WP_B       0xb0b1MX6UL_PAD_NAND_READY_B__RAWNAND_READY_B 0xb000MX6UL_PAD_NAND_CE0_B__RAWNAND_CE0_B     0xb0b1MX6UL_PAD_NAND_CE1_B__RAWNAND_CE1_B     0xb0b1MX6UL_PAD_NAND_RE_B__RAWNAND_RE_B       0xb0b1MX6UL_PAD_NAND_WE_B__RAWNAND_WE_B       0xb0b1MX6UL_PAD_NAND_DATA00__RAWNAND_DATA00   0xb0b1MX6UL_PAD_NAND_DATA01__RAWNAND_DATA01   0xb0b1MX6UL_PAD_NAND_DATA02__RAWNAND_DATA02   0xb0b1MX6UL_PAD_NAND_DATA03__RAWNAND_DATA03   0xb0b1MX6UL_PAD_NAND_DATA04__RAWNAND_DATA04   0xb0b1MX6UL_PAD_NAND_DATA05__RAWNAND_DATA05   0xb0b1MX6UL_PAD_NAND_DATA06__RAWNAND_DATA06   0xb0b1MX6UL_PAD_NAND_DATA07__RAWNAND_DATA07   0xb0b1>;};};};

2.根據自己的開發需求配置dts檔案,本文矩陣鍵盤驅動所使用到的GPIO管腳資源為:gpio2-2、gpio2-3、gpio2-4、gpio2-5、gpio2-6、gpio2-7、gpio4-25、gpio4-26。dts檔案配置如下:

~/yangfile/imx6ul/linux-3.14.38-v2$ vim arch/arm/boot/dts/imx6ul-newland.dts

2.1 在dts檔案中添加一個裝置節點,比如我們是矩陣鍵盤驅動,那麼就添加一個名為”keyboard“的裝置節點;

2.2 compatible屬性用於of_find_node_compatible函數擷取裝置節點用的,這個函數的通過”max-keypad“字串去遍曆device tree,尋找匹配的裝置節點;

2.3 pinctrl-0 = <&pinctrl_keypad>主要用於說明裝置硬體資源在哪裡擷取,比如這裡就是到iomuxc裡面去擷取IO資源

2.4 iomuxc裝置節點裡面定義了CPU所有的IO資源,包括每個IO口的初始化狀態都定義好了,比如:MX6UL_PAD_ENET1_RX_EN_GPIO2_IO02  0x70a0,這裡的MX6UL_PAD_ENET1_RX_EN_GPIO2_IO02宏表示的是GPIO2-2這個IO口的寄存器組(IO複用寄存器、IO方向控制寄存器、IO輸入輸出值設定寄存器),0x70a0這個值根據自己的驅動開發需求,查閱CPU手冊定義,不唯一。

keyboard {    compatible = "max-keypad";    pinctrl-names = "default";//這個設定成預設default就可以了,沒什麼特別要求    pinctrl-0 = <&pinctrl_keypad>;//到iomuxc裡面去擷取相應IO資源的初始化狀態    in-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>,      //“in-gpios”字串可以自己隨便定義,主要是為了擷取gpio資源的時候匹配用的               <&gpio2 4 GPIO_ACTIVE_HIGH>,      //GPIO_ACTIVE_HIGH:邏輯高電平有效               <&gpio2 5 GPIO_ACTIVE_HIGH>;      //key_in2    out-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>,    //“out<span style="font-family: Arial, Helvetica, sans-serif;">-gpios”字串可以自己隨便定義,主要是為了擷取gpio資源的時候匹配用的</span>                <&gpio2 2 GPIO_ACTIVE_HIGH>,    //key_out1                <&gpio2 7 GPIO_ACTIVE_HIGH>,    //key_out2                <&gpio4 25 GPIO_ACTIVE_HIGH>,   //key_out3                <&gpio4 26 GPIO_ACTIVE_HIGH>;   //key_out4                status = "okay";//使能要使用的gpio資源    };};
&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart1>;。。。。。。。。pinctrl_keypad: keypadgrp {             fsl,pins = <                MX6UL_PAD_ENET1_RX_EN__GPIO2_IO02       0x70a0                MX6UL_PAD_ENET1_TX_DATA0__GPIO2_IO03    0x70a0                MX6UL_PAD_ENET1_TX_DATA1__GPIO2_IO04    0x70a0                MX6UL_PAD_ENET1_TX_EN__GPIO2_IO05       0x70a0                MX6UL_PAD_ENET1_TX_CLK__GPIO2_IO06      0x70a0                MX6UL_PAD_ENET1_RX_ER__GPIO2_IO07       0x70a0                MX6UL_PAD_CSI_DATA04__GPIO4_IO25        0x70a0                MX6UL_PAD_CSI_DATA05__GPIO4_IO26        0x70a0            >;     };


3.編譯dts檔案,在核心根目錄下執行以下命令:

~/yangfile/imx6ul/linux-3.14.38-v2$ make ARCH=arm CROSS_COMPILE=arm-linux-gcc imx6ul-newland.dtb

(這裡的arm-Linux-gcc只是個代表交叉編譯器的標識,具體的根據實際情況而定)

4.將配置、編譯後的dtb檔案燒錄到裝置flash(或者SD卡)的dtb分區中。

2 驅動代碼中如何註冊dts檔案中的裝置 接觸了device tree機制的驅動開發後,其實device tree機制就是Linux-2.6.x中的platform 匯流排機制的最佳化版本。OK,我們來說說基於device tree機制的驅動開發中註冊裝置的過程,這裡以我寫的矩陣鍵盤驅動代碼的裝置註冊過程為例: 1.在probe函數中調用of_get_**或者of_find_**函數從dtb中擷取裝置資源:

static int max_keypad_probe(struct platform_device *pdev){    int i,ret;    struct device *dev;     struct device_node *dev_node = NULL;       //add by zengxiany        dev = &pdev->dev;    。。。。。。    //省略部分代碼    dev_node = of_find_compatible_node(NULL,NULL,"fsl,imx6ul-gpio");    if(!of_device_is_compatible(dev_node,"fsl,imx6ul-gpio"))    {        printk("get keypad device node error!\n");        return -EINVAL;    }    dev_node = of_find_compatible_node(dev_node,NULL,"max-keypad");    if(!of_device_is_compatible(dev_node,"max-keypad"))    {        printk("failure to find max-keypad device node!\n");        return -EINVAL;    }    for(i=0; i< KEYPAD_ROWS; i++)    {        gpio_map_rowkey[i] = of_get_named_gpio(dev_node,"in-gpios",i);set_key_input(gpio_map_rowkey[i]);    }for(i=0; i< KEYPAD_COLS; i++)    {        gpio_map_colkey0[i] = of_get_named_gpio(dev_node,"out-gpios",i);set_key_input(gpio_map_colkey0[i]);}}
2.在init函數中註冊裝置:
//add by zengxiany for platform device registerstatic struct of_device_id max_keypad_of_match[] = {{ .compatible = "max-keypad", },{ },};static struct platform_driver max_keypad_device_driver = {.probe= max_keypad_probe,.remove= max_keypad_remove,.driver= {.name= "max-keypad",.owner= THIS_MODULE,.of_match_table = of_match_ptr(max_keypad_of_match),}};
static int __init keypad_module_init(void){int ret;ret = platform_driver_register(&max_keypad_device_driver);//modify by zengxianyif(ret < 0){printk("max_keypad_device driver init error!\n");return -ENODEV;}    return 0;}static void __exit keypad_module_exit(void){platform_driver_unregister(&max_keypad_device_driver);}
OK,這樣就完成了裝置的註冊。





 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.