栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux驱动学习记录-6.设备树的LED驱动

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux驱动学习记录-6.设备树的LED驱动

这一章使用第五章的设备树知识来写led驱动

1.修改设备树

在根节点下面添加子节点

alphaled {
          #address-cells = <1>;
          #size-cells = <1>;
          compatible = "atkalpha-led";
          status = "okay";
          reg = < 0x020C406C 0x04     
                  0x020E0068 0x04     
                  0x020E02F4 0x04     
                  0x0209C000 0x04     
                  0x0209C004 0x04 >;  
};
  • alphaled是节点名字
  • #address和#size都是1,表示reg属性起始地址占用一个字节,地址长度也占用一个字节
  • compatbile设置节点兼容性为"atkalpha-led"。
  • status状态属性设置为okey
  • reg属性,设置了所要使用的寄存器物理地址。

添加完保存后使用命令

make dtbs

编译得到deb文件。

2.驱动程序

摘取正点原子/04_dtsled部分代码,代码在第五节新字符驱动上修改。

#define DTSLED_CNT			1		  	
#define DTSLED_NAME			"dtsled"	


struct dtsled_dev{
	dev_t devid;			
	struct cdev cdev;		
	struct class *class;		
	struct device *device;	
	int major;				
	int minor;				
	struct device_node	*nd; 
};

struct dtsled_dev dtsled;	

static int led_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &dtsled; 
	return 0;
}


static struct file_operations dtsled_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.read = led_read,
	.write = led_write,
	.release = 	led_release,
};


static int __init led_init(void)
{
	u32 val = 0;
	int ret;
	u32 regdata[14];
	const char *str;
	struct property *proper;

	
	
	dtsled.nd = of_find_node_by_path("/alphaled");
	if(dtsled.nd == NULL) {
		printk("alphaled node nost find!rn");
		return -EINVAL;
	} else {
		printk("alphaled node find!rn");
	}

	
	proper = of_find_property(dtsled.nd, "compatible", NULL);
	if(proper == NULL) {
		printk("compatible property find failedrn");
	} else {
		printk("compatible = %srn", (char*)proper->value);
	}

	
	ret = of_property_read_string(dtsled.nd, "status", &str);
	if(ret < 0){
		printk("status read failed!rn");
	} else {
		printk("status = %srn",str);
	}

	
	ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);
	if(ret < 0) {
		printk("reg property read failed!rn");
	} else {
		u8 i = 0;
		printk("reg data:rn");
		for(i = 0; i < 10; i++)
			printk("%#X ", regdata[i]);
		printk("rn");
	}

	

#if 0
	
	IMX6U_CCM_CCGR1 = ioremap(regdata[0], regdata[1]);
	SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]);
  	SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]);
	GPIO1_DR = ioremap(regdata[6], regdata[7]);
	GPIO1_GDIR = ioremap(regdata[8], regdata[9]);
#else
	IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0);
	SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1);
  	SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2);
	GPIO1_DR = of_iomap(dtsled.nd, 3);
	GPIO1_GDIR = of_iomap(dtsled.nd, 4);
#endif


	
	
	if (dtsled.major) {		
		dtsled.devid = MKDEV(dtsled.major, 0);
		register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);
	} else {						
		alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME);	
		dtsled.major = MAJOR(dtsled.devid);	
		dtsled.minor = MINOR(dtsled.devid);	
	}
	printk("dtsled major=%d,minor=%drn",dtsled.major, dtsled.minor);	
	
	
	dtsled.cdev.owner = THIS_MODULE;
	cdev_init(&dtsled.cdev, &dtsled_fops);
	
	
	cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);

	
	dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
	if (IS_ERR(dtsled.class)) {
		return PTR_ERR(dtsled.class);
	}

	
	dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
	if (IS_ERR(dtsled.device)) {
		return PTR_ERR(dtsled.device);
	}
	
	return 0;
}


static void __exit led_exit(void)
{
	
	iounmap(IMX6U_CCM_CCGR1);
	iounmap(SW_MUX_GPIO1_IO03);
	iounmap(SW_PAD_GPIO1_IO03);
	iounmap(GPIO1_DR);
	iounmap(GPIO1_GDIR);

	
	cdev_del(&dtsled.cdev);
	unregister_chrdev_region(dtsled.devid, DTSLED_CNT); 

	device_destroy(dtsled.class, dtsled.devid);
	class_destroy(dtsled.class);
}

        代码关键在获取设备树中的属性数据:因为知道设备树的地址,可以直接通过地址查找"/alphaled",得到设备节点(在创建设备结构体,多加一个成员:struct device_node),得到节点后就要获取属性值,compatible、status、reg等。这里获取reg采用_read_u32_array(),因为我们的reg是一组32位数组。获取reg数组后,可以用ioremap()得到物理地址对应的虚拟地址,也可以通过of_iomap()直接获取虚拟地址。使用设备树推荐第二种。

        其余部分和第五章一样。

3.测试

与前面一样。

4.设备树的编译更换运行

        学习资料是用正点,但是开发板用的东山,设备树描述板级信息,所以我们用了东山的设备树文件。

        东山用的是4.9.88版本源码,正点是4.1.15,都是4版本问题不大。板子到我手里时用的应该是正点的4.1.15版本,因为我下载正点的.ko驱动没有报错。因为要使用东山的设备树,设备树和源码的版本要一致,因此我把东山的4.9.88版本源码重新烧录安装。

        进入东山资料下载的4.1.15源码archarmbootdts,找到100ask_imx6ull-14x14.dts,可自行添加节点,完成后返回源码,执行make debs,产生100ask_imx6ull-14x14.dtb文件。此dtb就是要更换的设备树文件。

        编译的设备树由两种更换方法:

        第一,通过nfs从pc传文件至开发板,把dtb文件替换/boot里的dtb文件,开发板/boot里面应该有两个文件zImage和*.dtb,开发板启动要用的,缺少或者不匹配内核无法启动。Starting Kernel ...之后板子再无其他输出,启动失败!替换成功后可以reboot重新启动开发板,如果正常开机就可以使用新的设备树。

        第二,通过东山的缮写工具,100ask_imx6ull_flashing_tool.exe,把Ubuntu的设备树通过FileZila传输到pc上,然后替换/files文件里的.dtb文件。打开.exe,开发板设置为USB启动方式,显示设备已连接,点击更新设备树,怎软件会把dtb文件替换开发板/boot目录下的dtb文件。换成emmc模式,重新启动,可以用新的设备树。

        第二种比较麻烦,推荐第一种。

        安装时遇到一系列问题,以下作为记录。在使用100ASK ToolV3.0工具烧写emmc.img后,emmc启动开发板,发现/boot目录下有三个dtb文件。

         当我分别把100ask_imx6ull-14x14.dtb和100ask_myir_imx6ull_mini.dtb删除后,板子可以正常启动,但我把100ask_imx6ull_mini.dtb删除后,板子就启动不了,可以判断他用的是mini设备树。怪不得我修改14x14.dtb的时候重启板子节点没有改变。可我板子是全功能的pro板啊!然后我把14x14.dtb文件重命名为mini.dtb,启动不了。

        r然后我使用mfgtool 烧写整个系统到 EMMC 上,启动发现是正常的,/boot里面有一个dtb文件,就是14x14的,之后替换也正常。

        更新系统后,安装驱动文件显示版本不匹配,但我确实都是4.1.15,不过驱动仍然正常使用,此报错先搁置,遇到不能用的时候再探讨。

        之后需要重点学学习系统移植篇,对内核系统还是不熟悉。捣腾两周才算解决。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/297617.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号