linux驱动(九)platform驱动模型详解,以及基于platform驱动模型的led驱动

发布者:幸福花开最新更新时间:2025-01-07 来源: cnblogs关键字:linux驱动  platform  驱动模型  led驱动 手机看文章 扫描二维码
随时随地手机看文章

参考:

http://blog.csdn.net/qq_28992301/article/details/52385518

http://blog.csdn.net/zoe6553/article/details/6372445

http://blog.chinaunix.net/uid-25014876-id-111745.html

 

1:什么是platform总线
platform总线是区别于实体总线USB、 I2C、SPI 、PIC总线的虚拟总线,一些usb设备选址的话需要通过USB总线来进行寻址,

而有些类似于SoC内部外设如led 看门狗 定时器是直接通过内存的寻址空间来进行寻址的,cpu与这些设备通信是不需要总线的,2.6内核以后要

对所有设备进行统一管理,通过kset、kobject来建立层次关系,对这些直接通过内存寻址的设备虚拟了一种总线即platform总线,在硬件上

实际是没有这个总线;platform内核纯软件的总线,所有的直接通过内存寻址的设备都映射到这条总线上;

2:platform总线的优点

  a:可以通过platform总线,可以遍历所有的platform总线设备;platform本质其实也是kset、kobject,具有kobject的特性

  b:实现设备与驱动的分离,通过platform总线,设备与驱动是分开注册的,通过platform总线的probe来随时检测与设备匹配的驱动,如匹配上即进行这个设备的驱动注册;

  c:由于上面这个优势,一个驱动可以供同类的几个设备使用;

3:platform总线以及platform总线设备驱动的实现流程

  a:platform总线注册

  b:platform_device注册

  c:platform_driver注册

  d:设备与驱动的匹配

  e:驱动的注册

platform总线的工作流程如下图:

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------

 1:根据上面的流程我们来分析一下具体代码
  platform总线的注册:platform的注册是linux内核工程师已经设注册好的;重点看一下.match = platform_match函数;platform_driver和platform_device就是通过这个函数来匹配的


1 struct bus_type platform_bus_type = {

2     .name        = 'platform',

3     .dev_attrs    = platform_dev_attrs,

4     .match        = platform_match,

5     .uevent        = platform_uevent,

6     .pm        = &platform_dev_pm_ops,

7 };


 1 int __init platform_bus_init(void)

 2 {

 3     int error;

 4 

 5     early_platform_cleanup();

 6 

 7     error = device_register(&platform_bus);

 8     if (error)

 9         return error;

10     error =  bus_register(&platform_bus_type);

11     if (error)

12         device_unregister(&platform_bus);

13     return error;

14 }


 1 static int platform_match(struct device *dev, struct device_driver *drv)

 2 {

 3     struct platform_device *pdev = to_platform_device(dev);

 4     struct platform_driver *pdrv = to_platform_driver(drv);

 5 

 6     /* match against the id table first */

 7     if (pdrv->id_table)

 8         return platform_match_id(pdrv->id_table, pdev) != NULL;

 9 

10     /* fall-back to driver name match */

11     return (strcmp(pdev->name, drv->name) == 0);

12 }


由platform_match_id函数来进行匹配的,如果id_table不为空,则通过id_table来pdev_name匹配,如果为空,则drv->name与pdev->name来进行匹配,

匹配上以后再执行probe函数,这个函数即注册这个设备的驱动;

---------------------------------------------------------------------------------------------------------------------------------------------------------------

2:platform_device的注册

在arch/arm/mach-s3c2440/mach-mini2440.c文件中

 这里注意.name、.dev.platform_data 这两个变量 

platform_driver和platform_device就是通过name来匹配的。name一致则匹配上;

