二、尝试使用设备树进行驱动led

一、使用设备树驱动led

主要是为了熟悉设备树中获取自己想要的节点信息,在dtbs文件中自定义一个节点,然后使用设备树相关API获取该节点里面的led寄存器值,驱动在之前的led不变,变得只是获取设备树节点信息而已。

1.1、修改设备树

自己定义一个节点,关键节点是键值是reg,这个值里面代表需要操作的led寄存器地址的相关地址和值。

my_gpio{
		compatible = "my_led";
    	gpio-name = "GPIO103";
		#address-cells = <1>;
		#size-cells = <1>;
		reg = 	< 0x020C406C 0x04  	//时钟
				  0x020E0068 0x04 	//复用	
				  0x020E02F4 0x04 	//电器特性
				  0x0209C000 0x04 	//数据寄存器
				  0x0209C004 0x04 	>;	//方向寄存器
	};

1.2、查看嵌入式linux板子是否存在着自己自定义的节点

将其编译,重新启动linux,进入设备树相关目录,如下图,我们自定义的节点也显示在终端上,下一步,我们尝试将其reg的值获取出来。
在这里插入图片描述

1.3、读取自定义设备树节点键值

代码如下,其实一开始我这边调试使用五个数值,发现其实他是包含进去了

void dtbs_test(void)
{
    u32 data_tmp[5];
    unsigned char i = 0;
    disofled_dev.node = of_find_node_by_path("/my_gpio");
    if (!disofled_dev.node) {
		printk("No node found\r\rn");
        return;
	}
    
    printk("already get node\r\n");

    if (of_property_read_u32_array(disofled_dev.node, "reg", data_tmp, 5) == 0) {
        printk("reg:\r\n");
		for (i = 0; i < 5; i++) {
            printk("%#x ",data_tmp[i]);
		}
        printk("\r\n");
	}

}

获取到的结果为:在这里插入图片描述

读取代码最终为:

void dtbs_test(void)
{
    u32 data_tmp[10];
    unsigned char i = 0;
    disofled_dev.node = of_find_node_by_path("/my_gpio");
    if (!disofled_dev.node) {
		printk("No node found\r\rn");
        return;
	}
    
    printk("already get node\r\n");

    if (of_property_read_u32_array(disofled_dev.node, "reg", data_tmp, 10) == 0) {
        printk("reg:\r\n");
		for (i = 0; i < 10; i++) {
            printk("%#x ",data_tmp[i]);
		}
        printk("\r\n");
	}

}

实际获取到的reg值为:
在这里插入图片描述
这也和我们一开始自定义的值一样,所以我们就获取到设备树中自定义的值,接下来就是整体驱动了。

1.4、最终代码

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>

#define DISOFLED_NAME    "disofled"

#define LED_ON  0x00
#define LED_OFF 0x01



struct disofled{
     int major;		/* default to dynamic major */
     dev_t devid;
     struct cdev cdev;  /* use 1 cdev for all pins */
     struct class *class;
     struct device *device;
     struct device_node *node;
     u32 reg_data[10];
};

struct disofled  disofled_dev;


static void __iomem *ccm_ccgr1;
static void __iomem *sw_mux_gpio_io03;
static void __iomem *sw_pad_gpio_io03;
static void __iomem *gpio1_dr;
static void __iomem *gpio1_gdir;

//地址映射申请
void disofled_ioremap(void)
{
    ccm_ccgr1           = ioremap(disofled_dev.reg_data[0],4);
    sw_mux_gpio_io03    = ioremap(disofled_dev.reg_data[2],4);
    sw_pad_gpio_io03    = ioremap(disofled_dev.reg_data[4],4);
    gpio1_dr            = ioremap(disofled_dev.reg_data[6],4);
    gpio1_gdir          = ioremap(disofled_dev.reg_data[8],4);
}

//地址映射释放
void disofled_iounmap(void)
{
    iounmap(ccm_ccgr1);
    iounmap(sw_mux_gpio_io03);
    iounmap(sw_pad_gpio_io03);
    iounmap(gpio1_dr);
    iounmap(gpio1_gdir);
}



void led_switch(unsigned char stat)
{
    unsigned int tmp = 0;
    if(stat == LED_ON){

        tmp = 0;
        tmp &= ~(1<<3); 
        writel(tmp,gpio1_dr);
    }
    else if(stat == LED_OFF){
        
        tmp = 0;
        tmp |= (1<<3); 
        writel(tmp,gpio1_dr);
    }
}

void disofled_led_init(void)
{
    unsigned int val = 0;

    //初始化GPIO的时钟
    val = readl(ccm_ccgr1);
    val &= ~(3 << 26);
    val |= (3 << 26);
    writel(val,ccm_ccgr1);

    writel(0x05,sw_mux_gpio_io03);
    writel(0x10B0,sw_pad_gpio_io03);
    writel(0x08,gpio1_gdir);
    led_switch(LED_ON);
}





ssize_t disofled_write(struct file *file, const char __user *data,size_t len, loff_t *ppos)
{
    unsigned char write_data = 0;
    if(copy_from_user(&write_data,data,1))
        return -EFAULT;

    if(write_data == 1){
        led_switch(LED_ON);
    }
    else if(write_data == 0){
        led_switch(LED_OFF);
    }
    return 0;
}


static const struct file_operations disofled_fileops = {
	.owner   = THIS_MODULE,
	.write   = disofled_write,
};


int dtbs_gpio_get(void)
{
    unsigned char i = 0;
    disofled_dev.node = of_find_node_by_path("/my_gpio");
    if (!disofled_dev.node) {
		printk("No node found\r\rn");
        return -1;
	}
    
    printk("already get node\r\n");

    if (of_property_read_u32_array(disofled_dev.node, "reg", disofled_dev.reg_data, 10) == 0) {
        printk("reg:\r\n");
		for (i = 0; i < 10; i++) {
            printk("%#x ",disofled_dev.reg_data[i]);
		}
        printk("\r\n");
	}

    return 0;

}


static int __init disof_init(void)
{
    int ret = 0;
    disofled_dev.major = 0;

    if(disofled_dev.major){

    }
    if (disofled_dev.major) {
		disofled_dev.devid = MKDEV(disofled_dev.major, 0);
		ret = register_chrdev_region(disofled_dev.devid, 1, DISOFLED_NAME);
	} else {
		ret = alloc_chrdev_region(&disofled_dev.devid, 0, 1, DISOFLED_NAME);
		disofled_dev.major = MAJOR(disofled_dev.devid);
	}

    if(ret < 0){
        printk("chrdev err\r\n");
         goto CHRDEV_ERR;
    }

    printk("major:%#x\r\n",disofled_dev.major);

    cdev_init(&disofled_dev.cdev, &disofled_fileops);

	ret = cdev_add(&disofled_dev.cdev, disofled_dev.devid, 1);

    if(ret < 0){
        printk("cdev add err \r\n");
        goto CDEV_ADD;
    }

    disofled_dev.class = class_create(THIS_MODULE, DISOFLED_NAME);
    if (IS_ERR(disofled_dev.class)) {
		ret = PTR_ERR(disofled_dev.class);
		goto CDEV_ADD;
	}
    disofled_dev.device = device_create(disofled_dev.class, NULL, MKDEV(disofled_dev.major, 0), NULL,DISOFLED_NAME); 
    if (IS_ERR(disofled_dev.device)) {
		ret = PTR_ERR(disofled_dev.device);
        printk("device create err\r\n");
        goto DEVICE_CREATE;
		
	}
    printk("init module ok\r\n");

    ret = dtbs_gpio_get();
    if(ret < 0){
        printk("get node data err\r\n");
        goto NODE_ERR;
    }

    disofled_ioremap();
    disofled_led_init();

    return 0;

NODE_ERR:
    device_destroy(disofled_dev.class, disofled_dev.devid);
DEVICE_CREATE:
    class_destroy(disofled_dev.class);      //卸载类
CDEV_ADD:
    unregister_chrdev_region(MKDEV(disofled_dev.major, 0), 1);
CHRDEV_ERR:
    return ret;
}

static void __exit disofled_exit(void)
{
    
    device_destroy(disofled_dev.class, disofled_dev.devid);
    class_destroy(disofled_dev.class);      //卸载类

    cdev_del(&disofled_dev.cdev);
    unregister_chrdev_region(MKDEV(disofled_dev.major, 0), 1);

    led_switch(LED_OFF);
    disofled_iounmap();
    
}

module_init(disof_init);
module_exit(disofled_exit);
MODULE_AUTHOR("gale");
MODULE_LICENSE("GPL");


经过测试,达到自己想要的结果:
在这里插入图片描述

二、个人理解总结

从创建一个设备树节点到获取和实现自己的驱动,这个过程很简单,但是也加深自己对于驱动和设备树的一些关系理解。

发布了29 篇原创文章 · 获赞 0 · 访问量 434

猜你喜欢

转载自blog.csdn.net/weixin_42547950/article/details/104161564
今日推荐