07_plantform平台总线

news2024/9/22 13:26:12

总结

/sys/bus/plantform
平台总线其实就是继承 06_自己创建xbus总线 有了更多的玩法
和自己创建的xbus总线一样 平台总线也有dev和drv 需要这两个进行匹配之后 进行porbe调用
plantform_device 结构体中直觉继承了 struc device
lantform_driver 继承了driver

详细介绍

在这里插入图片描述

planform总线初始化

plantform平台总线不用手动注册 上电的时候执行了 platform_bus_init()

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_groups	= platform_dev_groups,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.dma_configure	= platform_dma_configure,
	.pm		= &platform_dev_pm_ops,
};
platform_bus_init()  //在这里进行创建planform总线
	error =  bus_register(&platform_bus_type);

plantform match的排序规则

  • of_driver_match_device:设备树匹配
  • acpi_driver_match_device:ACPI匹配
  • platform_match_id:id_table匹配
  • strcmp(pdev->name, drv->name):设备名和驱动名匹配

平台设备注册

在这里插入图片描述
plantform_device 结构体中直接继承了 struc device
仔细看里面还有结构体 resource resource专用用来继承硬件方面的信息

注册平台设备 /sys/bus/plantform/dev/xxx
int platform_device_register(struct platform_device *pdev)
struct platform_device 继承了 struct device
注意的点在于 其中platform_device->resouce 用来存放硬件资源

  • start:资源的开始值
  • end:资源的结束值
  • flasg:资源的类型
    • IORESOURCE_MEM:内存地址
    • IORESOURCE_IO:IO端口
    • IORESOURCE_DMA:DMA传输
    • IORESOURCE_IRQ:中断

平台驱动注册

在这里插入图片描述

struct plantform_driver 继承了struct driver
重写probe函数 增加id_table 存放能匹配的dev

注册平台驱动 /sys/bus/plantform/driver/xxx
platform_driver_register(struct platform_driver *)

平台驱动获取 平台dev 的硬件资源
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)

  • dev:平台设备
  • type:资源类型
  • num:resources数组中资源编号

代码实例

和构造xbus的时候差不多 关键是看明白使用平台总线的优势
在于可以抽取硬件资源 drv能直接抽取dev的硬件资源 对以后使用设备树帮助很大

platform_device.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>


#define CCM_CCGR1 																			  0x20C406C		//时钟控制寄存器
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 				0x20E006C	  //GPIO1_04复用功能选择寄存器
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 				 0x20E02F8		//PAD属性设置寄存器
#define GPIO1_GDIR 																			   0x0209C004	//GPIO方向设置寄存器(输入或输出)
#define GPIO1_DR 																				  0x0209C000   //GPIO输出状态寄存器
#define REGISTER_LENGTH																 4							//寄存器长度

/*定义平台设备的硬件资源列表*/
static struct resource rled_resource[] = {
	
