荔枝派zero驱动开发06:GPIO操作(platform框架)

参考:
正点原子Linux第五十四章 platform设备驱动实验
一张图掌握 Linux platform 平台设备驱动框架

上一篇:荔枝派zero驱动开发05:GPIO操作(使用GPIO子系统)
下一篇:更新中…

概述

platform是一种分层思想,所谓的 platform 驱动并不是独立于字符设备驱动、块设备驱动和网络设备驱动之外的其他种类的驱动;platform 只是为了驱动的分离与分层而提出来的一种框架,其驱动的具体实现还是需要字符设备驱动、块设备驱动或网络设备驱动。

  • 初学对具体设计的意图无需完全掌握,大致掌握运行流,在内核驱动中可以找到和读懂相关代码即可,用户编写驱动可以参考模板

  • 参考下图,一图流,完全弄懂这张图就能完全掌握platform框架的思想 😃

在这里插入图片描述
图源:一张图掌握 Linux platform 平台设备驱动框架!

设备树修改

设备树直接使用上一章即可,无需修改

简要分析

在上一章源码基础上修改,添加platform相关的数据结构和匹配表,实现led_probe(即原驱动初始化函数),实现led_remove(原退出函数),并将驱动初始化改为platform_driver_register和platform_driver_unregister

//platform相关
// 匹配列表
static const struct of_device_id led_of_match[] = {{ .compatible = "user,led" },{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, led_of_match);/* platform驱动结构体 */
static struct platform_driver led_driver = {.driver		= {.name	= "platform-led",			// 驱动名字,将在/sys/bus/platform/drivers/下生成 .of_match_table	= led_of_match,     // 设备树匹配表},.probe		= led_probe,.remove		= led_remove,
};static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);
}

如上,设备树与led_of_match的属性值匹配后,即执行led_probe函数,同理:卸载驱动时会执行led_remove函数,卸载操作无需改动

函数原型:int (*probe)(struct platform_device *);

led_probe函数参考实现:

