当前位置: 首页 > ops >正文

Rk3568驱动开发_设备树点亮LED_11

代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>#define DTSLED_CNT 1  // 设备号个数
#define DTSLED_NAME "dtsled" // 名字
#define LEDOFF 				0			/* 关灯 	*/
#define LEDON 				1			/* 开灯 	*//* 映射后的寄存器虚拟地址指针 */
static void __iomem *PMU_GRF_GPIO0C_IOMUX_L_PI;
static void __iomem *PMU_GRF_GPIO0C_DS_0_PI;
static void __iomem *GPIO0_SWPORT_DR_H_PI;
static void __iomem *GPIO0_SWPORT_DDR_H_PI;void led_unmap(void){/* 取消映射 */iounmap(PMU_GRF_GPIO0C_IOMUX_L_PI);iounmap(PMU_GRF_GPIO0C_DS_0_PI);iounmap(GPIO0_SWPORT_DR_H_PI);iounmap(GPIO0_SWPORT_DDR_H_PI);
}/*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;  // led设备void led_switch(u8 sta)
{u32 val = 0;if(sta == LEDON) {val = readl(GPIO0_SWPORT_DR_H_PI);val &= ~(0X1 << 0); /* bit0 清零*/val |= ((0X1 << 16) | (0X1 << 0));	/* bit16 置1,允许写bit0,bit0,高电平*/writel(val, GPIO0_SWPORT_DR_H_PI);}else if(sta == LEDOFF) { val = readl(GPIO0_SWPORT_DR_H_PI);val &= ~(0X1 << 0); /* bit0 清零*/val |= ((0X1 << 16) | (0X0 << 0));	/* bit16 置1,允许写bit0,bit0,低电平	*/writel(val, GPIO0_SWPORT_DR_H_PI);} 
}static int dtsled_open(struct inode* inode, struct file* filp){filp->private_data = &dtsled;return 0;
}
static int dtsled_release(struct inode* inode, struct file* filp){//struct dtsled_dev* dev = (struct dtsled_dev* )filp->private_data;return 0;
}
static ssize_t dtsled_write(struct file* filp, const char __user* buf, size_t count, loff_t* ppos){//struct dtsled_dev* dev = (struct dtsled_dev* )filp->private_data;int retvalue;unsigned char databuf[1];unsigned char ledstat;retvalue = copy_from_user(databuf, buf, count);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;}// dtsled 字符设备操作集
static const struct file_operations dtsled_fops = {.owner = THIS_MODULE,.write = dtsled_write,.open = dtsled_open,.release = dtsled_release,
};/*入口函数*/static int __init dtsled_init(void){int ret = 0;const char* str;u32 regdata[16];int i = 0;unsigned int val = 0;// 注册字符设备,新的开发方式dtsled.major = 0; // 设备号由内核分配if(dtsled.major){ // 定义了设备号dtsled.devid = MKDEV(dtsled.major, 0);ret = register_chrdev_region(dtsled.devid, DTSLED_CNT, DTSLED_NAME);}else{ // 没有给定设备号ret = alloc_chrdev_region(&dtsled.devid, 0, DTSLED_CNT, DTSLED_NAME);dtsled.major = MAJOR(dtsled.devid);dtsled.minor = MINOR(dtsled.minor);}if(ret < 0){printk("dtsled init error \r\n");return -1;}// 添加字符设备dtsled.cdev.owner = THIS_MODULE;cdev_init(&dtsled.cdev, &dtsled_fops);  // 初始化ret = cdev_add(&dtsled.cdev, dtsled.devid, DTSLED_CNT); // 添加到内核if(ret < 0){printk("dtsled add failed \r\n");unregister_chrdev_region(dtsled.devid, DTSLED_CNT); // 释放设备号return -1;}// 自动创建设备节点dtsled.class = class_create(THIS_MODULE, DTSLED_NAME);  // 创建类if(IS_ERR(dtsled.class)){ret= PTR_ERR(dtsled.class);cdev_del(&dtsled.cdev); // 删除设备unregister_chrdev_region(dtsled.devid, DTSLED_CNT); // 释放设备号return -1;}dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME);if(IS_ERR(dtsled.device)){ret = PTR_ERR(dtsled.device);cdev_del(&dtsled.cdev); // 删除设备unregister_chrdev_region(dtsled.devid, DTSLED_CNT); // 释放设备号class_destroy(dtsled.class); // 删除类return -1;}/*获取设备树属性函数*/dtsled.nd = of_find_node_by_path("/alphaled");if(dtsled.nd == NULL){ret = -EINVAL;printk("find node by path error\r\n");return -1;}ret = of_property_read_string(dtsled.nd, "status", &str);if(ret < 0){printk("get status failed!\r\n");}else{printk("status= %s \r\n", str);}ret = of_property_read_string(dtsled.nd, "compatible", &str);if(ret < 0){printk("get compatible failed!\r\n");}else{printk("compatible= %s \r\n", str);}ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 16);if(ret < 0){printk("read reg error \r\n");cdev_del(&dtsled.cdev); // 删除字符设备unregister_chrdev_region(dtsled.devid, DTSLED_CNT); // 删除设备号 device_destroy(dtsled.class, dtsled.devid); // 删除设备 (设备用到类)class_destroy(dtsled.class); // 删除类return -1;}else{printk("reg data: \r\n");for(i = 0; i < 16; i ++){printk("%#X ", regdata[i]);}printk("\r\n");}/* LED灯初始化 */ // 内存映射PMU_GRF_GPIO0C_IOMUX_L_PI = of_iomap(dtsled.nd, 0);PMU_GRF_GPIO0C_DS_0_PI = of_iomap(dtsled.nd, 1);GPIO0_SWPORT_DR_H_PI = of_iomap(dtsled.nd, 2);GPIO0_SWPORT_DDR_H_PI = of_iomap(dtsled.nd, 3);// 初始化io/* 2、设置GPIO0_C0为GPIO功能。*/val = readl(PMU_GRF_GPIO0C_IOMUX_L_PI);val &= ~(0X7 << 0);	/* bit2:0,清零 */val |= ((0X7 << 16) | (0X0 << 0));	/* bit18:16 置1,允许写bit2:0,bit2:0:0,用作GPIO0_C0	*/writel(val, PMU_GRF_GPIO0C_IOMUX_L_PI);/* 3、设置GPIO0_C0驱动能力为level5 */val = readl(PMU_GRF_GPIO0C_DS_0_PI);val &= ~(0X3F << 0);	/* bit5:0清零*/val |= ((0X3F << 16) | (0X3F << 0));	/* bit21:16 置1,允许写bit5:0,bit5:0:0,用作GPIO0_C0	*/writel(val, PMU_GRF_GPIO0C_DS_0_PI);/* 4、设置GPIO0_C0为输出 */val = readl(GPIO0_SWPORT_DDR_H_PI);val &= ~(0X1 << 0); /* bit0 清零*/val |= ((0X1 << 16) | (0X1 << 0));	/* bit16 置1,允许写bit0,bit0,高电平	*/writel(val, GPIO0_SWPORT_DDR_H_PI);/* 5、设置GPIO0_C0为低电平,关闭LED灯。*/val = readl(GPIO0_SWPORT_DR_H_PI);val &= ~(0X1 << 0); /* bit0 清零*/val |= ((0X1 << 16) | (0X0 << 0));	/* bit16 置1,允许写bit0,bit0,低电平	*/writel(val, GPIO0_SWPORT_DR_H_PI);return 0;
}/*出口*/static void __exit dtsled_exit(void){led_switch(LEDOFF);led_unmap(); // 取消地址映射cdev_del(&dtsled.cdev); // 删除字符设备unregister_chrdev_region(dtsled.devid, DTSLED_CNT); // 删除设备号 device_destroy(dtsled.class, dtsled.devid); // 删除设备 (设备用到类)class_destroy(dtsled.class); // 删除类
}/* 注册驱动和卸载驱动 */module_init(dtsled_init);module_exit(dtsled_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Narnat");

代码中通过读取alphaled节点数据,alphaled中存放的是led灯引脚地址,这样led灯引脚发生变化,只需要更改设备树中地址的具体值,无需更改代码

结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

http://www.xdnf.cn/news/9002.html

相关文章:

  • 系统分析师备考总结
  • SPL做量化—-VMA(变异平均线)
  • node.js配置变量
  • 内容的逐次呈现以及二分查找(算法)
  • DeepSORT中的卡尔曼滤波可观测性分析:从原理到实践
  • 提示词写的好,用VSCODE+python+Claude3.5开发edge扩展插件(2)
  • 内网映射有什么作用,如何实现内网的网络地址映射到公网连接?
  • 【东枫科技】基于Docker,Nodejs,GitSite构建一个KB站点
  • 电路中常见器件作用(二极管 三极管 MOS)
  • OpenCV (C/C++) 实现 Scharr 算子进行边缘检测
  • MySQL组合索引优化策略
  • Milvus可视化客户端Attu安装与使用指南
  • esp8266 点灯科技远程控制继电器
  • 如何解决大模型返回的JSON数据前后加上```的情况
  • 2025重庆市赛
  • [java]eclipse中windowbuilder插件在线安装
  • Python 之实用函数enumerate()详解
  • vue项目webpack、vite、rollup、parcel四种构建工具对比
  • HarmonyOS NEXT~鸿蒙操作系统功耗优化特性深度解析
  • STM32F4学习第一天——keil软件安装
  • VS Code新手基础教程
  • TripGenie:畅游济南旅行规划助手:个人工作纪实(二十)
  • yolov8,c++案例汇总
  • 【身份证识别表格】把大量手机拍摄的身份证信息转换成EXCEL表格的数据,拍的身份证照片转成excel表格保存,基于WPF和腾讯OCR的实现方案
  • 微服务(SpringCloud)的简单介绍
  • AI时代新词-机器学习即服务(MLaaS)
  • 蜂鸟E203与PicoRV32两款RISC-V处理器的对比分析
  • 【Pandas】pandas DataFrame add_prefix
  • Node.js Path模块路径处理秘籍
  • 本地项目如何设置https(2)——2025-05-19