基于 GPIO 、Pinctl子系统、设备树的LED 驱动程序

理论部分:

编写思路:

GPIO 的地位跟其他模块,比如 I2C UART 的地方是一样的,要使用某个引脚,需要先把引脚配置为 GPIO 功能,这要使用 Pinctrl 子系统,只需要在设备 树里指定就可以。在驱动代码上不需要我们做任何事情。 GPIO 本身需要确定引脚,这也需要在设备树里指定。
设备树节点会被内核转换为 platform_device 。 对应的,驱动代码中要注册一个 platform_driver ,在 probe 函数中:获得引脚、注册 file_operations。在 file_operations 中:设置方向、读值 / 写值。

在设备树中添加 Pinctrl 信息:

有些芯片提供了设备树生成工具,在 GUI 界面中选择引脚功能和配置信息, 就可以自动生成 Pinctrl 子结点。把它复制到你的设备树文件中,再在 client device 结点中引用就可以。
有 些 芯 片 只 提 供 文 档 , 那 就 去 阅 读 文 档 , 一 般 在 内 核 源 码 目 录 Documentation\devicetree\bindings\pinctrl 下面,保存有该厂家的文档。
如果连文档都没有,那只能参考内核源码中的设备树文件,在内核源码目录 arch/arm/boot/dts 目录下。
Pinctrl 子节点的样式如下:

在设备树中添加 GPIO 信息

先查看电路原理图确定所用引脚,再在设备树中指定:添加 ”[name]-gpios” 属性,指定使用的是哪一个 GPIO Controller 里的哪一个引脚,还有其他 Flag 信息,比如 GPIO_ACTIVE_LOW 等。具体需要多少个 cell 来描述一个引脚,需要查看设备树中这个 GPIO Controller 节点里的“ #gpio-cells ”属性值,也 可以查看内核文档。

在驱动代码中调用 GPIO 子系统函数访问设备的gpio

实践部分:

创建pinctl sever节点:

 修改imx6ull-myboard.dts,利用节点生成工具配置引脚后将生成的对应代码片段替换到dts文件内对应位置,节点内容如下:

pinctrl_gpioled: ledgrp{fsl,pins = <MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03    0x10b0>;
};
  • MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 表示将该io复用为GPIO
  • 0x10b0 表示对PAD寄存器的配置值,具体含义为如下,
    /*寄存器SW_PAD_SNVS_TAMPER3设置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 低转换率
    

Pinctrl节点示例:

创建pinctrl client节点并添加GPIO信息:

在根节点下创建名为gpioled的LED节点,内容如下:

/*pinctrl led*/
gpioled {compatible = "myboard,gpioled";pinctrl-names = "default";pinctrl-0 = <&pinctrl_gpioled>;led-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;status = "okay";
};
  • pinctrl-0 设置 LED所使用的PIN对应的pinctrl节点
  • led-gpio 指定了LED所使用的GPIO,这里是GPIO5的IO03,低电平有效 

注意事项:

因为我的开发板使用的设备树文件(imx6ull-myboard.dts)是从NXP官方提供的设备树文件(imx6ull-14x14-evk.dts)上修改而来的,可能某些引脚的配置与自己的开发板不一样,需要检查一下是否有使用冲突。

本次添加的这个MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03与文件中的其它引脚没有出现冲突,因此无需修改。 

修改LED驱动文件 

重要步骤:

1 步 定义、注册一个 platform_driver
2 步 在它的 probe 函数里:
a) 根据 platform_device 的设备树信息确定 GPIO gpiod_get
b)创建设备节点
c)注册一个 file_operations 结构体register_chrdev()
 file_operarions 中使用 GPIO 子系统的函数操作 GPIO: .open()、.write()         (也就是gpiod_direction_output、 gpiod_set_value) 
