基于im6ull开发板的设备树驱动led亮灭

一、设备树解析

        设备树是描述硬件信息的平台,主要是描述芯片外设的寄存器地址,可以用一张图来描述设备树:

        在Linux中主要是以dts文件体现的。该文件中记录着硬件信息,怎么样才能让内核知道硬件信息呢。

        首先通过内核编译dts文件,生成dtb文件,一个单板启动时, u-boot 先运行,它的作用是启动内核。 u-boot 会把内核和设备树文件都读入内存,然后启动内核。在启动内核时会把设备树在内存中的地址告诉内核。接着内核解析 dtb 文件,把每一个节点都转换为 device_node 结构体,最后对于某些 device_node 结构体,会被转换为 platform_device 结构体。至于内核怎么解析dtb文件生成device结构体的过程,我们可以不用关心。

        什么样节点会生成 platform_device 结构体?具有一下特征:

        1.根节点下含有 compatile 属性的子节点;

        2.含有特定 compatile 属性的节点的子节点:如果一个节点的 compatile 属性,它的值是这 4 者之一: "simple bus","simple-mfd","isa","arm,amba-bus", 那 么 它 的 子 结 点 ( 需含compatile 属性)也可以转换为 platform_device;

        3.总线 I2C、 SPI 节点下的子节点: 不转换为 platform_device

1.设备树属性:

      (1)#address-cells:cell表示一个32位的数值,address 要用多少个 32 位数来表示;

      (2) #size-cells:size 要用多少个 32 位数来表示;

      (3)compatible:该属性表示兼容,如对于一个led,可以兼容多个驱动;根节点下方也有该属性:compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";一般双引号内部为“厂家名,模块名”,有几个逗号表示兼容那些单板;

        (4)   model:准确地定义这个硬件是什么,这个单板具体型号;

        (5)    status:状态。具体为okay,disabled,fail,fail-sss,okay表示正常;disabled表示设备不可操作,但是后面可以恢复运行;fail表示发生错误,需要修复;fail-sss表示在前者基础上发送错误信息;

        (6)  reg:表示寄存器信息。其数值受address-cells和size-cells属性限制;

        以下是部分采用上述属性描述的设备节点信息:

  2.platform_device 如何与 platform_driver 配对

        从设备树转换得来的 platform_device 会被注册进内核里,以后当我们每注册一个platform_driver 时,它们就会两两确定能否配对,如果能配对成功调用 platform_driver 的 probe 函数。

        匹配规则借用一张图表示:

        其实,主要还是匹配定义的节点中compatible属性是否与platform_driver .driver.of_match_table中compatible属性相同,其它的个人认为并不是特别重要;

        3.API函数

       列举部分函数:

        (1)of_find_node_by_path:查找节点;

        (2)of_find_node_by_name:根据名字查找节点

        (3)of_property_read_u32_array:读取属性数据,以数组形式缓存

        (4)of_iomap:相当于ioremap函数

驱动led例子;

        在设备树中添加节点,并通过make dtbs进行编译:

myboardled {
	#address-cells = <1>;
	#size-cells = <1>;
	compatible = "myboard_led";
	reg = < 0X02290014 0x04    /*SW_MUX_SNVS_TAMPER3_BASE*/
			0X020AC004 0x04    /*GPIO5_GDIR_BASE*/ 
			0X020AC000 0x04 >; /*GPIO5_DR_BASE*/
};

          platform_driver编写和之前没什么太大差异:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/property.h>
#include <linux/of.h>

#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>


static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
static volatile unsigned int *GPIO5_GDIR;
static volatile unsigned int *GPIO5_DR;
static int major = 0;
static struct class *led_class;

static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	char val;
	int ret;
	
	/* copy_from_user : get data from app */
	ret = copy_from_user(&val, buf, 1);

	/* to set gpio register: out 1/0 */
	if (val)
	{
		/* set gpio to let led on */
		*GPIO5_DR &= ~(1<<3);
	}
	else
	{

		/* set gpio to let led off */
		*GPIO5_DR |= (1<<3);
	}
	return 1;
}

static int led_drv_open (struct inode *node, struct file *file)
{
	/* enable gpio5
	 * configure gpio5_io3 as gpio
	 * configure gpio5_io3 as output 
	 */
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;

	*GPIO5_GDIR |= (1<<3);
	
	return 0;
}


static struct file_operations led_fileoperation = {
	.open = led_drv_open,
	.write = led_drv_write,
	.owner = THIS_MODULE,
};

static int chip_demo_gpio_probe(struct platform_device *pdev)
{
	int ret = 0;
	int err = 0;
	uint32_t regdata[6];
	struct property *proper;
	struct device_node* np = pdev->dev.of_node;

	/* 1、获取compatible属性内容 */
    proper = of_find_property(np, "compatible", NULL);
    if(proper == NULL) 
    {
        printk("compatible property find failed\r\n");
    } 
    else 
    {
        printk("compatible = %s\r\n", (char*)proper->value);
    }
	
	//2.获取led资源
	ret = of_property_read_u32_array(np, "reg", regdata, 6);
    if(ret < 0) 
    {
        printk("reg property read failed!\r\n");
    } 
    
	//3.完成寄存器映射
	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = of_iomap(np,0);
	GPIO5_GDIR 								= of_iomap(np,1);
	GPIO5_DR 								= of_iomap(np,2);

	//4.创建字符设备
	major = register_chrdev(0, "100ask_led", &led_fileoperation);  /* /dev/100ask_led */
	led_class = class_create(THIS_MODULE, "100ask_led_class");
	err = PTR_ERR(led_class);
	if (IS_ERR(led_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "led");
		return -1;
	}
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "100ask_led%d", 0); /* /dev/100ask_led0,1,... */
	return 0;
	
}


static int chip_demo_gpio_remove(struct platform_device *pdev)
{
	iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
	iounmap(GPIO5_GDIR);
	iounmap(GPIO5_DR);
	
	unregister_chrdev(major, "100ask_led");
	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);

	return 0;
}

static const struct of_device_id ask100_led[] = {
	{.compatible = "myboard_led"},
};

static struct platform_driver led_driver = {
	.probe      = chip_demo_gpio_probe,
    .remove     = chip_demo_gpio_remove,
    .driver     = {
        .name   = "mydevice",
		.of_match_table = ask100_led,
    },
};


static int __init leddriver_init(void)
{
	int ret = 0;
	ret = platform_driver_register(&led_driver); 
	if (!ret)
		printk("platform_driver_register error\n");
	return 0;
}



static void __exit leddriver_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	platform_driver_unregister(&led_driver);
}


/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */

module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");



      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值