static int led_probe(struct platform_device *pdev)
{int ret;const char *str;printk("led driver and device was matched!\r\n");// 获取 LED 灯的 GPIO 号// 进probe说明设备树已匹配,直接使用设备树节点即可platform_led.led_gpio = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);if (platform_led.led_gpio < 0){printk("can't get gpios");return -EINVAL;}printk("gpio num = %d\r\n", platform_led.led_gpio);// 向 gpio 子系统申请使用 GPIOret = gpio_request(platform_led.led_gpio, "green");	// 设置 PI0 为输出,并且输出低电平,默认打开 LED 灯ret = gpio_direction_output(platform_led.led_gpio, 0);...// 注册字符设备...}

这里直接使用pdev->dev.of_node引用设备节点即可

后续注册字符设备、操作函数ops等无改动,不再赘述

测试

在这里插入图片描述

chardevApp同样使用上一章的测试APP,功能正常实现

源码

platform_led.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <asm/mach/map.h>
#include <asm/io.h>
#include <linux/printk.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>struct platform_led_dev
{dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node *nd;int led_gpio;
};
struct platform_led_dev platform_led = {.major = 0,
};#define PIN_N 0 // 第0个引脚,PG0,绿色
#define DEV_NAME "platform_led"
#define LED_ON 0 // 上拉,低电平亮
#define LED_OFF 1static int led_gpio_open(struct inode *inode, struct file *file)
{file->private_data = &platform_led;return 0;
}static int led_gpio_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{return 0;
}static int led_gpio_release(struct inode *inode, struct file *file)
{return 0;
}static ssize_t led_gpio_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)
{int ret = 0;unsigned char databuf;struct platform_led_dev *dev = file->private_data;ret = copy_from_user(&databuf, user_buf, sizeof(databuf));if (ret < 0){pr_err("copy_from_user failed\r\n");return -EFAULT;}if (databuf == 0 || databuf == '0') // LED_OFFgpio_set_value(dev->led_gpio, 1);if (databuf == 1 || databuf == '1') // LED_ONgpio_set_value(dev->led_gpio, 0);return 1;
}static const struct file_operations platform_led_fops = {.open = led_gpio_open,.read = led_gpio_read,.release = led_gpio_release,.write = led_gpio_write,
};static int led_probe(struct platform_device *pdev)
{int ret;const char *str;printk("led driver and device was matched!\r\n");// 获取 LED 灯的 GPIO 号// 进probe说明设备树已匹配,直接使用设备树节点即可platform_led.led_gpio = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);if (platform_led.led_gpio < 0){printk("can't get gpios");return -EINVAL;}printk("gpio num = %d\r\n", platform_led.led_gpio);// 向 gpio 子系统申请使用 GPIOret = gpio_request(platform_led.led_gpio, "green");if (ret){printk(KERN_ERR "Failed to request gpio\n");return ret;}// 设置 PI0 为输出,并且输出低电平,默认打开 LED 灯ret = gpio_direction_output(platform_led.led_gpio, 0);if (ret < 0){printk("can't set gpio!\r\n");}// 注册字符设备if (platform_led.major) // 定义了设备号,静态设备号{platform_led.devid = MKDEV(platform_led.major, 0);ret = register_chrdev_region(platform_led.major, 1, DEV_NAME);if (ret < 0){pr_err("cannot register %s char driver.ret:%d\r\n", DEV_NAME, ret);goto exit;}}else // 没有定义设备号,动态申请设备号{ret = alloc_chrdev_region(&platform_led.devid, 0, 1, DEV_NAME);if (ret < 0){pr_err("cannot alloc_chrdev_region,ret:%d\r\n", ret);goto exit;}platform_led.major = MAJOR(platform_led.devid);platform_led.minor = MINOR(platform_led.devid);}printk("led major=%d,minor=%d\r\n", platform_led.major, platform_led.minor);platform_led.cdev.owner = THIS_MODULE;cdev_init(&platform_led.cdev, &platform_led_fops);ret = cdev_add(&platform_led.cdev, platform_led.devid, 1);if (ret < 0)goto del_unregister;platform_led.class = class_create(THIS_MODULE, DEV_NAME);if (IS_ERR(platform_led.class))goto del_cdev;platform_led.device = device_create(platform_led.class, NULL, platform_led.devid, NULL, DEV_NAME);if (IS_ERR(platform_led.device))goto destroy_class;return 0;// 注意  goto后的标签没有return操作,将顺序执行多个label直至return,这里反向写
destroy_class:class_destroy(platform_led.class);
del_cdev:cdev_del(&platform_led.cdev);
del_unregister:unregister_chrdev_region(platform_led.devid, 1);
exit:printk("init failed\r\n");return -EIO;
}static int led_remove(struct platform_device *pdev)
{if (platform_led.led_gpio){gpio_set_value(platform_led.led_gpio, 1);gpio_free(platform_led.led_gpio);}cdev_del(&platform_led.cdev);unregister_chrdev_region(platform_led.devid, 1);device_destroy(platform_led.class, platform_led.devid);class_destroy(platform_led.class);return 0;
}//platform相关
// 匹配列表
static const struct of_device_id led_of_match[] = {{ .compatible = "user,led" },{ /* Sentinel */ }
};MODULE_DEVICE_TABLE(of, led_of_match);/* platform驱动结构体 */
static struct platform_driver led_driver = {.driver		= {.name	= "platform-led",			// 驱动名字,将在/sys/bus/platform/drivers/下生成 .of_match_table	= led_of_match,     // 设备树匹配表},.probe		= led_probe,.remove		= led_remove,
};static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);
}module_init(leddriver_init);
module_exit(leddriver_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("USER");
MODULE_INFO(intree, "Y");

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

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

相关文章

ELK介绍使用

文章目录 一、ELK介绍二、Elasticsearch1. ElasticSearch简介&#xff1a;2. Elasticsearch核心概念3. Elasticsearch安装4. Elasticsearch基本操作1. 字段类型介绍2. 索引3. 映射4. 文档 5. Elasticsearch 复杂查询 三、LogStash1. LogStash简介2. LogStash安装 四、kibana1. …

【企业发展战略】某环境管理集团公司发展战略与规划项目纪实

在集团公司高速发展、业务范围不断扩大时&#xff0c;组织往往对公司未来的发展方向感到迷茫&#xff0c;不知道如何进行更好的规划&#xff0c;找到合适的发展战略&#xff0c;为企业提供更长远的发展空间&#xff0c;带来更多是利益。面对这个问题&#xff0c;华恒智信认为企…

远程在线教育平台从涉及到落地实践

在当前数字化时代&#xff0c;远程在线教育平台正成为教育行业的重要趋势之一。随着互联网技术的不断发展&#xff0c;人们对于灵活、便捷的学习方式需求日益增加&#xff0c;远程在线教育平台为广大学生和教育机构提供了全新的学习和教学模式。然而&#xff0c;要让远程在线教…

uniapp微信小程序获取当前位置

uni-app微信小程序uni.getLocation获取位置&#xff1b;authorize scope.userLocation需要在app.json中声明permission&#xff1b;小程序用户拒绝授权后重新授权-CSDN博客

Python工具小技巧

Python工具小技巧 将.py后缀文件转化为.exe后缀文件安装PyinstallerPyinstaller参数大全 将.py后缀文件转化为.exe后缀文件 目前比较常见的打包exe方法都是通过Pyinstaller来实现的&#xff0c;本文也将使用这种常规方法。 安装Pyinstaller 首先我们要先安装Pyinstaller&…

CSS中em/px/rem/vh/vw区别详解

文章目录 一、介绍二、单位pxemremvh、vw 三、总结 一、介绍 传统的项目开发中&#xff0c;我们只会用到px、%、em这几个单位&#xff0c;它可以适用于大部分的项目开发&#xff0c;且拥有比较良好的兼容性 从CSS3开始&#xff0c;浏览器对计量单位的支持又提升到了另外一个境…

SpringBoot配置文件

在SpringBoot中默认配置文件是在resources目录下的名为application的文件&#xff0c;常用后缀为&#xff1a;.properties、.yml、.yaml 一、指定自己的配置文件 如果把所有的配置文件都放到一个application.properties文件中&#xff0c;难免有些太多&#xff0c;有的时候我们…

【C语言】数据类型和变量

前言&#x1f49e;&#x1f49e; 啦啦啦~这里是土土数据结构学习笔记&#x1f973;&#x1f973; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1f4a5; 所属专栏&#xff1a;C语言笔记 &#x1f4a5;欢迎大家&#x1f973;&#x1f973;点赞✨收藏&#x1f49…

Day24:安全开发-PHP应用文件管理模块显示上传黑白名单类型过滤访问控制

目录 文件管理模块-上传-过滤机制 文件管理模块-显示-过滤机制 思维导图 PHP知识点 功能&#xff1a;新闻列表&#xff0c;会员中心&#xff0c;资源下载&#xff0c;留言版&#xff0c;后台模块&#xff0c;模版引用&#xff0c;框架开发等 技术&#xff1a;输入输出&#…

[java基础揉碎]方法的重写/覆盖

重写介绍 简单的说:方法覆盖(重写)就是子类有一个方法,和父类(也可能是爷爷,更上一级)的某个方法的名称、返回类型、参数一样&#xff0c;那么我们就说子类的这个方法 覆盖了父类的方法 重写重载对比

语音模块学习——LSYT201B模组(实际操作篇)

目录 一、定制词条 二、直接用串口通信 三、使用单片机通信 理论篇在这&#xff0c;依旧是深圳雷龙发展的语音模块。 http://t.csdnimg.cn/2SzJL 一、定制词条 因为我想后面加到我的毕设上加个语音模块&#xff0c;所以定制的词条都是和芯测相关的。 动作词条播报串口输…

排序(6)——快速排序算法之挖坑版&前后指针版

目录 挖坑版 基本思路 代码实现 注意点 前后指针版 基本思路 代码实现 注意点 由于hoare版本的快速排序有很多坑和需要注意的地方&#xff0c;就会导致代码写起来不容易&#xff0c;这里我们给出两种不同的单趟排序思路&#xff1a;挖坑版&#xff06;前后指针版。 挖坑…

Python 读取写入excel文件

使用Python读取和写入excel的xlsx、xls文件 目录 读取xlsx文件 安装三方库 引入三方库 读取数据 打开文件 表名 最大行数 最大列数 读取一张表 读取整个文件 返回xls整体内容 安装三方包 读取内容 写入xls文件 引入三方库 创建文件并写入数据 报错及解决 报错…

房屋租赁系统|基于 Mysql+Java+JSP技术的房屋租赁系统设计与实现(可运行源码+数据库+设计文档+部署说明+视频演示)

目录 文末获取源码 前台首页功能 管理员功能 租户功能 房屋租赁系统结构图 数据库设计 lunwen参考 概述 源码获取 文末获取源码 前台首页功能 管理员功能 租户功能 房屋租赁系统结构图 数据库设计 lunwen参考 概述 随着科学技术的飞速发展&#xff0c;社会的方方面面…

ODI报错

三月 08, 2024 1:20:09 下午 oracle.odi.mapping 信息: Start generation of map physical design: MapPhysicalDesign New_Mapping.物理 三月 08, 2024 1:20:09 下午 oracle.odi.mapping 信息: Finished generation of map physical design: MapPhysicalDesign New_Mapping.物…

HTML—基本介绍

HTML是一种超文本标记语言(HyperText Markup Language)&#xff0c;用于创建网页的标记语言超文本&#xff1a;是指页面内可以包含图片、链接、声音、视频等内容标记&#xff1a;HTML富含大量的标签供程序员使用&#xff0c;通过标记符号来规定指定内容的样式 浏览器最终根据不…

HybridCLR热更新介绍

官方文档 参照视频 HybridCLR介绍 HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生c#热更方案 HybridCLR与ToLua/XLua、ILRuntime有什么不同 什么是游戏热更新&#xff1a;有热更的游戏更新流程 游戏热更新的种类 资源热更新&#xff1a;主要…

内存分区与具体介绍:

1. 内存分区图&#xff1a; 2. 分区介绍&#xff1a; 2.1. 栈区&#xff1a; 存放&#xff1a;临时的局部变量、函数的传参 特点&#xff1a;占用内存小&#xff0c;速度快 数据的存储和释放采用栈式结构&#xff0c;先入后出&#xff0c;类似于C下类的构造析构函数 2.2. 堆区&…

在Linux(Ubuntu)中使用终端编译 vscode安装

文章目录 &#x1f4da;在Linux&#xff08;Ubuntu&#xff09;中使用终端编译&#x1f407;.cpp程序编译&#x1f407;.py程序编译&#x1f407;查看Python、C编程环境 &#x1f4da;vscode安装 &#x1f4da;在Linux&#xff08;Ubuntu&#xff09;中使用终端编译 虚拟机安装…

移动端精准测试之跨版本覆盖率合并

一&#xff0c;项目简介 在移动端项目测试过程中&#xff0c;尤其是发版前的回归测试阶段&#xff0c;会遇到这样的情况&#xff0c;在测试过程中测试不断地发现问题&#xff0c;开发就进行修改&#xff0c;然后打包测试。而测试完成后呢&#xff0c;业务测试同学想知道整个回归…