tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断
来源:互联网 发布:好看女装品牌推荐知乎 编辑:程序博客网 时间:2024/06/05 08:52
- 硬件平台: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做出如下相关规范调整
本质上,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.变化
现在:
二、设备树文件
1、修改设备树文件支持GPIO按键中断
interrupt_demo: interrupt_demo { compatible = "tiny4412,interrupt_demo"; tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>; };
2、完整的设备树文件:
/* * FriendlyARM's Exynos4412 based TINY4412 board device tree source * * Copyright (c) 2013 Alex Ling <kasimling@gmail.com> * * Device tree source file for FriendlyARM's TINY4412 board which is based on * Samsung's Exynos4412 SoC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation.*//dts-v1/;#include "exynos4412.dtsi"#include <dt-bindings/gpio/gpio.h>/ { //root结点"/"model = "FriendlyARM TINY4412 board based on Exynos4412";//root结点"/"的属性compatible,组织形式为:<manufacturer>,<model>//Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine//compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,//形式为"<manufacturer>,<model>",其后的字符串表征可兼容的其他设备。//可以说前面的是特指,后面的则涵盖更广的范围。compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4"; //以下开始为子节点//子结点的命名,它们遵循的组织形式为:<name>[@<unit-address>],//<>中的内容是必选项,[]中的则为可选项。name是一个ASCII字符串,用于描述结点对应的设备类型,如memory;//多个相同类型设备结点的name可以一样,只要unit-address不同即可//chosen节点并不代表一个真正的设备,而是用来在Firmware与操作系统间传递数据,如启动参数。chosen { //子结点"chosen"stdout-path = &serial_0;bootargs = "root=/dev/ram0 rw rootfstype=ext4 console=ttySAC0,115200 init=/linuxrc earlyprintk";};memory { //子结点"memory"reg = <0x40000000 0x40000000>;};leds { //子结点"leds"compatible = "gpio-leds";led1 { //子子结点"led1"label = "led1";gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;default-state = "off";linux,default-trigger = "heartbeat";};led2 {label = "led2";gpios = <&gpm4 1 GPIO_ACTIVE_LOW>;default-state = "off";};led3 {label = "led3";gpios = <&gpm4 2 GPIO_ACTIVE_LOW>;default-state = "off";};led4 {label = "led4";gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;default-state = "off";linux,default-trigger = "mmc0";};};fixed-rate-clocks {xxti {compatible = "samsung,clock-xxti";clock-frequency = <0>;};xusbxti {compatible = "samsung,clock-xusbxti";clock-frequency = <24000000>;};};interrupt_demo: interrupt_demo { compatible = "tiny4412,interrupt_demo"; tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>; tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>; };};&rtc {status = "okay";};&sdhci_2 {bus-width = <4>;pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;pinctrl-names = "default";#status = "okay";status = "disabled";};&serial_0 {status = "okay";};&serial_1 {status = "okay";};&serial_2 {status = "okay";};&serial_3 {status = "okay";};
三、设备树驱动
#include <linux/init.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/gpio.h>#include <linux/of.h>#include <linux/of_gpio.h>#include <linux/interrupt.h>typedef struct { int gpio; int irq; char name[20];}int_demo_data_t;static irqreturn_t int_demo_isr(int irq, void *dev_id){ int_demo_data_t *data = dev_id; printk("%s enter, %s: gpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq); return IRQ_HANDLED;}static int int_demo_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int irq_gpio = -1; int irq = -1; int ret = 0; int i = 0; int_demo_data_t *data = NULL; printk("%s enter.\n", __func__); if (!dev->of_node) { dev_err(dev, "no platform data.\n"); goto err1; } data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL); if (!data) { dev_err(dev, "no memory.\n"); goto err0; }#if 1 for (i = 3; i >= 0; i--) { sprintf(data[i].name, "tiny4412,int_gpio%d", i+1);#else for (i = 0; i < 4; i++) {#endif irq_gpio = of_get_named_gpio(dev->of_node, data[i].name, 0);//通过名字获取gpio if (irq_gpio < 0) { dev_err(dev, "Looking up %s property in node %s failed %d\n", data[i].name, dev->of_node->full_name, irq_gpio); goto err1; } data[i].gpio = irq_gpio; irq = gpio_to_irq(irq_gpio); //将gpio转换成对应的中断号 if (irq < 0) { dev_err(dev, "Unable to get irq number for GPIO %d, error %d\n", irq_gpio, irq); goto err1; } data[i].irq = irq; printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq); //注册中断 ret = devm_request_any_context_irq(dev, irq, int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i); if (ret < 0) { dev_err(dev, "Unable to claim irq %d; error %d\n", irq, ret); goto err1; } } return 0;err1: devm_kfree(dev, data);err0: return -EINVAL;}static int int_demo_remove(struct platform_device *pdev) { printk("%s enter.\n", __func__); return 0;}static const struct of_device_id int_demo_dt_ids[] = { { .compatible = "tiny4412,interrupt_demo", }, {},};MODULE_DEVICE_TABLE(of, int_demo_dt_ids);static struct platform_driver int_demo_driver = { .driver = { .name = "interrupt_demo", .of_match_table = of_match_ptr(int_demo_dt_ids), }, .probe = int_demo_probe, .remove = int_demo_remove,};static int __init int_demo_init(void){ int ret; ret = platform_driver_register(&int_demo_driver); if (ret) printk(KERN_ERR "int demo: probe failed: %d\n", ret); return ret;}module_init(int_demo_init);static void __exit int_demo_exit(void){ platform_driver_unregister(&int_demo_driver);}module_exit(int_demo_exit);MODULE_LICENSE("GPL");
编译驱动
KERN_DIR = /work/system/linux-3.4.2all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderobj-m+= mykey.o
采用了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
- tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断
- tiny4412学习(四)之移植linux-设备树(2)设备树之LED点灯
- 设备树学习之(一)GPIO中断
- 设备树学习之(一)GPIO中断
- 设备树学习之(一)GPIO中断
- tiny4412 设备树之按键中断(一)
- tiny4412学习(二)之移植linux-4.x支持设备树
- linux设备树之gpio
- 基于tiny4412的Linux内核移植 -- 设备树的展开
- 设备树学习之(四)ADC 又见中断
- 设备树学习之(四)ADC 又见中断
- 设备树学习之(四)ADC 又见中断
- linux设备树的gpio和gpio中断应用实例
- tiny4412 设备树之pinctrl(番外)
- tiny4412 设备树之i2c设备(二)
- tiny4412 设备树之LCD背光驱动(四)(待续)
- linux驱动:TI+DM8127+GPIO(四)之设备
- tiny4412 设备树之SD卡驱动(三)
- PAT甲级 1124. Raffle for Weibo Followers (20)
- 基于OpenStack+Docker设计与实现CI/CD——基于Docker技术的CI&CD实践
- stringstream
- CodeForces
- 宏定义中的# ## \ @#
- tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断
- 书写手机移动页面时的一些坑
- Git使用及安装
- jquery遍历table的tr获取td的值
- PHP 23种设计模式
- Spring Boot初探
- Javascript 严格模式详解
- HBuilder 的使用1
- JavaScript常用原生数组方法