RK3568(六)——led设备驱动(GPIO子系统)

修改设备树文件

先关闭心跳灯功能,也就是在图 10.4.1.2 中第 167 行添加 status 改为 disabled,也就是禁止 work 这个节点,那么禁止心跳灯功能。

我们后面需要禁止哪个功能,只需要将其 status 属性改为 disabled 就可以了。

	gpioled{compatible = "zxk, led";led-gpio = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;status = "okay";};

编译内核并烧写boot.img

// 1. 编译
./bulid.sh kernel
// 2. 烧写

驱动编写

/* 设置LED所使用的GPIO *//* 1. 获取设备节点:gpioled */gpioled.nd = of_find_node_by_path("/gpioled");if (gpioled.nd == NULL){printk("gpioled node not found!\n");return -EINVAL;}/* 2. 读取status属性 */ret = of_property_read_string(gpioled.nd, "status", &str);if (ret < 0){printk("gpioled status not found!\n");return -EINVAL;}if (strcmp(str, "okay") != 0){printk("gpioled status not okay!\n");return -EINVAL;}/* 3. 获取compatible属性值并进行匹配 */ret = of_property_read_string(gpioled.nd, "compatible", &str);if (ret < 0){printk("compatible property not found!\n");return -EINVAL;}if (strcmp(str, "zxk, led")!= 0){printk("compatible property not match!\n");return -EINVAL;}/* 4. 获取gpio属性值并转换为gpio */ gpioled.led_gpio =  of_get_named_gpio(gpioled.nd, "led-gpio", 0);if (gpioled.led_gpio < 0){printk("led-gpio property not found!\n");return -EINVAL;}printk("led-gpio = %d\n", gpioled.led_gpio);/* 5. 向gpio子系统申请使用GPIO */ret = gpio_request(gpioled.led_gpio, "led-gpio");if (ret < 0){printk("gpio_request failed!\n");return -EINVAL;}/* 6. 设置GPIO为输出模式,并输出为低电平,默认led关闭 */ret = gpio_direction_output(gpioled.led_gpio, 0);if (ret < 0){printk("gpio_direction_output failed!\n");return -EINVAL;}
#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 <linux/of_gpio.h>
//#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>/**************************************************************** 文件名   : gpioled.c* 功能     : 这是一个led设备驱动程序文件* 作者     : zxk* 创建日期: 2024年11月28日* 其他     
***************************************************************/#define GPIOLED_CNT     1               /* 设备号个数 */
#define GPIOLED_NAME    "gpioled"       /* 设备名 */
#define LED_ON          1       /* 开灯 */
#define LED_OFF         0       /* 关灯 *//* gpioled 设备结构体 */
struct gpioled_dev
{dev_t devid;                /* 设备号 */struct cdev cdev;               /* cdev */struct class *class;        /* 类 */struct device *device;      /* 设备 */int major;                  /* 主设备号 */int minor;                  /* 次设备号 */struct device_node *nd;     /* 设备节点 */int led_gpio;               /* led对应的gpio */
};struct gpioled_dev gpioled;/**************************************************************** led_open - 函数名* description  : 打开设备* @param-inode : 传递给驱动的 inode* @param-filp  : 设备文件,file 结构体有个叫做 private_data 的成员变量* 一般在 open 的时候将 private_data 指向设备结构体。** 返回值       : 0 成功
***************************************************************/
static int led_open(struct inode *inode, struct file *filp)
{filp->private_data = &gpioled; /* 设置私有数据 */return 0;
}/**************************************************************** led_reads - 函数名* @description   : 从设备读取数据* @param-filp   : 要打开的文件设备* @param-buf    : 返回给用户空间的数据缓冲区* @param-cnt    : 读取的数据长度* @param-off_t  : 相对于文件首地址的偏移* @return       :读取的字节数
***************************************************************/
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off_t)
{    return 0;
}/**************************************************************** led_write - 函数名* @description   : 向设备写入数据* @param-filp   : 设备文件,要打开的文件设备* @param-buf    : 要写入设备的数据* @param-cnt    : 写入的数据长度* @param-off_t  : 相对于文件首地址的偏移* @return       :写入的文件数 
***************************************************************/
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *off_t)
{int retvalue;unsigned char databuf[1];unsigned char ledstat;struct gpioled_dev *dev = filp->private_data;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];       /* 获取状态值 */if(ledstat == LED_ON) { gpio_set_value(dev->led_gpio, 1);       /* 打开LED灯 */} else if(ledstat == LED_OFF) {gpio_set_value(dev->led_gpio, 0);       /* 关闭LED灯 */}return 0;
}/**************************************************************** led_release - 函数名* description  : 关闭释放设备* @param-inode : 传递给驱动的 inode* @param-filp  : 设备文件,要关闭的文件设备描述符** 返回值       : 0 成功
***************************************************************/
static int led_release(struct inode *inode, struct file *filp)
{return 0;
}/*
* 设备操作函数结构体
* 将驱动函数映射为系统调用
*/static struct file_operations gpioled_fops = 
{.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release = led_release,
};/**************************************************************** led_init - 函数名* description  : 驱动入口函数* @param       : 无* 返回值        : 0 成功
***************************************************************/
static int __init led_init(void)
{int ret;const char *str;/* 设置LED所使用的GPIO *//* 1. 获取设备节点:gpioled */gpioled.nd = of_find_node_by_path("/gpioled");if (gpioled.nd == NULL){printk("gpioled node not found!\n");return -EINVAL;}/* 2. 读取status属性 */ret = of_property_read_string(gpioled.nd, "status", &str);if (ret < 0){printk("gpioled status not found!\n");return -EINVAL;}if (strcmp(str, "okay") != 0){printk("gpioled status not okay!\n");return -EINVAL;}/* 3. 获取compatible属性值并进行匹配 */ret = of_property_read_string(gpioled.nd, "compatible", &str);if (ret < 0){printk("compatible property not found!\n");return -EINVAL;}if (strcmp(str, "zxk, led")!= 0){printk("compatible property not match!\n");return -EINVAL;}/* 4. 获取gpio属性值并转换为gpio */ gpioled.led_gpio =  of_get_named_gpio(gpioled.nd, "led-gpio", 0);if (gpioled.led_gpio < 0){printk("led-gpio property not found!\n");return -EINVAL;}printk("led-gpio = %d\n", gpioled.led_gpio);/* 5. 向gpio子系统申请使用GPIO */ret = gpio_request(gpioled.led_gpio, "led-gpio");if (ret < 0){printk("gpio_request failed!\n");return -EINVAL;}/* 6. 设置GPIO为输出模式,并输出为低电平,默认led关闭 */ret = gpio_direction_output(gpioled.led_gpio, 0);if (ret < 0){printk("gpio_direction_output failed!\n");return -EINVAL;}/* 注册字符设备驱动 *//* 1.创建设备号 */if (gpioled.major){gpioled.devid = MKDEV(gpioled.major, 0);ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);if (ret < 0){printk("cannot register %s char driver [ret=%d]\n",GPIOLED_NAME, GPIOLED_CNT);goto free_gpio;}}else{ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);if (ret < 0){printk("cannot register %s char driver [ret=%d]\n",GPIOLED_NAME, GPIOLED_CNT);goto free_gpio;}gpioled.major = MAJOR(gpioled.devid);/* 获取主设备号 */gpioled.minor = MINOR(gpioled.devid);/* 获取次设备号 */}printk("gpioled major=%d,minor=%d\r\n",gpioled.major,gpioled.minor);/*  2.初始化cdev */gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev, &gpioled_fops);/* 3.添加一个cdev字符设备 */ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);if (ret < 0){goto del_unregister;}/* 4. 创建类 */gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if (IS_ERR(gpioled.class)){goto del_cdev;}/* 5.创建设备 */gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);if (IS_ERR(gpioled.device)){goto destroy_class;}printk("led_init() \r\n");return 0;destroy_class:class_destroy(gpioled.class);
del_cdev:cdev_del(&gpioled.cdev);
del_unregister:unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
free_gpio:gpio_free(gpioled.led_gpio);return -EIO;
}/**************************************************************** led_exit - 函数名* description  : 驱动出口函数* @param       : 无* 返回值        : 0 成功
***************************************************************/
static void __exit led_exit(void)
{/* 注销字符设备驱动 */cdev_del(&gpioled.cdev);    /* 删除 cdev */unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);/* 删除类 */device_destroy(gpioled.class, gpioled.devid);class_destroy(gpioled.class);/* 释放GPIO */gpio_free(gpioled.led_gpio);printk("led_exit() \r\n");
}/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("zxk");
MODULE_INFO(intree, "Y");
ARCH = arm64
KERNELDIR := /home/zxk/work/rk3568_linux_sdk/kernel
CURRENT_PATH := /home/zxk/linux_driver/05_gpioled/obj-m := gpioled.obulid: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) cleana

编译测试

// 1.编译
make ARCH=arm64 //ARCH=arm64 必须指定,否则编译会失败
/opt/atk-dlrk356x-toolchain/bin/aarch64-buildroot-linux-gnu-gcc ledApp.c -o ledApp
// 2.上传
scp ./01_chrdevbase/chrdevbase.ko root@192.168.137.65:/lib/modules/4.19.232/
scp ./01_chrdevbase/chrdevbaseAPP root@192.168.137.65:/lib/modules/4.19.232/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/63925.shtml

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

相关文章

【自然语言处理与大模型】使用llama.cpp将HF格式大模型转换为GGUF格式

llama.cpp的主要目标是在本地和云端的各种硬件上以最小的设置和最先进的性能实现LLM推理。是一个专为大型语言模型&#xff08;LLM&#xff09;设计的高性能推理框架&#xff0c;完全使用C和C编写&#xff0c;没有外部依赖&#xff0c;这使得它可以很容易地被移植到不同的操作系…

npm : 无法加载文件 D:\nodejs\npm.ps1

问题描述 npm run serve 启动一个Vue项目&#xff0c;报错如下&#xff1a; npm : 无法加载文件 D:\nodejs\npm.ps1&#xff0c;因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅 https:/go.microsoft.com/fwlink/? LinkID135170 中的 about_Execution_Policies。…

【算法】EWMA指数加权移动平均绘制平滑曲线

EWMA&#xff08;Exponentially Weighted Moving Average&#xff0c;指数加权移动平均&#xff09;是一种常用的时间序列平滑技术&#xff0c;特别适用于对过去数据给予不同的权重。以下是对EWMA算法的详细介绍&#xff1a; 一、核心思想 EWMA算法的核心思想是通过指数衰减来…

UAC2.0 speaker——带反馈端点的 USB speaker(16bit 单声道)

UAC2.0 speaker 系列文章 UAC2.0 speaker——单声道 USB speaker(16bit) UAC2.0 speaker——类特殊请求 UAC2.0 speaker——音量控制 UAC2.0 speaker——多采样率支持 UAC2.0 speaker——24/32bit 支持 UAC2.0 speaker——speaker 数据传输 UAC2.0 speaker——同时支持 16bi…

智星云技术文档:GPU测速教程

安装gpu burn git clone https://github.com/wilicc/gpu-burn cd gpu-burn/ make测试 ./gpu_burn 60100.0% procd: 14280 (7373 Gflop/s) - 13390 (6997 Gflop/s) - 15912 (7110 Gflop/s) - 13184 (7055 Gflop/s) - 13464 (7369 Gflop/s) - 13974 (7351 Gflop/s) - 16626 (7…

Python工厂设计模式:简化对象创建

Python工厂设计模式&#xff1a;简化对象创建 引言什么是工厂模式&#xff1f;简单工厂模式示例定义基类和子类创建工厂类使用工厂创建对象 优点使用场景总结 引言 在编程中&#xff0c;我们经常需要创建不同的对象&#xff0c;但有时创建对象的逻辑可能会变得复杂。工厂设计模…

线程池+线程安全+常见锁

目录 一、线程池1、日志与策略模式2、线程池设计3、线程安全的单例模式&#xff08;1&#xff09;单例模式的特点&#xff08;2&#xff09;饿汉实现方式和懒汉实现方式&#xff08;i&#xff09;饿汉方式实现单例模式&#xff08;ii&#xff09;懒汉方式实现单例模式&#xff…

数据结构6.4——归并排序

基本思想&#xff1a; 归并排序是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法的一个非常典型的应用。将已有的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有序&#xff0c;再使子序列段间有序。若将两个有序表合并成一个…

vue3+element-plus导航栏定位

一、父组件代码&#xff1a; <template> <div v-loading"loading" class"stock-detail" scroll"handleScroll"> <!-- tab导航栏 --> <navList :tabActive"activeIndex" :tabList"tabList" :tabStyle&…

数仓高频面试 | 数仓为什么要分层