	[0] = {
		.start 	= GPIO1_DR,
		.end 	= (GPIO1_DR + REGISTER_LENGTH - 1),
		.flags 	= IORESOURCE_MEM,
	},	
	[1] = {
		.start	= GPIO1_GDIR,
		.end	= (GPIO1_GDIR + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[2] = {
		.start	= IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04,
		.end	= (IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[3] = {
		.start	= CCM_CCGR1,
		.end	= (CCM_CCGR1 + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[4] = {
		.start	= IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04,
		.end	= (IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
};

/*释放paltform设备模块时执行*/
static void	rled_release(struct device *dev)
{
	printk(KERN_ALERT "led device released!\r\n");	
}

/*定义平台设备*/
static struct platform_device rled_pdev = {
	.name = "imx6ull-rled",
	.id = -1,
	.dev.release  = rled_release,
	.num_resources = ARRAY_SIZE(rled_resource),
	.resource = rled_resource,
};

/*模块入口函数,注册平台设备*/
static __init int leddevice_init(void)
{
	printk(KERN_ALERT "leddevice_init\r\n");
	platform_device_register(&rled_pdev);
	return 0;
}

/*模块退出函数,注销平台设备*/
static __exit void leddevice_exit(void)
{
	platform_device_unregister(&rled_pdev);
}

module_init(leddevice_init);
module_exit(leddevice_exit);


MODULE_LICENSE("GPL");
MODULE_AUTHOR("embedfire ");
MODULE_DESCRIPTION("led_module");
MODULE_ALIAS("led_module");

platform_driver.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

#include <linux/fs.h>
#include <linux/uaccess.h>
#include <asm/io.h>

#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/device.h>

#define DEV_MAJOR		0		/* 动态申请主设备号 */
#define DEV_NAME		"red_led" 	/*led设备名字 */

/* GPIO虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO04;
static void __iomem *SW_PAD_GPIO1_IO04;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

static int led_open(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
	return -EFAULT;
}

static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{

	unsigned char databuf[10];

	if(cnt >10)
		cnt =10;
		
    /*从用户空间拷贝数据到内核空间*/
    if(copy_from_user(databuf, buf, cnt)){
		return -EIO;
	}
    	
	if(!memcmp(databuf,"on",2)) {	
		iowrite32(0 << 4, GPIO1_DR);	
	} else if(!memcmp(databuf,"off",3)) {
		iowrite32(1 << 4, GPIO1_DR);
	}
	/*写成功后,返回写入的字数*/
	return cnt;
}

static int led_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* 自定义led的file_operations 接口*/
static struct file_operations led_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.read = led_read,
	.write = led_write,
	.release = 	led_release,
};


int major = 0;
struct class *class_led;
static int led_probe(struct platform_device *pdev)
{

	struct resource *mem_dr;
	struct resource *mem_gdir;
	struct resource *mem_iomuxc_mux;
	struct resource *mem_ccm_ccgrx;
	struct resource *mem_iomux_pad; 

	printk(KERN_ALERT "led_probe\r\n");
	/*
	* 关键在这里 drv的probe函数中 能拿到platform_device 的结构体
	* 通过 platform_get_resource 根据类型和下表拿出dev中硬件资源数组 的硬件资源resource 
	*/
	mem_dr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	mem_gdir = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	mem_iomuxc_mux = platform_get_resource(pdev, IORESOURCE_MEM, 2);
	mem_ccm_ccgrx = platform_get_resource(pdev, IORESOURCE_MEM, 3);
	mem_iomux_pad = platform_get_resource(pdev, IORESOURCE_MEM, 4);

	/* GPIO相关寄存器映射 */
  	IMX6U_CCM_CCGR1 = ioremap(mem_ccm_ccgrx->start,resource_size(mem_ccm_ccgrx));
	SW_MUX_GPIO1_IO04 = ioremap(mem_iomuxc_mux->start,resource_size(mem_iomuxc_mux));
  	SW_PAD_GPIO1_IO04 = ioremap(mem_iomux_pad->start,resource_size(mem_iomux_pad));
	GPIO1_GDIR = ioremap(mem_gdir->start, resource_size(mem_gdir));
	GPIO1_DR = ioremap(mem_dr->start, resource_size(mem_dr));	
		
		
	/* 使能GPIO1时钟 */
	iowrite32(0xffffffff, IMX6U_CCM_CCGR1);

	/* 设置GPIO1_IO04复用为普通GPIO*/
	iowrite32(5, SW_MUX_GPIO1_IO04);
	
    /*设置GPIO属性*/
	iowrite32(0x10B0, SW_PAD_GPIO1_IO04);

	/* 设置GPIO1_IO04为输出功能 */
	iowrite32(1 << 4, GPIO1_GDIR);

	/* LED输出高电平 */
	iowrite32(1<< 4, GPIO1_DR);	

	/* 注册字符设备驱动 */
	major = register_chrdev(DEV_MAJOR, DEV_NAME, &led_fops);
    printk(KERN_ALERT "led major:%d\n",major);

	/*创建/sys/class/xxx目录项*/
	class_led = class_create(THIS_MODULE, "xxx");

	/*创建/sys/class/xxx/my_led目录项,并生成dev属性文件*/
	device_create(class_led, NULL, MKDEV(major, 0), NULL,"my_led");

	return 0;
}

static int led_remove(struct platform_device *dev)
{
		/* 取消映射 */
	iounmap(IMX6U_CCM_CCGR1);
	iounmap(SW_MUX_GPIO1_IO04);
	iounmap(SW_PAD_GPIO1_IO04);
	iounmap(GPIO1_DR);
	iounmap(GPIO1_GDIR);

	/* 注销字符设备驱动 */
	unregister_chrdev(major, DEV_NAME);

	/*销毁/sys/class/xxx/my_led目录项*/
	device_destroy(class_led, MKDEV(major, 0));

	/*销毁/sys/class/xxx目录项*/
	class_destroy(class_led);

	return 0;
}

/*与平台设备文件名匹配*/
static struct platform_device_id led_ids[] = {
	{.name = "imx6ull-rled"},
	{}
};

/*定义平台驱动*/
static struct platform_driver led_driver = {
	.driver.name       =   "imx6ull-rled",
	.probe		 = led_probe,
	.remove	  = led_remove,
	.id_table = led_ids,
};

/*模块入口函数,注册平台驱动*/
static int __init leddriver_init(void)
{
	printk(KERN_ALERT "leddriver_init\r\n");
	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("embedfire ");
MODULE_DESCRIPTION("led_module");
MODULE_ALIAS("led_module");

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

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

相关文章

树(基础部分)

章节目录&#xff1a;一、二叉树1.1 为什么要使用树&#xff1f;1.2 树的常用术语1.3 二叉树概念1.4 二叉树应用二、顺序存储二叉树2.1 概述2.2 基本应用三、线索化二叉树3.1 问题引出3.2 概述3.3 基本应用四、结束语一、二叉树 1.1 为什么要使用树&#xff1f; 数组存储方式&…

MP-2平面烟雾气体传感器介绍

MP-2平面烟雾气体传感器简介MP-2烟雾检测气体传感器采用多层厚膜制造工艺&#xff0c;在微型Al2O3陶瓷基片的两面分别制作加热器和金属氧化物半导体气敏层&#xff0c;封装在金属壳体内。当环境空气中有被检测气体存在时传感器电导率发生变化&#xff0c;该气体的浓度越高&…

【数据库概论】3.1 SQL简述、数据定义和索引

第三章 关系数据库标准语言SQL 目录第三章 关系数据库标准语言SQL3.1 SQL概述3.1.1 产生与发展3.1.2 SQL的特点3.1.3 SQL的基本概念3.2 数据库实例3.3 数据定义3.3.1 模式的定义和删除3.2.2基本表的定义、删除和修改1.常见数据类型2.定义基本表3.修改基本表4.删除基本表5.模式和…

英语学习打卡day3

2023.1.22 1.mariner n.水手 2.formation n.队形;组成;形成 n.形状;形式样式;表格 the formation of landscapes Keep the formation 保持队形 The chairs were arranged in the form of circle. fill in the form 填写表格 formal adj.正式的inform 通知deform 变形uniform 统…

06_平台总线匹配规则,自己搭建总线xbus

总结 bus_register() 自己创建平台总线 /sys/bux/xxx device_register() 对平台总线加入dev /sys/bus/xxx/dev driver_register() 对平台总线加入drv /sys/bus/xxx/drv 两个相匹配的时候 直接调用drv->probe 函数 进行基本的class_create() device_create()等 创建设备文件…

TryHackMe-红队-07_武器化

Weaponization 了解并探索常见的红队武器化技术。您将学习如何使用业内常见的方法来构建自定义有效负载&#xff0c;以获得初始访问权限。 什么是武器化 武器化是网络杀伤链模式的第二阶段。在此阶段&#xff0c;攻击者使用可交付的有效负载&#xff08;如word文档&#xff…

七、python-PySpark篇(黑马程序猿-python学习记录)

1. pyspark定义 2. 下载 点击右下角版本 点击解释器设置 点击号 搜索pyspark 选择pyspark 勾选选项 在输入框中输入 -i https://pypi.tuna.tsinghua.edu.cn/simple 点击安装软件包 提示正在安装 等一两分钟就能安装完毕 3. 获取PySpark版本号 # 导包 from pyspark import Spar…

树,二叉树的认识

1.树概念及结构 1.1树的概念 注意&#xff1a;树形结构中&#xff0c;子树之间不能有交集&#xff0c;否则就不是树形结构 1.2 树的相关概念 1.3 树的表示 树结构相对线性表就比较复杂了&#xff0c;要存储表示起来就比较麻烦了&#xff0c;既然保存值域&#xff0c;也要保存…

(18)go-micro微服务ELK介绍

文章目录一 什么是ELK二 Beats的六种工具三 ELK系统的特点四 ELKbeats系统架构五 ELK优点六 最后一 什么是ELK ELK是三个[开源软件]的缩写&#xff0c;分别表示&#xff1a;Elasticsearch , Logstash, Kibana , 它们都是开源软件&#xff0c;新增了一个Beats。 Elasticsearch …

几种觉排序优劣

冒泡排序 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 对每一对相邻元素做同样的工作&#xff0c;从开始第一对到结尾的最后一对。在这一点&#xff0c;最后的元素应该会是最大的数。 针对所有的元素重复以上的步骤&#xff0c;除了最后一个。 持…

23. 异常处理机制

1. 异常 即便 python 程序的语法是正确的&#xff0c;在运行它的时候&#xff0c;也有可能发生错误。运行期检测到的错误被称为异常。 # int不能与str相加, 触发异常 print(22) # 0 不能作为除数, 触发异常 print(1/0) # sum未定义, 触发异常 print(num)异常以不同的类型出现…

【JavaSE专栏4】关键字、标识符和命名规范

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

k8s部署elk+filebeat。springCloud集成elk+filebeat+kafka+zipkin实现多个服务日志链路追踪聚合到es

一、目的 如今2023了&#xff0c;大多数javaweb架构都是springboot微服务&#xff0c;一个前端功能请求后台可能是多个不同的服务共同协做完成的。例如用户下单功能&#xff0c;js转发到后台网关gateway服务&#xff0c;然后到鉴权spring-sercurity服务&#xff0c;然后到业务…

mysql数据库管理-GTID详解

一、GTID概述 1 sql线程执行的事件也可以通过log_slave_updates系统变量来决定是否写入自己的二进制文件中&#xff0c;这是可以用于级联复制的场景。 GTID是MYSQL5.6新增的特性&#xff0c;GTID&#xff08;Global Transaction Identifier&#xff09;全称为全局事务标示符…

17种编程语言实现排序算法-计数排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

力扣sql简单篇练习(五)

力扣sql简单篇练习(五) 1 游戏玩法分析 I 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 第一次登录平台的日期就代表是时间靠前的日期 # 窗口函数是Mysql8版本后才能使用 SELECT e.player_id,e.event_date first_login FROM (SELECT player_id,e…

五、python-地图可视化篇(黑马程序猿-python学习记录)

黑马程序猿的python学习视频&#xff1a;https://www.bilibili.com/video/BV1qW4y1a7fU/ 目录 1. 基础地图 2. 设置分段 1. 基础地图 from pyecharts.charts import Map # 准备地图对象 map Map() # 准备数据 data[ ("北京",99), ("上海",199), ("…

17种编程语言实现排序算法-堆排序

开源地址 https://gitee.com/lblbc/simple-works/tree/master/sort/ 覆盖语言&#xff1a;C、C、C#、Java、Kotlin、Dart、Go、JavaScript(JS)、TypeScript(TS)、ArkTS、swift、PHP。 覆盖平台&#xff1a;安卓(Java、Kotlin)、iOS(SwiftUI)、Flutter(Dart)、Window桌面(C#)、…

Maplab 2.0发布:多传感器融合的SLAM框架,支持多机器人、语义回环检测功能

摘要 将多种传感器和深度学习集成到SLAM系统中是当前研究的重要领域。多模态是一块跳板&#xff0c;既可以在挑战场景下增强鲁棒性&#xff0c;又可以解决不同传感器配置的多机系统建图问题。Maplab 2.0提供了一个更加通用的开源平台&#xff0c;最初的Maplab用于创建和管理视…

5-3中央处理器-数据通路的功能和基本结构

文章目录一.功能二.基本结构三.数据流向&#xff08;一&#xff09;内部单总线方式1.寄存器之间的数据传送2.主存与CPU之间的数据传送3.执行算术或逻辑运算&#xff08;二&#xff09;专用数据通路方式一.功能 数据在功能部件之间传送的路径称为数据通路。路径上的部件称为数据…