.dev.platform_data这个元素是中的内容是name、gpio flag def_trigger四个元素

 1 static struct platform_device mini2440_led1 = {

 2     .name        = 's3c24xx_led',      

 3     .id        = 1,

 4     .dev        = {

 5         .platform_data    = &mini2440_led1_pdata,

 6     },

 7 };

 8 

 9 static struct platform_device mini2440_led2 = {

10     .name        = 's3c24xx_led',

11     .id        = 2,

12     .dev        = {

13         .platform_data    = &mini2440_led2_pdata,

14     },

15 };

 


设置好platform_device 结构体以后就可以注册platform_device设备了,把我们设置好的platform_device结构体放到mini2440这个结构体数组指针中;


 1 static struct platform_device *mini2440_devices[] __initdata = {

 2     &s3c_device_ohci,

 3     &s3c_device_wdt,

 4     &s3c_device_i2c0,

 5     &s3c_device_rtc,

 6     &s3c_device_usbgadget,

 7     &mini2440_device_eth,

 8     &mini2440_led1,

 9     &mini2440_led2,

10     &mini2440_led3,

11     &mini2440_led4,

12     &mini2440_button_device,

13     &s3c_device_nand,

14     &s3c_device_sdi,

15     &s3c_device_iis,

16     &mini2440_audio,

17 };


在arch/arm/mach-s3c2440/mach-mini2440.c


mini2440_init 函数下


platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));


使用的platform_add_devices这个函数把mini2440的所有设备注册到内核中;内核会自动查找platform_device链表以及platform_driver链表,当match以后字自动执行platform_driver的probe函数;


在整理一下platform_device的注册过程:


1:设置好platform_device结构体(对于led驱动来说关键是name、dev->platform_data两个元素)


2:初始化好dev->platform_data结构体,这里主要涉及到led驱动所要用到的gpio,


这里我们可以看到linux内核platform驱动框架的设计思想:首先设备和驱动是分开的,同类设备有共性的部分,不同的部分,不同的部分在初始化的即被设置好;共性的部分内核工程师以及设置好;然后在通过一个匹配函数如果内核链表的设备与驱动链表的驱动匹配,则会自动安装驱动,否则不会安装驱动;


3:把设置好的platform_device设备加入到mini2440_devices中


4:在mini2440_device初始化的时候通过platform_add_devices函数把platform设备注册上去;注册以后再/sys/bus/platform/devices目录下会看到dev.name的文件夹


---------------------------------------------------------------------------------------------------------------------------------------------------------


3:platform_driver的注册


1 struct platform_driver {

2     int (*probe)(struct platform_device *);

3     int (*remove)(struct platform_device *);

4     void (*shutdown)(struct platform_device *);

5     int (*suspend)(struct platform_device *, pm_message_t state);

6     int (*resume)(struct platform_device *);

7     struct device_driver driver;

8     const struct platform_device_id *id_table;

9 };


 1 static struct platform_driver s3c24xx_led_driver = {

 2     .probe        = s3c24xx_led_probe,

 3     .remove        = s3c24xx_led_remove,

 4     .driver        = {

 5         .name        = 's3c24xx_led',

 6         .owner        = THIS_MODULE,

 7     },

 8 };

 9 

10 static int __init s3c24xx_led_init(void)

11 {

12     return platform_driver_register(&s3c24xx_led_driver);

13 }


设置好platform_driver  结构体,使用platform_driver_register注册即可,这里关键的是probe、remove、driver.name 三个变量;


platform_driver_register  使用这个函数注册以后再 /sys/bus/platform/drivers目录下会看到 dev.name的文件夹


内核会自动检测匹配以后会自动执行probe函数;


-----------------------------------------------------------------------------------------------------------------------------------------------------------


代码实战:


