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

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灯引脚发生变化,只需要更改设备树中地址的具体值,无需更改代码

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

相关文章:

  • 剑指offer11_矩阵中的路径
  • AI时代新词-零样本学习(Zero-Shot Learning):AI的未来趋势
  • 4 通道1250MSPS‐16bit DAC 回放板
  • IPD流程落地:项目任务书Charter开发
  • MQTT通信协议
  • Guard Trace 值得吗?
  • ASP.NET Core OData 实践——Lesson2增删改查Entity和EntitySet(C#)
  • 基于Qlearning强化学习的二阶弹簧动力学模型PID控制matlab性能仿真
  • OSC协议简介、工作原理、特点、数据的接收和发送
  • 《数据结构与算法分析》读书笔记:第一章 引 论
  • 如何搭建perfino监控(分析java服务性能)
  • 第三十七天打卡
  • 鸿蒙OSUniApp 制作动态生成的轮播图#三方框架 #Uniapp
  • Monorepo 管理
  • 信创名录取消的背景下,如何认定信创产品符合信创要求?
  • 基于 STC89C52 单片机的机动车里程表设计与实现
  • 配置Maven环境(全局)
  • Python训练营打卡Day37
  • 高中数学配凑法
  • Java 权威方案:彻底修复 OPTIONS 方法安全漏洞(附企业级案例与测试指南)
  • 东莞网站推广优化/济源网络推广
  • 医疗手机网站建设/天津天狮网络营销课程
  • 做网站需要公司吗/引流推广平台
  • 做图片视频的网站有哪些/定制化网站建设
  • 做网站组服务器/培训心得体会范文
  • 宝和网站建设/庆云网站seo