tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断

发布者:老卫最新更新时间:2022-04-21 来源: eefocus关键字:tiny4412  移植linux  设备树  GPIO中断 手机看文章 扫描二维码
随时随地手机看文章

硬件平台: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)

    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、完整的设备树文件:

Device Tree有自己的独立的语法,它的源文件为.dts,编译后得到.dtb,Bootloader在引导Linux内核的时候会将.dtb地址告知内核。之后内核会展开Device Tree并创建和注册相关的设备,因此arch/arm/mach-xxx和arch/arm/plat-xxx中大量的用于注册platform、I2C、SPI板级信息的代码被删除,而驱动也以新的方式和.dts中定义的设备结点进行匹配。

/*

 * FriendlyARM's Exynos4412 based TINY4412 board device tree source

 *

 * Copyright (c) 2013 Alex Ling

 *

 * 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

 

/ {  //root结点"/"

model = "FriendlyARM TINY4412 board based on Exynos4412";

//root结点"/"的属性compatible,组织形式为:,

//Linux内核透过root结点"/"的compatible 属性即可判断它启动的是什么machine

//compatible 属性是一个字符串的列表,列表中的第一个字符串表征了结点代表的确切设备,

//形式为",",其后的字符串表征可兼容的其他设备。

//可以说前面的是特指,后面的则涵盖更广的范围。

compatible = "friendlyarm,tiny4412", "samsung,exynos4412", "samsung,exynos4";

 

  //以下开始为子节点

//子结点的命名,它们遵循的组织形式为:[@],

//<>中的内容是必选项,[]中的则为可选项。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

#include

#include

#include

#include

#include

#include

 

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: %dn", __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 %dn",

                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 %dn",

                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 %dn",

                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", },

[1] [2]
关键字:tiny4412  移植linux  设备树  GPIO中断 引用地址:tiny4412学习(四)之移植linux-设备树(1)设备树基础知识及GPIO中断

上一篇:ARM9时钟体系结构
下一篇:tiny4412学习(二)之移植linux-4.x支持设备树

推荐阅读最新更新时间:2024-11-11 05:43

Tiny4412之按键驱动
  一:按键驱动   按键驱动跟之前的LED,蜂鸣器的方法类似;通过底板,核心板我们可以看到按键的电路图:    通过电路图我们可以看出,当按键按下去为低电平,松开为高电平;所以我们要检测XEINT26的状态,通过芯片手册找到GPX3_2的说明; 有芯片手册可知:GPX3CON为0为检测,GPAC3DAT为1是高电平下面贴出代码:按键KEY1,KEY2,KEY3分别控制输出字符串,KEY4控制退出: #define GPX3CON (*(volatile unsigned long *)0x11000c60) #define GPX3DAT (*(volatile unsigned long *)0x11000c6
[单片机]
<font color='red'>Tiny4412</font>之按键驱动
基于3c2410的linux2.6.22移植(3)
4、 生成第一阶段gcc: $root@host:/home/arm/build-tools/# tar xvjf gcc-4.2.1.tar.bz2 打补丁: $root@host:/home/arm/build-tools/# cd gcc-4.2.1 $root@host:/home/arm/build-tools/gcc-4.2.1# patch Np1 i /home/arm/build-tools/patch/gcc-4.2.1-* $root@host:/home/arm/build-tools/ gcc-4.2.1# cd .. $root@host:/home/arm/build-tools/# cd
[单片机]
实操经验分享——在STM32上移植Linux
刚从硬件跳槽为嵌软时,没有任何一丝的准备。一入职,领导就交代了一项特难的任务——在stm32上移植linux! 瞬间我就懵了,没办法硬着头皮上吧,先搜集资料,我之前跑的是ok6410的板子上运行的linux,现在是在stm32上移植,以前stm32倒是玩过,研究生期间就捣鼓过它,但现在还没从抓烙铁的硬件当中缓过神来,就转到嵌入式软件的开发,更头疼的是stm32没有MMU!没有MMU!找了一下,好吧,有个uClinux! 于是开始学习各种相关的知识,了解到linux的启动一般是u-boot——》liunx内核——》根文件系统,那么首先要做个基于stm32的u-boot,先初始化时钟、外设、中断什么的,看了韦东山老师的视频感觉
[单片机]
linux-2.6.32在mini2440开发板上移植-W35型LCD驱动移植
编者注:本移植主要步骤还是按照手册来,里面讲解了一些有用的基础知识。但书册上提供了集中屏幕的方案,我们这里主要就用一种,也就是开发板自带的W35型号。液晶驱动的源程序在src/drivers/video/目录下,主要是s3c2410fb.c这几个文件,详细的讲解可以参照《linux设备驱动开发详解》一书。对于这里的移植,一般是实现为platform形式,所以,对platform_device这个结构体,把我准确一般就可以了。移植期间遇到的一个问题,一直没搞通。移植好后,烧尽板子,发现没正常运行。尝试了整整一下午,也不行。难道把drives/video/下的哪个驱动给改了?differ一下,发现没。match-mini2440.c这
[单片机]
Tiny4412裸机程序,时钟操作
其实,Exynos 4412的IROM代码已经设置了PLL,我们可以通过串口把IROM设置的PLL寄存器值打印出来,这些值打印出来是这样的(摘自韦东山老师的《嵌入式Linux系统开发完全手册_基于4412__上册》): CLK_SRC_CPU = 0x01000001 CLK_DIV_DMC0 = 0x00111713 CLK_DIV_DMC1 = 0x01011171 CLK_SRC_TOP0 = 0x01110000 CLK_SRC_TOP1 = 0x00001000 CLK_DIV_TOP = 0x00015470 CLK_SRC_LEFTBUS = 0x00000001 CLK_DIV_LEFTBUS = 0x0000
[单片机]
<font color='red'>Tiny4412</font>裸机程序,时钟操作
linux-2.6.32在mini2440开发板上移植(17)之按键驱动程序移植
编者:按键驱动程序涉及到linux中断程序的编写。 1、按键原理图。 2、驱动程序的编写移植。 在/linux-2.6.32.2/drivers/char/目录下创建一个新的驱动程序文件mini2440_buttons.c,内容及详细注释如下: #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/poll.h #include linux/irq.h #include asm/irq.h #incl
[单片机]
第十二章、Tiny4412 U-BOOT移植十二 DDR3初始化顺序
现在网上很难搜到Exynos4412的源码,基本上我没有找到任何资料有过分析DDR3的内存初始化代码的。在看U-Boot的这段代码时,也徘徊了很久,不知道如下手,很多文章或资料都将这一段分析过程有意无意的隐藏掉了,最多也只是提一下说参考裸板的代码,在找不到任何资料的情况下,我只能依靠芯片手册上,三星在内存控制器这一章,写的关于DDR3的初始化顺序的21个步骤来一条一条去读去看,在安静下来看了芯片手册以后,我发现三星给的U-Boot的DDR初始化代码和芯片手册上的初始化步骤完全一致,有的时候,最好的资料其实就在手边,只是我一直在想着找捷径,学习哪有那么多捷径? 好好研读手册吧,第18章中有下面一段关于初始化的说明: 图12-
[单片机]
第十二章、<font color='red'>Tiny4412</font> U-BOOT<font color='red'>移植</font>十二 DDR3初始化顺序
让TQ2440也用上设备(2)
一、下载 前几天我把之前在Linux4.9上的改动在Linux-4.10.17上重新做了一下,改正了一些问题,下面是下载方法: git clone https://github.com/pengdonglin137/linux-4.10.17.git -b tq2440_dt 二、配置工具链 关于这部分请参考博客移植Python3到TQ2440(一) 三、编译 1、配置 make ARCH=arm CROSS_COMPILE=arm-linux- tq2440_dt_defconfig 2、编译内核 make ARCH=arm CROSS_COMPILE=arm-linux- uImage -j4 3、
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved