Browse Source

of_find_node_by_name获取设备树

xuxinyi 1 year ago
parent
commit
88689e9f38
3 changed files with 343 additions and 3 deletions
  1. 7 3
      设备树/tspi-rk3566-user-v10-linux.dts
  2. 306 0
      驱动文件/5/dtsled.c
  3. 30 0
      驱动文件/5/dtsof.c

+ 7 - 3
设备树/tspi-rk3566-user-v10-linux.dts

@@ -56,9 +56,13 @@
 		pinctrl-0 = <&hp_det>;
 	};
 
-    mynode4 {
-
-    };
+    my_backlight {
+        compatible = "pwm-backlight";
+        pwms = <&pwm1 0 500000>;
+        brightness-levels = <0 102 204 306 408 510 612 714 816 918 1020>;
+        default-brightness = <6>;
+        status = "okay";
+    }
 
 	leds: leds {
 		compatible = "gpio-leds";

+ 306 - 0
驱动文件/5/dtsled.c

@@ -0,0 +1,306 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <asm/mach/map.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/***************************************************************
+Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
+文件名		: dtsled.c
+作者	  	: 左忠凯
+版本	   	: V1.0
+描述	   	: LED驱动文件。
+其他	   	: 无
+论坛 	   	: www.openedv.com
+日志	   	: 初版V1.0 2019/7/9 左忠凯创建
+***************************************************************/
+#define DTSLED_CNT			1		  	/* 设备号个数 */
+#define DTSLED_NAME			"dtsled"	/* 名字 */
+#define LEDOFF 					0			/* 关灯 */
+#define LEDON 					1			/* 开灯 */
+
+/* 映射后的寄存器虚拟地址指针 */
+static void __iomem *IMX6U_CCM_CCGR1;
+static void __iomem *SW_MUX_GPIO1_IO03;
+static void __iomem *SW_PAD_GPIO1_IO03;
+static void __iomem *GPIO1_DR;
+static void __iomem *GPIO1_GDIR;
+
+/* dtsled设备结构体 */
+struct dtsled_dev{
+	dev_t devid;			/* 设备号 	 */
+	struct cdev cdev;		/* cdev 	*/
+	struct class *class;		/* 类 		*/
+	struct device *device;	/* 设备 	 */
+	int major;				/* 主设备号	  */
+	int minor;				/* 次设备号   */
+	struct device_node	*nd; /* 设备节点 */
+};
+
+struct dtsled_dev dtsled;	/* led设备 */
+
+/*
+ * @description		: LED打开/关闭
+ * @param - sta 	: LEDON(0) 打开LED,LEDOFF(1) 关闭LED
+ * @return 			: 无
+ */
+void led_switch(u8 sta)
+{
+	u32 val = 0;
+	if(sta == LEDON) {
+		val = readl(GPIO1_DR);
+		val &= ~(1 << 3);	
+		writel(val, GPIO1_DR);
+	}else if(sta == LEDOFF) {
+		val = readl(GPIO1_DR);
+		val|= (1 << 3);	
+		writel(val, GPIO1_DR);
+	}	
+}
+
+/*
+ * @description		: 打开设备
+ * @param - inode 	: 传递给驱动的inode
+ * @param - filp 	: 设备文件,file结构体有个叫做private_data的成员变量
+ * 					  一般在open的时候将private_data指向设备结构体。
+ * @return 			: 0 成功;其他 失败
+ */
+static int led_open(struct inode *inode, struct file *filp)
+{
+	filp->private_data = &dtsled; /* 设置私有数据 */
+	return 0;
+}
+
+/*
+ * @description		: 从设备读取数据 
+ * @param - filp 	: 要打开的设备文件(文件描述符)
+ * @param - buf 	: 返回给用户空间的数据缓冲区
+ * @param - cnt 	: 要读取的数据长度
+ * @param - offt 	: 相对于文件首地址的偏移
+ * @return 			: 读取的字节数,如果为负值,表示读取失败
+ */
+static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
+{
+	return 0;
+}
+
+/*
+ * @description		: 向设备写数据 
+ * @param - filp 	: 设备文件,表示打开的文件描述符
+ * @param - buf 	: 要写给设备写入的数据
+ * @param - cnt 	: 要写入的数据长度
+ * @param - offt 	: 相对于文件首地址的偏移
+ * @return 			: 写入的字节数,如果为负值,表示写入失败
+ */
+static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
+{
+	int retvalue;
+	unsigned char databuf[1];
+	unsigned char ledstat;
+
+	retvalue = copy_from_user(databuf, buf, cnt);
+	if(retvalue < 0) {
+		printk("kernel write failed!\r\n");
+		return -EFAULT;
+	}
+
+	ledstat = databuf[0];		/* 获取状态值 */
+
+	if(ledstat == LEDON) {	
+		led_switch(LEDON);		/* 打开LED灯 */
+	} else if(ledstat == LEDOFF) {
+		led_switch(LEDOFF);	/* 关闭LED灯 */
+	}
+	return 0;
+}
+
+/*
+ * @description		: 关闭/释放设备
+ * @param - filp 	: 要关闭的设备文件(文件描述符)
+ * @return 			: 0 成功;其他 失败
+ */
+static int led_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+/* 设备操作函数 */
+static struct file_operations dtsled_fops = {
+	.owner = THIS_MODULE,
+	.open = led_open,
+	.read = led_read,
+	.write = led_write,
+	.release = 	led_release,
+};
+
+/*
+ * @description	: 驱动出口函数
+ * @param 		: 无
+ * @return 		: 无
+ */
+static int __init led_init(void)
+{
+	u32 val = 0;
+	int ret;
+	u32 regdata[14];
+	const char *str;
+	struct property *proper;
+
+	/* 获取设备树中的属性数据 */
+	/* 1、获取设备节点:alphaled */
+	dtsled.nd = of_find_node_by_name("my_backlight");
+	if(dtsled.nd == NULL) {
+		printk("alphaled node nost find!\r\n");
+		return -EINVAL;
+	} else {
+		printk("alphaled node find!\r\n");
+	}
+
+	/* 2、获取compatible属性内容 */
+	proper = of_find_property(dtsled.nd, "compatible", NULL);
+	if(proper == NULL) {
+		printk("compatible property find failed\r\n");
+	} else {
+		printk("compatible = %s\r\n", (char*)proper->value);
+	}
+
+	/* 3、获取status属性内容 */
+	ret = of_property_read_string(dtsled.nd, "status", &str);
+	if(ret < 0){
+		printk("status read failed!\r\n");
+	} else {
+		printk("status = %s\r\n",str);
+	}
+
+	/* 4、获取reg属性内容 */
+	ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10);
+	if(ret < 0) {
+		printk("reg property read failed!\r\n");
+	} else {
+		u8 i = 0;
+		printk("reg data:\r\n");
+		for(i = 0; i < 10; i++)
+			printk("%#X ", regdata[i]);
+		printk("\r\n");
+	}
+
+	/* 初始化LED */
+#if 0
+	/* 1、寄存器地址映射 */
+	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
+
+	/* 2、使能GPIO1时钟 */
+	val = readl(IMX6U_CCM_CCGR1);
+	val &= ~(3 << 26);	/* 清楚以前的设置 */
+	val |= (3 << 26);	/* 设置新值 */
+	writel(val, IMX6U_CCM_CCGR1);
+
+	/* 3、设置GPIO1_IO03的复用功能,将其复用为
+	 *    GPIO1_IO03,最后设置IO属性。
+	 */
+	writel(5, SW_MUX_GPIO1_IO03);
+	
+	/*寄存器SW_PAD_GPIO1_IO03设置IO属性
+	 *bit 16:0 HYS关闭
+	 *bit [15:14]: 00 默认下拉
+     *bit [13]: 0 kepper功能
+     *bit [12]: 1 pull/keeper使能
+     *bit [11]: 0 关闭开路输出
+     *bit [7:6]: 10 速度100Mhz
+     *bit [5:3]: 110 R0/6驱动能力
+     *bit [0]: 0 低转换率
+	 */
+	writel(0x10B0, SW_PAD_GPIO1_IO03);
+
+	/* 4、设置GPIO1_IO03为输出功能 */
+	val = readl(GPIO1_GDIR);
+	val &= ~(1 << 3);	/* 清除以前的设置 */
+	val |= (1 << 3);	/* 设置为输出 */
+	writel(val, GPIO1_GDIR);
+
+	/* 5、默认关闭LED */
+	val = readl(GPIO1_DR);
+	val |= (1 << 3);	
+	writel(val, GPIO1_DR);
+
+	/* 注册字符设备驱动 */
+	/* 1、创建设备号 */
+	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=%d\r\n",dtsled.major, dtsled.minor);	
+	
+	/* 2、初始化cdev */
+	dtsled.cdev.owner = THIS_MODULE;
+	cdev_init(&dtsled.cdev, &dtsled_fops);
+	
+	/* 3、添加一个cdev */
+	cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT);
+
+	/* 4、创建类 */
+	dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);
+	if (IS_ERR(dtsled.class)) {
+		return PTR_ERR(dtsled.class);
+	}
+
+	/* 5、创建设备 */
+	dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);
+	if (IS_ERR(dtsled.device)) {
+		return PTR_ERR(dtsled.device);
+	}
+	
+	return 0;
+}
+
+/*
+ * @description	: 驱动出口函数
+ * @param 		: 无
+ * @return 		: 无
+ */
+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);/*  删除cdev */
+	unregister_chrdev_region(dtsled.devid, DTSLED_CNT); /* 注销设备号 */
+
+	device_destroy(dtsled.class, dtsled.devid);
+	class_destroy(dtsled.class);
+}
+
+module_init(led_init);
+module_exit(led_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("zuozhongkai");

+ 30 - 0
驱动文件/5/dtsof.c

@@ -0,0 +1,30 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+
+struct device_node *nd; /* 设备节点 */
+
+static int __init helloworld_init(void) {
+    pr_info("Hello world initialization!\n");
+
+    // 第一个参数设置为 NULL,从根节点开始查找
+    nd = of_find_node_by_name(NULL, "my_backlight");
+    if (nd == NULL) {
+        printk("my_backlight node not found!\n");
+        return -EINVAL;
+    } else {
+        printk("my_backlight node found!\n");
+    }
+
+    return 0;
+}
+
+static void __exit helloworld_exit(void) {
+    pr_info("Hello world exit\n");
+}
+
+module_init(helloworld_init);
+module_exit(helloworld_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Madieu <john.madieu@gmail.com>");
+MODULE_DESCRIPTION("Linux kernel module skeleton");