led_driver.c driver注册;


  1 #include // module_init  module_exit

  2 #include    // __init   __exit

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 #include

 17 #include

 18 #include

 19 

 20 struct led_classdev *led_device;

 21 struct s5pv210_led_platdata *pdata;

 22 

 23 

 24 #define x210_led_on     0

 25 #define x210_led_off     1

 26 

 27 static void s5pv210_led_set(struct led_classdev *led_cdev,

 28                    enum led_brightness value)

 29 {

 30     

 31     //真正控制硬件的函数

 32     if (value == LED_OFF) {        

 33         gpio_set_value(pdata->gpio, x210_led_off);

 34         printk(KERN_INFO 'LED1 OFF...');

 35     }

 36     else {

 37         

 38         gpio_set_value(pdata->gpio, x210_led_on);

 39         printk(KERN_INFO 'LED1 ON...');

 40     }

 41 

 42 }

 43 

 44 

 45 

 46 

 47 // 模块安装函数

 48 static int s5pv210_led_probe(struct platform_device *dev)

 49 {

 50     int ret = -1;

 51     printk(KERN_INFO 'led_device initn');

 52 

 53 

 54     led_device = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);

 55     if (led_device == NULL)

 56     {

 57     printk(KERN_ERR 'No memory for led_devicen');

 58     return -ENOMEM;

 59     }

 60 

 61     pdata = dev->dev.platform_data;

 62     

 63     led_device->name = pdata->name;

 64     led_device->brightness_set = s5pv210_led_set;

 65 

 66     

 67 

 68     //在这里进行注册驱动;

 69     ret = led_classdev_register(NULL, led_device);

[1] [2]
关键字:linux驱动  platform  驱动模型  led驱动 引用地址:linux驱动(九)platform驱动模型详解,以及基于platform驱动模型的led驱动

上一篇:tiny210裸机第1课(启动原理)
下一篇:linux下的misc设备led示例

推荐阅读最新更新时间:2026-03-20 11:00