全部代码如下:
/* 1. 确定主设备号                                                                 */
static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;#define MIN(a, b) (a < b ? a : b)void led_class_create_device(int minor)
{device_create(led_class, NULL, MKDEV(major, minor), NULL, "100ask_led%d", minor); /* /dev/100ask_led0,1,... */
}
void led_class_destroy_device(int minor)
{device_destroy(led_class, MKDEV(major, minor));
}
void register_led_operations(struct led_operations *opr)
{p_led_opr = opr;
}EXPORT_SYMBOL(led_class_create_device);
EXPORT_SYMBOL(led_class_destroy_device);
EXPORT_SYMBOL(register_led_operations);/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;char status;struct inode *inode = file_inode(file);int minor = iminor(inode);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = copy_from_user(&status, buf, 1);/* 根据次设备号和status控制LED */p_led_opr->ctl(minor, status);return 1;
}static int led_drv_open (struct inode *node, struct file *file)
{int minor = iminor(node);printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);/* 根据次设备号初始化LED */p_led_opr->init(minor);return 0;
}static int led_drv_close (struct inode *node, struct file *file)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations led_drv = {.owner	 = THIS_MODULE,.open    = led_drv_open,.read    = led_drv_read,.write   = led_drv_write,.release = led_drv_close,
};/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init led_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */led_class = class_create(THIS_MODULE, "100ask_led_class");err = PTR_ERR(led_class);if (IS_ERR(led_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "led");return -1;}return 0;
}/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
static void __exit led_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);class_destroy(led_class);unregister_chrdev(major, "100ask_led");
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");

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

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

相关文章

力扣HOT100 - 41. 缺失的第一个正数

解题思路&#xff1a; 原地哈希 就相当于&#xff0c;让每个数字n都回到下标为n-1的家里。 而那些没有回到家里的就成了孤魂野鬼流浪在外&#xff0c;他们要么是根本就没有自己的家&#xff08;数字小于等于0或者大于nums.size()&#xff09;&#xff0c;要么是自己的家被别…

springCloud项目打包 ,maven package或install打包报错

解决思路一&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>2.3.7.RELEASE</version></plugin><plugin>&…

【应急响应事件】记一次矿机木马事件

事情起因&#xff0c;是因为实验室有一台服务器的占用率从开机启动就是100%&#xff0c;很怀疑就是中了某种矿机木马&#xff0c;拿去挖矿了&#xff0c;然后经过师兄的不懈努力&#xff0c;终于找到了木马文件&#xff0c;给他命名为virus_sample 然后我就拿着样本去逆了 木马…

OSCP靶场--Peppo

OSCP靶场–Peppo 考点(ident枚举服务用户名ssh登陆rbash绕过 docker提权) 1.nmap扫描 ## ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.158.60 -sV -sC -Pn --min-rate 2500 -p- Starting Nmap 7.92 ( https://nmap.org ) at 2024-04-10 09:32 EDT Nmap scan report…

使用 Docker 部署 Linux-Command 命令搜索工具

1&#xff09;介绍 Linux-Command GitHub&#xff1a;https://github.com/jaywcjlove/linux-command Linux-Command 仓库搜集了 580 多个 Linux 命令&#xff0c;是一个非盈利性的仓库&#xff0c;生成了一个 Web 网站方便使用&#xff0c;目前网站没有任何广告&#xff0c;内…

T2.数据库原理

2.1 关系模型概述 1.域 域&#xff1a; 一组有相同数据类型的值得集合 2.笛卡尔积 笛卡尔积&#xff1a; 设任意的N个域D1,D2,…,Dn。 3、关系的定义和性质 &#xff08;1&#xff09;关系的数学定义&#xff1a; 在笛卡儿积中取出有实际意义的元组来构造关系。 关系也是…

C++11 数据结构1 线性表的概念,线性表的顺序存储,实现,测试

一 线性表的概念 线性结构是一种最简单且常用的数据结构。 线性结构的基本特点是节点之间满足线性关系。 本章讨论的动态数组、链表、栈、队列都属于线性结构。 他们的共同之处&#xff0c;是节点中有且只有一个开始节点和终端节点。按这种关系&#xff0c;可以把它们的所有…

leetcode每日一题第四十六天

