05 - 设备树开发

//=================================================================================================================================
[1] >> 设备树基础知识
[
	0>>设备树由来
	[
	    在Linux2.6中,arch/arm/plat-xxx和arch/arm/mach-xxx(存放产品设备信息)中充斥着大量的垃圾代码
	    Linux开发社区就开始整改,借鉴PowerPC设备树
	]
	1>>FDT = Flattened device tree 展开设备树 --  /proc/device-tree/ 各个设备树节点 
	2>>OF = open firmware(固件) = 打开固件
	3>>DTSI = device tree source include 设备树源码头的文件
	4>>DTC =  device tree compiler  
	[
		1>>开源,源代码位于/script/dtc  #注意:在Linux内核使能了Device Tree的情况下,TDC才能被编译出来
		2>>DTS --> DTC --> DTB
		3>>编译DTC的步骤
		[
				1>>步骤1:在inux内核的ach/arm/boot/dts/Makefile中,选中EXYNOS的Soc被选中后CONFIG_ARCH_EXYNOS宏被置1
					[方法1举例]
					dtb-$(CONFIG_ARCH_EXYNOS)+ = exynos 4210-origen dtb 
					exynos 4412-fs4412.dtb 
					exynos 4210-trats.dtb
				2>>步骤2: 再Linux内核下make dtbs
					[方法2举例]
					ubuntu:~/Linux_4412/kernel/linux-3.14$make dtbs     
					DTC      arch/arm/boot/dts/exynos 4412-fs4412 dtb
					DTC      arch/arm/boot/dts/ 4210-trats dtb
				3>>步骤3:将编译后的DTB拷贝到开发板
				4>>步骤4:在bootloader设置启动该dtb文件
					[步骤4举例]
					set bootcmd tftp 0x41000000 ulmage \;      //内核加载到0x41000000地址
					tftp Ox42000000 exynos4412-fs4412.dtb \;  //将设备树dtb文件加载到Ox42000000
					bootm 0x41000000-0x42000000 \;           //解析0x41000000-0x42000000内存
		]
	]
	5>>DTB = device tree binary   设备树二进制 
	6>>boot loader运行 --> DTB传递给操作系统 --> 操作系统将DTB展开(Flattened) --> 产生硬件拓扑图 --> 编程获取设备树拓扑图的节点与属性
							↓							↓							 ↓			
							↓							↓				      [/proc/device-tree/][DTB展开在平台总线内,平台总线可直接使用]
					[描述了所有硬件信息]
]
//=================================================================================================================================
[2] >> 设备树语法
[
		/{  														     //根节点
			string1 = "hello word" ;                                    //字符串数据
			data1 = <0xFF12  0xEE34  8888> ;                           //非二进制数据
			bindata1 = [11 22 33 44]  ; 							  //二进制数据
			mixdata1 = [11 22 33 44],"hello word",<0xFF12> ;		 //混合数据
			compatible ="acme, coyotes-revenge"; 	                //"制造商,型号",每个节点必须由compatiblej节点
			#address-cells= <2>;                                   //表示子节点的reg属性只有1个寄存器地址
			#size-cells= <1>;                                     //表示子节点的reg属性只有1个表示寄存器长度
			interrupt-parent =<&intc>;                           //父中断 -- 继承intc节点
			
			serial@101f0000{                 //[设备地址101f0000]  [node-name : serial] [device-full-name : 	serial@101f0000]
				compatible="arm,pl011";     //"制造商,型号",每个节点必须由compatiblej节点
				reg=<0x1 0x2  0x1000>;     // <寄存器1地址  寄存器2地址  寄存器空间大小>	
				interrupts=<1 0>;         //中断gpx_1 ,触发方式=0
				}
				
			intc:interrupt-controller@10140000{      //设备名interrupt-controller + 设备地址10140000
				compatible ="arm,pl190";            //"制造商,型号",每个节点必须由compatiblej节点
				reg=<0x3 0x4 0x1000>;         	   //<寄存器1地址  寄存器2地址  寄存器空间大小>	
				interrupt-controller;             //中断控制器节点
				#interrupt-cells =<2>;           //子节点的interrupt = <x1 x2>
			}
		}
]