Linux下实现流水灯等功能的LED驱动代码及测试实例
驱动代码: #include linux/errno.h #include linux/kernel.h #include linux/module.h #include linux/slab.h #include linux/input.h #include linux/init.h #include linux/serio.h #include linux/delay.h #include linux/clk.h #include linux/miscdevice.h #include linux/gpio.h #include asm/io.h #include asm/irq.h #incl
[单片机]
基于S3C2440的linux-3.6.6移植——LED驱动
目前的linux版本的许多驱动都是基于设备模型,LED也不例外。 简单地说,设备模型就是系统认为所有的设备都是挂接在总线上的,而要使设备工作,就需要相应的驱动。设备模型会产生一个虚拟的文件系统——sysfs,它给用户提供了一个从用户空间去访问内核设备的方法,它在linux里的路径是/sys。如果要写程序访问sysfs,可以像读写普通文件一样来操作/sys目录下的文件。 对于基于s3c2440的开发板来说,linux-3.6.6自动的LED驱动只需改变连接LED的IO端口,及高、低电平响应即可。我的开发板的四个LED连接在了B口的5到8引脚上,当输出低电平时被点亮,与linux自带的LED驱动一致,因此无需做任何改动。
[单片机]
Linux之ARM(IMX6U)裸机汇编LED驱动实验--驱动编写
1. I.MX6ULL的初始化 ①、使能时钟 使能时钟。CCGR0–CCGR6这七个寄存器控制着I.MX6ULL所有外设时钟的使能,为了简单,设置CCGR0–CCGR6这七个寄存器全部为0xFFFFFFFF,相当于使能所有的外设时钟 CCGR0: CCGR1: CCGR2: CCGR3: CCGR4: CCGR5: CCGR6: 汇编使能所有的外设时钟: ②、配置 GPIO_I003 PIN的复用为GPIO 将IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3-0,设置为0101,这样GPIO_IO03就复用为GPIO 汇编实现: ③、配置 IOMUXC_SW_P
[单片机]
<font color='red'>Linux</font>之ARM(IMX6U)裸机汇编<font color='red'>LED驱动</font>实验--<font color='red'>驱动</font>编写
Linux之ARM(IMX6U)裸机汇编LED驱动实验--烧写bin文件到SD卡运行
代码烧写 I.MX6U 虽然内部有 96K 的 ROM,但是这 96K 的 ROM 是 NXP自己用的,不向用户开放。所以相当于说 I.MX6U 是没有内部 flash 的,但是我们的代码得有地方存放啊,为此,I.MX6U 支持从外置的 NOR Flash、NAND Flash、SD/EMMC、SPI NOR Flash和 QSPI Flash 这些存储介质中启动,所以我们可以将代码烧写到这些存储介质中中。在这些存储介质中,除了 SD 卡以外,其他的一般都是焊接到了板子上的,我们没法直接烧写。但是 SD卡是活动的,是可以从板子上插拔的,我们可以将 SD 卡插到电脑上,在电脑上使用软件将.bin文件烧写到 SD 卡中,然后再插到板子
[单片机]
<font color='red'>Linux</font>之ARM(IMX6U)裸机汇编<font color='red'>LED驱动</font>实验--烧写bin文件到SD卡运行
凸轮磨损的“预测性革命”,接触应力分析和AI驱动的寿命预测模型
凸轮作为机械传动系统的核心部件,其磨损问题长期制约着设备可靠性与维护效率。传统磨损分析依赖接触应力计算与经验公式,而现代AI技术的融入正推动该领域向预测性维护演进。从材料力学建模到深度学习算法,凸轮磨损预测体系正经历系统性变革,为工业设备智能化管理提供关键支撑。 接触应力分析:磨损机理的量化基础 凸轮磨损的根源在于接触副的应力集中与材料疲劳。赫兹接触理论揭示了凸轮与从动件间的应力分布规律:当凸轮鼻半径为6.35毫米、接触力682牛时,钢制凸轮的最大接触应力可达595兆帕,远超材料屈服强度。这种应力集中导致凸轮表面出现疲劳剥落与塑性变形,尤其在低速重载工况下,油膜厚度不足加剧了边界摩擦。 有限元仿真技术进一步细化了应力分析。某柴
[嵌入式]
IMX257 设备驱动模型之sysfs文件系统知识点整合(二)
前天我们实现了一个简单的sysfs的kobject的驱动程序,可是有没有发现很多东西都不懂,原因就是在我们对sysfs和kobject的工作原理不懂,虽然我一直不提倡整天接触那些乏味的知识点,也一直不喜欢谈论太多的知识点,但是有的时候,理论知识是实践的基础,有些基础的知识点还是不得不提,下面进入正题。 一、sysfs介绍 在linux2.6内核以后,引入了一个新的文件系统sysfs,它挂载于/sys目录下,跟devfs一样它也是一个虚拟文 件系统,也是用来对系统的设备进行管理的,它把实际连接到系统上的设备和总线组织成一个分级的文件,用户空间的程序同样可以利用这些信息以实现和内核的交 互,该文件系统是当前系统上实际设备树的一个直观反
[单片机]
IMX257 设备<font color='red'>驱动</font><font color='red'>模型</font>之sysfs文件系统知识点整合(二)
IMX257设备驱动模型之Kset
一、kset介绍 1. kset结构体 Struct kset{ Struct list_head list; //连接所包含的kobject对象的链表首部 Spinlock_t list_lock; //维护list链表的自旋锁 Struct kobject kobj; //内嵌的kobject结构体,说明kset本身也是一个目录 Struct kset_uevent_ops *uevent_ops; //热插拔事件 } 从上面的结构体可以得知: kset 包含kobject 和 一个kset_uevent_ops 热插拔事件结构体 2. 热插拔事件结构体 kset_uevent_ops 热插拔事件意思就是当ks
[单片机]
IMX257设备<font color='red'>驱动</font><font color='red'>模型</font>之Kset
总线设备驱动模型
led_dev.c 1 #include linux/module.h 2 #include linux/version.h 3 4 #include linux/init.h 5 6 #include linux/kernel.h 7 #include linux/types.h 8 #include linux/interrupt.h 9 #include linux/list.h 10 #include linux/timer.h 11 #include linux/init.h 12 #include linux/serial_core.h 13 #include linux/platform_
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved