0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一文总结linux的platform驱动

嵌入式小生 来源:嵌入式小生 2023-10-16 16:45 次阅读

一、简介

相关文件;

  • /include/linux/platform_device.h
  • /drivers/base/platform.c

在linux设备驱动中,有许多没有特定总线的外设驱动,在实际开发中,又需要使用到总线、驱动和设备模型这三个概念,故而linux提供了platform这个虚拟总线,挂接在platform总线上的驱动称为platform驱动,由struct platform_driver描述,挂接在platorm总线上的设备称为platform设备,由struct platform_device描述。

在linux内核的驱动源码中,可以看见很多基于platform驱动框架的驱动案例实现。

二、platform总线

在linux内核中,使用struct bus_type描述一个总线,为了抽象出platform这个虚拟总线,其定义如下(/drivers/base/platform.c):

structbus_typeplatform_bus_type={
.name="platform",
.dev_groups=platform_dev_groups,
.match=platform_match,
.uevent=platform_uevent,
.pm=&platform_dev_pm_ops,
};

platform总线的注册由platform_bus_init()完成:

int__initplatform_bus_init(void)
{
interror;

early_platform_cleanup();

error=device_register(&platform_bus);
if(error)
returnerror;
error=bus_register(&platform_bus_type);
if(error)
device_unregister(&platform_bus);
of_platform_register_reconfig_notifier();
returnerror;
}

该函数在linux内核启动过程中,在driver_init()中被调用,从而向linux内核注册了platform总线。

7f22bd46-6bf9-11ee-939d-92fbcf53809c.png

三、platform设备和驱动的匹配过程

在定义platform总线的时候就定了该总线下设备和驱动的具体匹配过程,由platform_match()实现:

staticintplatform_match(structdevice*dev,structdevice_driver*drv)
{
structplatform_device*pdev=to_platform_device(dev);
structplatform_driver*pdrv=to_platform_driver(drv);

/*Whendriver_overrideisset,onlybindtothematchingdriver*/
if(pdev->driver_override)
return!strcmp(pdev->driver_override,drv->name);

/*AttemptanOFstylematchfirst*/
if(of_driver_match_device(dev,drv))
return1;

/*ThentryACPIstylematch*/
if(acpi_driver_match_device(dev,drv))
return1;

/*Thentrytomatchagainsttheidtable*/
if(pdrv->id_table)
returnplatform_match_id(pdrv->id_table,pdev)!=NULL;

/*fall-backtodrivernamematch*/
return(strcmp(pdev->name,drv->name)==0);
}

从上述代码可知,platform设备和驱动的匹配分为了四种方式处理:

  • 1、基于设备树的匹配方式。

struct device_driver结构中有个名为of_match_table的成员变量,此成员变量保存着驱动的compatible匹配表,在设备树中的每个设备节点的compatible属性会和of_match_table表中的所有成员比较,查看是否存在相同的条目,如果存在则表示设备和此驱动匹配,设备和驱动匹配成功以后probe函数就会执行(这个过程是由linux设备驱动模型中的总线去完成)。

  • 2、ACPI的匹配方式。

  • 3、id_table 匹配。

每个struct platform_driver有一个id_table成员变量,用于保存很多id信息,这些id信息存放着这个platform驱动所支持的驱动类型。

  • 4、比较name字段

如果第三种匹配方式的id_table不存在,就直接比较驱动和设备的name字段是否相等,如果相等则匹配成功;反之匹配不成功。

一般设备驱动为了兼容性都支持设备树和无设备树两种匹配方式。也就是第一种匹配方式一般都会存在,第三种和第四种只要存在一种就可以,一般用的最多的还是第四种,也就是直接比较驱动和设备的name字段,因为这种方式最简单了。

四、platrom驱动和platform设备

前文已经提到:挂接在platform总线上的驱动称为platform驱动,由struct platform_driver描述,挂接在platorm总线上的设备称为platform设备,由struct platform_device描述。要想开发基于platform设备驱动驱动框架的驱动程序,一定离不开这两个数据结构。首先来看看platform驱动的描述者struct platform_driver,该结构定义如下(/include/linux/platform_device.h):

structplatform_driver{
int(*probe)(structplatform_device*);
int(*remove)(structplatform_device*);
void(*shutdown)(structplatform_device*);
int(*suspend)(structplatform_device*,pm_message_tstate);
int(*resume)(structplatform_device*);
structdevice_driverdriver;
conststructplatform_device_id*id_table;
boolprevent_deferred_probe;
};
  • probe:当驱动与设备匹配成功以后.probe函数就会执行,这是一个非常重要的函数,一般驱动的提供者都会设计该函数。
  • remove:当platform驱动移除的时候,.remove指向的函数将执行。
  • shutdown、suspend和resume:与电源管理相关的函数。
  • driver:为device_driver结构体变量,相当于C++中的基类,提供了最基础的驱动框架。plaform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。
  • id_table:描述platform设备的id_table表,platform总线匹配驱动和设备的时候会使用。
  • prevent_deferred_probe:布尔类型变量(内部参数),用于防止驱动程序请求延迟probe,以避免进一步的徒劳的探测尝试。

再看看platform设备的描述者struct platform_device,定义如下(/include/linux/platform_device.h):

structplatform_device{
constchar*name;
intid;
boolid_auto;
structdevicedev;
u32num_resources;
structresource*resource;

conststructplatform_device_id*id_entry;
char*driver_override;/*Drivernametoforceamatch*/

/*MFDcellpointer*/
structmfd_cell*mfd_cell;

/*archspecificadditions*/
structpdev_archdataarchdata;
};
  • name :name表示设备名字,该参数要和所使用的platform驱动的name字段相同,否则设备就无法匹配到对应的驱动。
  • id:设备id。
  • dev:linux内核面向对象的具体体现,用于描述platform_device的基类。
  • num_resources:表示资源的数量。
  • resource:表示资源,也就是设备的信息,比如外设寄存器等。Linux内核使用struct resource结构体表示资源。
  • id_entry:platform设备对应的id匹配表实例,在platform总线匹配驱动和设备的时候会使用到。

五、platform驱动设计

platform驱动设计的总体思路分为两种:

  • (1)使用【struct platform_device + struct platform_driver】的方式实现。

在这种实现方式中,需要实现描述设备信息的struct platform_device结构,并需要使用platform_device来描述具体的设备信息,然后使用platform_device_register()函数将设备信息注册到 Linux 内核中;如果不再使用platform了,可以通过platform_device_unregister()函数注销相应的platform设备。

这种方式在不支持设备树的linux内核中使用!

  • (2)使用【struct platform_driver + 设备树】的方式来实现。

在编写 platform 驱动的时候,首先定义一个struct platform_driver结构体变量,然后实现结构体中的各个成员变量,重点是实现匹配方法以及probe 函数。当驱动和设备匹配成功以后.probe函数就会执行,具体的驱动程序在 probe 函数里面编写。当定义并初始化好 platform_driver 结构体变量以后,需要在驱动入口函数里面调用platform_driver_register()函数向Linux内核注册一个platform驱动。

注意,如果linux内核支持设备树,就可以不需要再使用struct platform_device来描述设备,直接使用设备树去描述设备的信息。当然,如果一定要用struct platform_device来描述设备信息也是可以的。基于新版的linux内核的platform驱动的开发,通常是通过设备树来描述设备信息,我们只需要实现对应的platform驱动即可。

六、代码示例

本小节基于【struct platform_driver + 设备树】给出一个基本的platform驱动的设计结构。

首先使用设备树描述设备的信息:

debug_device_node{
compatible="iriczhao_debug";
pinctrl-0=<&pinctrl_usdhc2_8bit>;
pinctrl-1=<&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2=<&pinctrl_usdhc2_8bit_200mhz>;
bus-width=<8>;
non-removable;
status="okay";
};

上述代码描述了一个名为debug_device_node的设备节点,给出了compatible属性值。

platform驱动设计:

#include
#include
#include
#include

#include

#include

#include

staticintplatform_demo_probe(structplatform_device*dev)
{printk("
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
");
printk("doplatform_demo_probe
");
printk("
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
");

return0;
}

staticintplatform_demo_remove(structplatform_device*dev)
{
printk("doplatform_demo_remove
");
return0;
}

staticconststructof_device_idplatform_demo_id[]={
{.compatible="iriczhao_debug"},
{/*Sentinel*/}
};

MODULE_DEVICE_TABLE(of,platform_demo_id);

staticstructplatform_driverplatform_demo_driver={
.probe=platform_demo_probe,
.remove=platform_demo_remove,
.driver={
.name="dd",
.of_match_table=platform_demo_id,
}
};


staticint__initplatform_demo_init(void)
{
printk("doplatform_demo_init
");

returnplatform_driver_register(&platform_demo_driver);
}

staticvoid__exitplatform_demo_exit(void)
{
printk("doplatform_demo_exit
");

platform_driver_unregister(&platform_demo_driver);
}

module_init(platform_demo_init);
module_exit(platform_demo_exit);

MODULE_AUTHOR("IRIC");
MODULE_LICENSE("GPL");

以模块方式构建上述代码,运行后结果如下:

7f3a1f72-6bf9-11ee-939d-92fbcf53809c.png

从上述结果可知:platform驱动和对应的设备匹配成功,且.probe指向的函数得以执行,当模块退出时,platform驱动将被移除,这时候.remove指向的函数得以执行。结果符合程序预期效果!


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206735
  • 函数
    +关注

    关注

    3

    文章

    3868

    浏览量

    61309
  • platform
    +关注

    关注

    0

    文章

    19

    浏览量

    17337

原文标题:干货 | 一文总结linux的platform驱动

文章出处:【微信号:嵌入式小生,微信公众号:嵌入式小生】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于linux内核的platform_get_resource函数

    最近在做linux驱动,在用到这个函数时有了个小问题,就是第三个参数num的意义是什么?struct resource *platform_get_resource(struct
    发表于 02-17 17:32

    sysfs platform总线

     从Linux 2.6起引入了套新的驱动管理和注册机制:platform_device和platform_driver。
    发表于 06-26 05:43

    Linuxplatform机制开发驱动流程是怎么样的?

    Linux 2.6起引入了套新的驱动管理和注册机制:platform_device和platform_driver。
    发表于 09-23 07:31

    「正点原子Linux连载」第五十四章 platform设备驱动实验(

    ,在这个思路下诞生了我们将来最常打交道的platform设备驱动,也叫做平台设备驱动。本章我们就来学习Linux下的
    发表于 03-21 10:01

    「正点原子Linux连载」第五十四章 platform设备驱动实验(二)

    IMX6U-ALPHA开发板上的LED灯,因此实验硬件原理图参考8.3小节即可。54.4试验程序编写本实验对应的例程路径为:开发板光盘->2、Linux驱动例程->17_platform。本章实验我们
    发表于 03-21 10:02

    「正点原子Linux连载」第五十五章设备树下的platform驱动编写

    1)实验平台:正点原子Linux开发板2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》关注官方微信号公众号,获取更多资料:正点原子第五十五章设备树下的platform
    发表于 03-21 10:03

    Linux驱动之基本理论常识总结

    0 引言前面Linux专题中关于Linux下系统编程总结了17篇博,主要是为了提高Linux下的C编程应用能力,熟悉
    发表于 07-01 10:38

    Linux之leds_platform教程

    Linux之leds_platform教程,很好的Linux自学资料,快来学习吧。
    发表于 04-15 17:59 9次下载

    Linux ALSA声卡驱动之八:ASoC架构中的Platform

    前面几章内容已经说过,ASoC被分为Machine,Platform和Codec三大部件,Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口(DAI)把音频数据传送给Codec进行处理,最终由Cod
    发表于 05-06 17:39 1777次阅读
    <b class='flag-5'>Linux</b> ALSA声卡<b class='flag-5'>驱动</b>之八:ASoC架构中的<b class='flag-5'>Platform</b>

    Linux设备驱动platform

    根据Linux设备模型可知,一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC系统中集成的独立的外设控制器、挂接在 SoC 内存空间的
    发表于 05-13 11:43 960次阅读
    <b class='flag-5'>Linux</b>设备<b class='flag-5'>驱动</b>之<b class='flag-5'>platform</b>

    驱动之路之platform按键驱动

    Linux 2.6起引入了一套新的驱动管理和注册机制,platform_device和platform_driver,Linux中大部分的
    发表于 05-15 17:14 925次阅读
    <b class='flag-5'>驱动</b>之路之<b class='flag-5'>platform</b>按键<b class='flag-5'>驱动</b>

    Linux内核驱动platform机制是怎样的

    Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver。
    发表于 11-06 14:12 1352次阅读
    <b class='flag-5'>Linux</b>内核<b class='flag-5'>驱动</b>的<b class='flag-5'>platform</b>机制是怎样的

    Linux驱动中的platform总线详解

    platform总线是学习linux驱动必须要掌握的一个知识点。 一、概念 嵌入式系统中有很多的物理总线:I2c、SPI、USB、uart、PCIE、APB、AHB linux从2.6
    的头像 发表于 02-26 14:02 3763次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>中的<b class='flag-5'>platform</b>总线详解

    深入解析LinuxPlatform_device 及Platform_driver

    [导读] 前文分析了Linux设备驱动驱动模型,本文来聊聊Platform_driver/Platform_device这个类。做嵌入式
    发表于 02-07 10:10 11次下载
    深入解析<b class='flag-5'>Linux</b>下 <b class='flag-5'>Platform</b>_device 及<b class='flag-5'>Platform</b>_driver

    Linux内核中现存的所有platform_device

    platform_device,证明其来源于 dtb。 note:/proc/device-tree 是链接文件, 指向 /sys/firmware/devicetree/base 以上是 Linux 原生的节点,可以供我们使用。如果你用的芯片是某个厂家,这个厂家客制
    的头像 发表于 07-30 15:28 616次阅读