大家好&#xff0c;我是大D呀。 关于数仓分层&#xff0c;在面试过程中几乎是必问的。不过&#xff0c;面试官一般也不会直接考你数仓为什么要分层&#xff0c;而是在你介绍项目时&#xff0c;可能会换一种形式来穿插着问&#xff0c;比如数据链路为什么要这样设计&#xff0c…

revit转gltf,revit转3dtiles,如何将Revit模型转为3DTiles格式并在Cesiumjs中高效可视化

Revit模型导出gltf、glb与3dtiles有多种方式&#xff0c;但一般的商业工具收费普遍较高&#xff1a;Cesiumlab导出3dTile格式数据&#xff0c;Cesiumlab暂时可试用3天&#xff0c;会员版收费每年800&#xff1b;BimAngleEngine导出3dTile格式数据BimAngleEngine暂时可试用30天&…

可视化建模与UML《部署图实验报告》

一、实验目的&#xff1a; 1、熟悉部署图的基本功能和使用方法。 2、掌握使用建模工具软件绘制部署图的方法 二、实验环境&#xff1a; window11 EA15 三、实验内容&#xff1a; 根据以下的描述&#xff0c;绘制部署图。 网上选课系统在服务器端使用了两台主机&#xff0c;一…

在CentOS中安装和卸载mysql

在CentOS7中安装和卸载mysql 卸载mysql1、查看是否安装过mysql2、查看mysql服务状态3、关闭mysql服务4、卸载mysql相关的rpm程序5、删除mysql相关的文件6、删除mysql的配置文件my.cnf 安装mysql1、下载mysql相关的rpm程序2、检查/tmp临时目录权限3、安装mysql前的依赖检查3、安…

三相电机不转,如何判断好坏?

在现代工业生产中&#xff0c;三相电机被广泛应用于各类机械设备中&#xff0c;由于其高效能和稳定性&#xff0c;成为驱动设备的首选。然而&#xff0c;在实际使用过程中&#xff0c;三相电机有时会出现不转动的情况&#xff0c;这不仅会影响生产效率&#xff0c;还可能对设备…

ChatGPT大模型 创作高质量文案的使用教程和案例

引言 随着人工智能技术的飞速发展,大语言模型如 ChatGPT 在创作文案、生成内容方面展现出了强大的能力。无论是个人用户还是企业用户,都可以利用 ChatGPT 提高工作效率、激发创意、甚至解决实际问题。本文将详细介绍 ChatGPT 如何帮助创作各类高质量文案,并通过具体案例展示…

使用ERA5数据绘制风向玫瑰图的简易流程

使用ERA5数据绘制风向玫瑰图的简易流程 今天需要做一个2017年-2023年的平均风向的统计,做一个风向玫瑰图&#xff0c;想到的还是高分辨率的ERA5land的数据&#xff08;0.1分辨率&#xff0c;逐小时分辨率&#xff0c;1950年至今&#xff09;。 风向&#xff0c;我分为了16个&…

软考:工作后再考的性价比分析

引言 在当今的就业市场中&#xff0c;软考&#xff08;软件设计师、系统分析师等资格考试&#xff09;是否值得在校学生花费时间和精力去准备&#xff1f;本文将从多个角度深入分析软考在不同阶段的性价比&#xff0c;帮助大家做出明智的选择。 一、软考的价值与局限性 1.1 …

Qt绘制仪表————附带详细说明和代码示例

文章目录 1 效果2 原理3 编码实践3.1 创建仪表属性类3.2 设置类属性3.3 绘制图案3.3.1 设置反走样3.3.2 绘制背景3.3.3 重新定义坐标原点3.3.4 绘制圆环3.3.5 绘制刻度线3.3.6 绘制刻度线上的描述值3.3.7 绘制指针3.3.8 绘制指针数值和单位3.3.9 控制指针变化 扩展福利参考 1 效…

vue 纯前端预览pdf,纯前端实现pdf加水印下载文件也带水印,防止pdf下载

效果图 1.pdf预览 原理:主要是利用pdfh5这个插件来完成的 使用方法: 1.页面需要有一个容器例子: 2.下载pdfh5插件 npm install pdfh5 (注意:webpack5之后不会下载polyfill 需要手动下载 所以引入pdfh5的时候会报错) 解决方案:下载 node-polyfill-webpack-plugin npm i…

重生之我在异世界学编程之C语言:深入文件操作篇(上)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 函数递归与迭代 引言正文一、为什么要用文件二、文…