//=================================================================================================================================
[3] >> 常用OF API
[
		1>>struct device_node *of_find_node_by_path(const char *path)
		#将展开后的节点封装在device_node对象[device_node对象 <--> 设备树节点]
	
		2>>struct property *of_find_property(const struct device_node *np, const char *name,int *lenp)
		#根据属性名获取属性值 -- 存储在属性结构体property
		#由于属性值可能是int,char,str,所以用void类型存储在property结构体,使用时在强制转换
		
		3>>int of_device_is_compatible(const struct device_node *device,const char *compat)
		#判断compatible值是否该设备树节点的compatible
			
		4>>struct device_node *of_get_parent(const struct device_node *node)
	    #获取当前节点的父亲节点
	    
		5>>int of_property_read_u32_array(const struct device_node *np,const char *propname,  u8 *out_values, size_t sz)
		#获取u32数组
	
		6>>unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
		#解析interrupt的中断号
]
//=================================================================================================================================

====================================================================================================
实验 >> 获取下面设备树的信息
		test_nod@12345678{
                compatible = "test,farsight";
                reg = <0xa2345678 0x24 0xb3456780 0x24>;
                mytest; 
                test_list_string = "red fish", "blue fish";
                interrupt-parent = <&gpx1>;  
                interrupts = <1 2>;   //gpx1_1,中断触发方式2
		};
====================================================================================================

====================================================================================================
//                                                d t _ d e v . c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#define ARRAY_MAX 4

static int irqno;

//中断服务函数
irqreturn_t key_irq_handler(int irqno, void *devid)
{
	printk("------------------------key pressed \n");
	return IRQ_HANDLED;
}

//模块加载
static int __init dt_drv_init(void)
{
	struct device_node *np = NULL;  //创建设备树节点 --> device_node
	
	np = of_find_node_by_path("/test_nod@12345678");
	if(np!=0){
		printk("node name = %s\n", np->name);  //test_nod
		printk("node full name = %s\n", np->full_name);  //test_nod@12345678
	}

	//节点树属性对象
	struct property *prop = NULL;
	
	//获取compatible属性值
	prop = of_find_property(np, "compatible",NULL);
	if(prop!=0)
	{
		printk("compatible value = %s\n", prop->value);
		printk("compatible name = %s\n", prop->name);
	}

	//判断该设备树节点的compatible值
	if(of_device_is_compatible(np, "farsight,test") >0 )
	{
		printk("this node have a compatible named : farsight,test\n");
	}

	//读取u32数组
	u32 regdata[ARRAY_MAX];
	int ret;
	ret = of_property_read_u32_array(np, "reg", regdata, ARRAY_MAX);
	if(!ret)
	{
		int i;
		for(i=0; i<ARRAY_MAX; i++)
			printk("----regdata[%d] = 0x%x\n", i,regdata[i]);
	}

	//读取字符串数组
	const char *pstr[3];
	int i;
	for(i=0; i<3; i++)
	{
		ret = of_property_read_string_index(np, "test_list_string", i, &pstr[i]);
		if(!ret)
		{
			printk("----pstr[%d] = %s\n", i,pstr[i]);
		}
	}

	//获取到中断号
	irqno = irq_of_parse_and_map(np, 0);
	printk("-----irqno = %d\n", irqno);
	
	
	//申请中断服务函数key_irq_handler
	ret = request_irq(irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 
				"key_irq", NULL);
	if(ret)
	{
		printk("request_irq error\n");
		return -EBUSY;
	}
	return 0;
}

static void __exit dt_drv_exit(void)
{
	free_irq(irqno,  NULL);  //释放中断号资源
}
module_init(dt_drv_init);
module_exit(dt_drv_exit);
MODULE_LICENSE("GPL");




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值