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

news2025/6/1 9:35:09

代码:

#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.coloradmin.cn/o/2392623.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多功能文档处理工具推荐

软件介绍 今天为大家介绍一款功能强大的文档编辑工具坤Tools&#xff0c;这是一款在吾爱论坛广受好评的办公软件。 软件背景 坤Tools是由吾爱论坛用户分享的软件&#xff0c;在论坛软件榜单上长期位居前列&#xff0c;获得了用户的一致好评。 软件性质 这是一款完全离线、…

【目标检测】【ICCV 2021】条件式DETR实现快速训练收敛

Conditional DETR for Fast Training Convergence 条件式DETR实现快速训练收敛 代码链接 论文链接 摘要 最近提出的DETR方法将Transformer编码器-解码器架构应用于目标检测领域&#xff0c;并取得了显著性能。本文针对其训练收敛速度慢这一关键问题&#xff0c;提出了一种条…

【工作笔记】 WSL开启报错

【工作笔记】 WSL开启报错 时间&#xff1a;2025年5月30日16:50:42 1.现象 Installing, this may take a few minutes... WslRegisterDistribution failed with error: 0x80370114 Error: 0x80370114 ??????????????????Press any key to continue...

VMware使用时出现的问题,此文章会不断更新分享使用过程中会出现的问题

VMware使用时出现的问题&#xff0c;此文章会不断更新分享使用过程中会出现的问题 一、VMware安装后没有虚拟网卡&#xff0c;VMnet1&#xff0c;VMnet8显示黄色三角警告 此文章会不断更新&#xff0c;分享VMware使用过程中出现的问题 如果没找到你的问题可以私信我 一、VMware…

深入解析Kafka JVM堆内存:优化策略与监控实践

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…

【高级终端Termux】在安卓手机/平板上使用Termux 搭建 Debian 环境并运行 PC 级 Linux 应用教程(含安装WPS,VS Code)

Termux 搭建 Debian 环境并运行 PC 级 Linux 应用教程 一、前言 1. 背景 众所周知&#xff0c;最新搭载澎湃OS和鸿蒙OS的平板都内置了PC级WPS&#xff0c;办公效率直接拉满&#xff08;板子终于从“泡面盖”升级为“生产力”了&#xff09;。但问题来了&#xff1a;如果不是这…

高频面试--redis

Reids 1. 常见的数据结构&#xff08;string, list, hash, set, zset&#xff09; 答法模板&#xff1a; Redis 提供五种核心数据结构&#xff1a; String&#xff1a;最基本的类型&#xff0c;支持整数、自增、自减、位操作。 List&#xff1a;双端链表&#xff0c;支持消息…

CRMEB 单商户Java版 v2.3公测版发布,欢迎体验!

当商城管理后台一成不变时&#xff0c;你是否也有过换换风格的想法&#xff1f; 当商城流量激增时&#xff0c;你是否也希望随时观察服务器负载状况&#xff0c;确保系统稳定运行&#xff1f; CRMEB单商户Java版v2.3公测版发布&#xff0c;更新200管理后台页面、弹窗&#xf…

华为OD机试真题——求最多可以派出多少支队伍(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

《软件工程》第 12 章 - 软件测试

软件测试是确保软件质量的关键环节&#xff0c;它通过执行程序来发现错误&#xff0c;验证软件是否满足需求。本章将依据目录&#xff0c;结合 Java 代码示例、可视化图表&#xff0c;深入讲解软件测试的概念、过程、方法及实践。 12.1 软件测试的概念 12.1.1 软件测试的任务 …

消息队列-kafka为例

目录 消息队列应用场景和基础知识MQ常见的应用场景MQ消息队列的两种消息模式如何保证消息队列的高可用&#xff1f;如何保证消息不丢失&#xff1f;如何保证消息不被重复消费&#xff1f;如何保证消息消费的幂等性&#xff1f;重复消费的原因解决方案 如何保证消息被消费的顺序…

学习STC51单片机20(芯片为STC89C52RCRC)

每日一言 生活不会一帆风顺&#xff0c;但你的勇敢能让风浪变成风景。 串口助手的界面就等于是pc端的页面设置的是pc端的波特率等等参数 程序里面的是单片机的波特率等等参数 串口助手是 PC 端软件 串口助手&#xff08;如 STC-ISP&#xff09;是运行在 PC 上的工具&#x…

链路追踪神器zipkin安装详细教程教程

今天分享下zipkin的详细安装教程&#xff0c;具体代码demo可以参考我上篇文章&#xff1a;Spring Cloud Sleuth与Zipkin深度整合指南&#xff1a;微服务链路追踪实战-CSDN博客 一、Zipkin是什么&#xff1f; Zipkin是由Twitter开源的一款分布式追踪系统&#xff08;现由OpenZ…

bug: uniCloud 查询数组字段失败

问题根源&#xff1a;使用了支付宝云 官方说&#xff1a;2024年11月之后创建的新的支付宝云空间&#xff0c;数组字段查询强制必须设置 array 类型的索引 布尔类型的查询&#xff0c;强制必须设置 bool 类型的索引。 方案一&#xff1a;找到云服务空间-》云数据库-》对应的表-…

视觉分析开发范例:Puppeteer截图+计算机视觉动态定位

一、选型背景&#xff1a;传统爬虫已无力应对的视觉挑战 在现代互联网环境中&#xff0c;尤其是小红书、抖音、B站等视觉驱动型平台&#xff0c;传统基于 HTML 的爬虫已经难以满足精准数据采集需求&#xff1a; 内容加载由 JS 动态触发&#xff0c;难以直接解析 HTML&#xf…

Linux 基础开发工具的使用

目录 前言 一&#xff1a;下载工具yum 二&#xff1a;文本编辑器vim 1. 命令模式 2. 插入模式 3. 底行模式 三&#xff1a;gcc和g 基本使用格式 常用选项及作用 编译过程示例 四、Linux 项目自动化构建工具 ——make/Makefile 1. make 与 Makefile 的关系 2. Make…

华为云Flexus+DeepSeek征文 | Dify-LLM平台一键部署教程及问题解决指南

作者简介 我是摘星&#xff0c;一名专注于云计算和AI技术的开发者。本次通过华为云MaaS平台体验DeepSeek系列模型&#xff0c;将实际使用经验分享给大家&#xff0c;希望能帮助开发者快速掌握华为云AI服务的核心能力。 目录 1. 前言 2. 准备工作 2.1 注册华为云账号 2.2 确…

哈工大计算机系统2025大作业——Hello的程序人生

计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算学部 学   号 2023113072 班 级 23L0513 学 生 董国帅 指 导 教 师 史先俊 计算机科学与…

Vue中van-stepper与input值不同步问题及解决方案

一、问题描述 在使用Vant UI的van-stepper步进器组件与原生input输入框绑定同一响应式数据时&#xff0c;出现以下现象&#xff1a; 通过步进器修改值后&#xff0c;页面直接输出{{ count }}和watch监听器均能获取最新值但input输入框显示的数值未同步更新&#xff0c;仍为旧…

react基础技术栈

react基础技术栈 react项目构建react的事件绑定React组件的响应式数据条件渲染和列表循环表单绑定 Props和组件间传值&#xff0c;插槽react中的样式操作 生命周期ref 和 context函数组件和hook高阶组件React性能问题React-route的三个版本react-router使用步骤react-router提供…