zoukankan      html  css  js  c++  java
  • tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断【转】

    本文转载自:http://blog.csdn.net/fengyuwuzu0519/article/details/74177978

     

    目录(?)[+]

     
    • 硬件平台:tiny4412
    • 系统:linux-4.4
    • 文件系统:busybox-1.25
    • 编译器: arm-none-linux-gnueabi-gcc(gcc version 4.8.3 20140320)
    • uboot:友善自带uboot.

    一、DTS引入

    1.什么是DTS?为什么要引入DTS?

    DTS即Device Tree Source设备树源码,DeviceTree是一种描述硬件的数据结构,它起源于OpenFirmware (OF)。

    在Linux2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,比如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data,这些板级细节代码对内核来讲只不过是垃圾代码。而采用DeviceTree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。   

    2.ARM平台的相关code做出如下相关规范调整

    •ARM的核心代码仍然保存在arch/arm目录下
    •ARM SoC corearchitecture code保存在arch/arm目录下
    •ARMSOC的周边外设模块的驱动保存在drivers目录下
    •ARMSOC的特定代码在arch/arm/mach-xxx目录下
    •ARM SOCboard specific的代码被移除,由DeviceTree机制来负责传递硬件拓扑和硬件资源信息。

    本质上,Device Tree改变了原来用hardcode方式将HW配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。

    3.DTS的加载过程

    如果要使用DeviceTree,首先用户要了解自己的硬件配置和系统运行参数,并把这些信息组织成DeviceTree source file。通过DTC(DeviceTree Compiler),可以将这些适合人类阅读的DeviceTree source file变成适合机器处理的DeviceTree binary file(DTB,devicetree blob)。在系统启动的时候,bootprogram(例如:firmware、bootloader)可以将保存在flash中的DTB copy到内存(当然也可以通过其他方式,例如可以通过bootloader的交互式命令加载DTB),并把DTB的起始地址传递给OSkernel。对于计算机系统(computersystem),一般是firmware->bootloader->OS,对于嵌入式系统,一般是bootloader->OS。

    4.DTS的描述信息

    Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在DeviceTree中,可描述的信息包括(原先这些信息大多被hardcode到kernel中):

    •CPU的数量和类别
    •内存基地址和大小
    •总线和桥
    •外设连接
    •中断控制器和中断使用情况
    •GPIO控制器和GPIO使用情况
    •Clock控制器和Clock使用情况

      它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

    一个.dts文件对应一个ARM的machine,一般放置在内核的arch/arm/boot/dts/目录。由于一个SoC可能对应多个machine(一个SoC可以对应多个产品和电路板),势必这些.dts文件需包含许多共同的部分,Linux内核为了简化,把SoC公用的部分或者多个machine共同的部分一般提炼为.dtsi。所有的ARMSoC的.dtsi都引用了skeleton.dtsi,即#include"skeleton.dtsi“或者 /include/ "skeleton.dtsi"

    5.变化

    platform之前:

    现在:

    二、设备树文件

    1、修改设备树文件支持GPIO按键中断

    (/work/linux-4.4.0/linux-4.4/arch/arm/boot/dts/exynos4412-tiny4412.dts)
    [cpp] view plain copy
     
     print?
    1. interrupt_demo: interrupt_demo {  
    2.         compatible         = "tiny4412,interrupt_demo";  
    3.         tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;  
    4.         tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;  
    5.         tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;  
    6.         tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;  
    7. };  

    2、完整的设备树文件:

    Device Tree有自己的独立的语法,它的源文件为.dts,编译后得到.dtb,Bootloader在引导Linux内核的时候会将.dtb地址告知内核。之后内核会展开Device Tree并创建和注册相关的设备,因此arch/arm/mach-xxx和arch/arm/plat-xxx中大量的用于注册platform、I2C、SPI板级信息的代码被删除,而驱动也以新的方式和.dts中定义的设备结点进行匹配。
    [cpp] view plain copy
     
     print?
    1. /* 
    2.  * FriendlyARM's Exynos4412 based TINY4412 board device tree source 
    3.  * 
    4.  * Copyright (c) 2013 Alex Ling <kasimling@gmail.com> 
    5.  * 
    6.  * Device tree source file for FriendlyARM's TINY4412 board which is based on 
    7.  * Samsung's Exynos4412 SoC. 
    8.  * 
    9.  * This program is free software; you can redistribute it and/or modify 
    10.  * it under the terms of the GNU General Public License version 2 as 
    11.  * published by the Free Software Foundation. 
    12. */  
    13.   
    14. /dts-v1/;  
    15. #include "exynos4412.dtsi"  
    16. #include <dt-bindings/gpio/gpio.h>  
    17.   
    18. / {  //root结点"/"  
    19.     model = "FriendlyARM TINY4412 board based on Exynos4412";  
    20.     //root结点"/"的属性compatible,组织形式为:<manufacturer>,<model>  
    21.     //Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine  
    22.     //compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,  
    23.     //形式为"<manufacturer>,<model>",其后的字符串表征可兼容的其他设备。  
    24.     //可以说前面的是特指,后面的则涵盖更广的范围。  
    25.     compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";  
    26.   
    27.   //以下开始为子节点  
    28.     //子结点的命名,它们遵循的组织形式为:<name>[@<unit-address>],  
    29.     //<>中的内容是必选项,[]中的则为可选项。name是一个ASCII字符串,用于描述结点对应的设备类型,如memory;  
    30.     //多个相同类型设备结点的name可以一样,只要unit-address不同即可  
    31.       
    32.     //chosen节点并不代表一个真正的设备,而是用来在Firmware与操作系统间传递数据,如启动参数。  
    33.     chosen {                         //子结点"chosen"  
    34.         stdout-path = &serial_0;  
    35.         bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init=/linuxrc earlyprintk";  
    36.     };  
    37.   
    38.     memory {                         //子结点"memory"  
    39.         reg = <0x40000000 0x40000000>;  
    40.     };  
    41.   
    42.     leds {                           //子结点"leds"  
    43.         compatible = "gpio-leds";  
    44.   
    45.         led1 {                         //子子结点"led1"  
    46.             label = "led1";  
    47.             gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;  
    48.             default-state = "off";  
    49.             linux,default-trigger = "heartbeat";  
    50.         };  
    51.   
    52.         led2 {  
    53.             label = "led2";  
    54.             gpios = <&gpm4 1 GPIO_ACTIVE_LOW>;  
    55.             default-state = "off";  
    56.         };  
    57.   
    58.         led3 {  
    59.             label = "led3";  
    60.             gpios = <&gpm4 2 GPIO_ACTIVE_LOW>;  
    61.             default-state = "off";  
    62.         };  
    63.   
    64.         led4 {  
    65.             label = "led4";  
    66.             gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;  
    67.             default-state = "off";  
    68.             linux,default-trigger = "mmc0";  
    69.         };  
    70.     };  
    71.   
    72.     fixed-rate-clocks {  
    73.         xxti {  
    74.             compatible = "samsung,clock-xxti";  
    75.             clock-frequency = <0>;  
    76.         };  
    77.   
    78.         xusbxti {  
    79.             compatible = "samsung,clock-xusbxti";  
    80.             clock-frequency = <24000000>;  
    81.         };  
    82.     };  
    83.     interrupt_demo: interrupt_demo {  
    84.      compatible         = "tiny4412,interrupt_demo";  
    85.      tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;  
    86.      tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;  
    87.      tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;  
    88.      tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;  
    89.     };  
    90. };  
    91.   
    92. &rtc {  
    93.     status = "okay";  
    94. };  
    95.   
    96. &sdhci_2 {  
    97.     bus-width = <4>;  
    98.     pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;  
    99.     pinctrl-names = "default";  
    100.     #status = "okay";     
    101.     status = "disabled";  
    102. };  
    103.   
    104. &serial_0 {  
    105.     status = "okay";  
    106. };  
    107.   
    108. &serial_1 {  
    109.     status = "okay";  
    110. };  
    111.   
    112. &serial_2 {  
    113.     status = "okay";  
    114. };  
    115.   
    116. &serial_3 {  
    117.     status = "okay";  
    118. };  


    三、设备树驱动

    设备树引来的驱动变化
    [cpp] view plain copy
     
     print?
    1. #include <linux/init.h>  
    2. #include <linux/module.h>  
    3. #include <linux/platform_device.h>  
    4. #include <linux/gpio.h>  
    5. #include <linux/of.h>  
    6. #include <linux/of_gpio.h>  
    7. #include <linux/interrupt.h>  
    8.   
    9. typedef struct   
    10. {  
    11.     int gpio;  
    12.     int irq;  
    13.     char name[20];  
    14. }int_demo_data_t;  
    15.   
    16. static irqreturn_t int_demo_isr(int irq, void *dev_id)  
    17. {  
    18.     int_demo_data_t *data = dev_id;  
    19.   
    20.     printk("%s enter, %s: gpio:%d, irq: %d ", __func__, data->name, data->gpio, data->irq);  
    21.   
    22.     return IRQ_HANDLED;  
    23. }  
    24.   
    25. static int int_demo_probe(struct platform_device *pdev) {  
    26.     struct device *dev = &pdev->dev;  
    27.     int irq_gpio = -1;  
    28.     int irq = -1;  
    29.     int ret = 0;  
    30.     int i = 0;  
    31.     int_demo_data_t *data = NULL;  
    32.   
    33.     printk("%s enter. ", __func__);  
    34.   
    35.     if (!dev->of_node) {  
    36.         dev_err(dev, "no platform data. ");  
    37.         goto err1;  
    38.     }  
    39.   
    40.     data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL);  
    41.     if (!data) {  
    42.         dev_err(dev, "no memory. ");  
    43.         goto err0;  
    44.     }  
    45.   
    46. #if 1  
    47.     for (i = 3; i >= 0; i--) {  
    48.         sprintf(data[i].name, "tiny4412,int_gpio%d", i+1);  
    49. #else  
    50.     for (i = 0; i < 4; i++) {  
    51. #endif  
    52.         irq_gpio = of_get_named_gpio(dev->of_node, data[i].name, 0);//通过名字获取gpio  
    53.         if (irq_gpio < 0) {  
    54.             dev_err(dev, "Looking up %s property in node %s failed %d ",  
    55.                 data[i].name, dev->of_node->full_name, irq_gpio);  
    56.             goto err1;  
    57.         }  
    58.   
    59.         data[i].gpio = irq_gpio;  
    60.   
    61.         irq = gpio_to_irq(irq_gpio);    //将gpio转换成对应的中断号  
    62.         if (irq < 0) {  
    63.             dev_err(dev,  
    64.                 "Unable to get irq number for GPIO %d, error %d ",  
    65.                 irq_gpio, irq);  
    66.             goto err1;  
    67.         }  
    68.   
    69.         data[i].irq = irq;  
    70.   
    71.         printk("%s: gpio: %d ---> irq (%d) ", __func__, irq_gpio, irq);  
    72.     //注册中断  
    73.         ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i);  
    74.         if (ret < 0) {  
    75.             dev_err(dev, "Unable to claim irq %d; error %d ",  
    76.                 irq, ret);  
    77.             goto err1;  
    78.         }  
    79.     }  
    80.   
    81.     return 0;  
    82.   
    83. err1:  
    84.     devm_kfree(dev, data);  
    85. err0:  
    86.     return -EINVAL;  
    87. }  
    88.   
    89. static int int_demo_remove(struct platform_device *pdev) {  
    90.   
    91.     printk("%s enter. ", __func__);  
    92.   
    93.     return 0;  
    94. }  
    95.   
    96. static const struct of_device_id int_demo_dt_ids[] = {  
    97.     { .compatible = "tiny4412,interrupt_demo", },  
    98.     {},  
    99. };  
    100.   
    101. MODULE_DEVICE_TABLE(of, int_demo_dt_ids);  
    102.   
    103. static struct platform_driver int_demo_driver = {  
    104.     .driver        = {  
    105.         .name      = "interrupt_demo",  
    106.         .of_match_table    = of_match_ptr(int_demo_dt_ids),  
    107.     },  
    108.     .probe         = int_demo_probe,  
    109.     .remove        = int_demo_remove,  
    110. };  
    111.   
    112. static int __init int_demo_init(void)  
    113. {  
    114.     int ret;  
    115.   
    116.     ret = platform_driver_register(&int_demo_driver);  
    117.     if (ret)  
    118.         printk(KERN_ERR "int demo: probe failed: %d ", ret);  
    119.   
    120.     return ret;  
    121. }  
    122. module_init(int_demo_init);  
    123.   
    124. static void __exit int_demo_exit(void)  
    125. {  
    126.     platform_driver_unregister(&int_demo_driver);  
    127. }  
    128. module_exit(int_demo_exit);  
    129.   
    130. MODULE_LICENSE("GPL");  

    编译驱动

    [cpp] view plain copy
     
     print?
    1. KERN_DIR = /work/system/linux-3.4.2  
    2.   
    3. all:  
    4.     make -C $(KERN_DIR) M=`pwd` modules   
    5.   
    6. clean:  
    7.     make -C $(KERN_DIR) M=`pwd` modules clean  
    8.     rm -rf modules.order  
    9.   
    10. obj-m   += mykey.o<span style="font-size:18px;">  
    11. </span>  

    采用了platform平台设备驱动的方式

    platform_driver_register(&int_demo_driver);-->

    .of_match_table    = of_match_ptr(int_demo_dt_ids),-->

    .probe         = int_demo_probe,-->

    of_get_named_gpio(dev->of_node, data[i].name, 0):将dev->of_node节点上的data[i].name的值取下。-->

    irq = gpio_to_irq(irq_gpio);    //将gpio转换成对应的中断号-->

    ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i);

    //注册中断-->

    中断发生-->

    执行中断处理函数int_demo_isr-->

    等待中断发生。

    四、下载测试

    #u-boot:
    setenv bootargs  'root=/dev/nfs  rw  nfsroot=192.168.1.123:/work/nfs/rootfs_for_tiny4412/rootfs ethmac=1C:6F:65:34:51:7E  ip=192.168.1.125:192.168.1.123:192.168.1.1:255.255.255.0::eth0:off console=ttySAC0,115200  init=/linuxrc'
    #u-boot:save
    #u-boot:dnw 0x40600000
    dnw arch/arm/boot/uImage
    #u-boot:dnw 0x42000000
    dnw  arch/arm/boot/dts/exynos4412-tiny4412.dtb
    bootm 0x40600000 - 0x42000000


    内核:
    git clone https://github.com/fengyuwuzu0519/linux4_forTiny4412.git
    文件系统:
    git clone https://github.com/fengyuwuzu0519/rootfs_forTiny4412
    文件系统git下了少东西,则创建如下:
    (mkdir dev  proc  sys  tmp  var    mknod  dev/console  c  5  1)
    uboot:
    git clone https://github.com/fengyuwuzu0519/u-boot_forTiny4412
    make distclean
    make tiny4412_config
    make
  • 相关阅读:
    解决点击状态栏时ScrollView自动滚动到初始位置失效办法
    如何设计用户、角色、权限表
    Subject的功能
    shiro授权的源码分析
    shiro之认证源码分析
    shiro配置
    JSONArray转JSONObject
    parameterType
    MyBatis:Parameter Maps collection does not contain value for 的问题解决
    mybatis报ORA-00911: 无效字符
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7249945.html
Copyright © 2011-2022 走看看