递归解法 class Solution { public:int search(vector<int>& nums, int target) {return midsearch(nums,target,0,nums.size()-1);}int midsearch(vector<int>& nums, int target, int low,int high){if(low < high){int mid (lowhigh) / 2;if(nums[…

在Windows 10中打开PowerShell的几种方法,总有一种适合你

PowerShell是一种比命令提示符更强大的命令行shell和脚本语言。自Windows10发布以来,它已成为默认选择,并且有许多方法可以打开它。 PowerShell和命令提示符之间的区别是什么 PowerShell的使用更复杂,但它比命令提示符强大得多。这就是为什么它成为超级用户和it专业人员的…

从0开始创建单链表

前言 这次我来为大家讲解链表&#xff0c;首先我们来理解一下什么是单链表&#xff0c;我们可以将单链表想象成火车 每一节车厢装着货物和连接下一个车厢的链子&#xff0c;单链表也是如此&#xff0c;它是将一个又一个的数据封装到节点上&#xff0c;节点里不仅包含着数据&…

防错设计及原理

目录 1、防错的作用 2、防错的原理 2.1断根原理 2.2保险原理 2.3自动原理 2.4相符原理 2.5顺序原理 2.6隔离原理 2.7层别原理 2.8复制原理 2.9警告原理 2.10缓和原理 防错法&#xff08;Poka-Yoke&#xff09;&#xff0c;又称愚巧法、防呆法&#xff0c;是一种在作…

C++ 类和对象(一)

目录 0.前言 1.面向过程&面向对象 1.1面向过程编程&#xff08;PP&#xff09; 1.2面向对象编程&#xff08;OOP&#xff09; 1.3从C到C 2.类的引入 2.1C语言中的结构体 2.2C中类的引入 2.3结构体与类的区别 2.4为什么引入类 3.类的定义 3.1声明与定义不分离 …

Blast生态借贷协议Pac Finance陷“清算”风波,兄弟项目ParaSpace曾上演内斗

Blast生态协议又出事了。4月11日晚间&#xff0c;有用户发现借贷协议Pac Finance上出现了大量ezETH清算&#xff0c;涉及金额达2400 万美元。官方回应称&#xff0c;系一位智能合约工程师的操作导致Pac Finance发行清算阈值在没有事先通知团队的情况下被意外更改。 目前社区内…

【MATLAB源码-第8期】基于matlab的DPSK的误码率仿真,差分编码使用汉明码(hanming)。

1、算法描述 差分相移键控常称为二相相对调相&#xff0c;记作2DPSK。它不是利用载波相位的绝对数值传送数字信息&#xff0c;而是用前后码元的相对载波相位值传送数字信息。所谓相对载波相位是指本码元初相与前一码元初相之差。差分相移键控信号的波形如概述图所示。 假设相对…

成都百洲文化传媒有限公司电商领域的新锐力量

在电商服务领域&#xff0c;成都百洲文化传媒有限公司凭借其专业的服务理念和创新的策略&#xff0c;正逐渐成为行业内的翘楚。这家公司不仅拥有资深的电商团队&#xff0c;还以其精准的市场定位和高效的服务模式&#xff0c;赢得了众多客户的信赖和好评。 一、专业团队&#…

UDP网络程序

上一章中&#xff0c;我们介绍了socket&#xff0c;以及TCP/UDP协议。这一章带大家实现几个UDP协议的网络服务。我们需要一个 服务端和一个客户端。 1.服务端实现 1.1socket函数 #include <sys/types.h> #include <sys/socket.h>int socket(int domain, in…

Linux——十个槽位,RWX

Linux——RWX 十个槽位 - 表示文件 d 表示文件夹 l 表示软链接 r权&#xff0c;针对文件可以查看文件内容 针对文件夹&#xff0c;可以查看文件夹内容&#xff0c;如ls命令 w权&#xff0c;针对表示可以修改此文件 针对文件夹&#xff0c;可以在文件夹内&#…

Qt案例 通过调用Setupapi.h库实现对设备管理器中设备默认驱动的备份

参考腾讯电脑管家-软件市场中的驱动备份专家写的一个驱动备份软件案例&#xff0c;学习Setupapi.h库中的函数使用.通过Setupapi.h库读取设备管理器中安装的设备获取安装的驱动列表&#xff0c;通过bit7z库备份驱动目录下的所有文件. 目录导读 实现效果相关内容示例获取SP_DRVIN…

Scikit-learn 快速入门篇

Sklearn 简介 scikit-learn (sklearn) 是 Python 中用于机器学习的最流行的库之一。它提供了一系列有效的算法和工具&#xff0c;涵盖各种机器学习任务&#xff0c;包括&#xff1a; 分类回归聚类降维模型选择数据预处理 Sklearn 六大模块 分类&#xff1a;预测离散类别 算…

分布式强化学习

标题 易混淆概念联邦学习与强化学习1&#xff09;联邦学习应用于强化学习2&#xff09;强化学习应用于联邦学习 时空图卷积网络&#xff08;ST-GCN&#xff09;基本概念结合训练 易混淆概念 DistributionalRL是分布RL&#xff0c;不是分布式RL。分布RL是把Q值从一个期望构建成…