Stm32mp157A-DK1评估Linux LED驱动-5 platform设备

本文介绍了如何将Linux字符设备驱动程序拆分为驱动程序和设备程序两部分,通过platform接口连接。在设备程序中定义了寄存器地址并创建了platform_device结构体,而在驱动程序中则通过platform_driver结构体调用设备程序,并在运行时从设备程序获取寄存器地址进行映射。这样改进提高了驱动的灵活性和安全性,避免了多个应用对同一设备的冲突问题。
摘要由CSDN通过智能技术生成
之前的程序说到底只是对字符设备的一种简化写法,使用设备树进行寄存器的地址定义然后使用gpio子系统对寄存器进行设置。但是这些程序都是直接写了一个驱动对Linux进行操作,在实际的工程应用中这种做法的风险很大,如果有多个应用程序希望对同一个设备进行操作,此时会发生两种可能,一种是误操作,一种时堵塞。在实际应用中会有一个中间层负责调度,从而解决这个问题。
st-img
接下来我们要做的就是把新字符设备的驱动例程拆分为两部分:驱动程序、设备程序中间通过platform接口进行链接。
新建文件leddevice.c,用于存放设备程序,其中主要为寄存器相关程序。
头文件需要添加 :
#include<linux/platform_device.h>
然后将寄存器相关复制进去:
#definePERIPH_BASE                       (0x40000000)    //查阅手册第158页,外设总线地址为AB1-AB5其地址为0x4000 0000 – 0X5FFF FFFF。
#defineMPU_AHB4_PERIPH_BASE                   (PERIPH_BASE+ 0x10000000)     //查阅手册第158页,gpios总线AHB4,地址为0X5000 0000 - 0x5001 FFFF。
#defineRCC_BASE                          (MPU_AHB4_PERIPH_BASE + 0x0000) //查阅手册第162页,gpios时钟,地址为0X50000000-0X5000 0FFFF 。
#defineRCC_MP_AHB4ENSETR                       (RCC_BASE+ 0XA28) //查阅手册第866页,RCC_MP_AHB4ENSETR寄存器的偏移地址为0XA28,其负责GPIOA-K的时钟开关
#defineGPIOI_BASE                                        (MPU_AHB4_PERIPH_BASE+ 0x2000) //查阅手册第162页,GPIOA地址为0X5000 2000-0X5000 23FF 。
//接下来是GPIO相关的寄存器,查阅手册第1086页,可以查阅到各个寄存器的偏移地址。
#defineGPIOI_MODER                            (GPIOI_BASE + 0x0000)         
#defineGPIOI_OTYPER                            (GPIOI_BASE + 0x0004)
#defineGPIOI_OSPEEDR                          (GPIOI_BASE + 0x0008)
#defineGPIOI_PUPDR                             (GPIOI_BASE + 0x000C)      
#defineGPIOI_BSRR                         (GPIOI_BASE+ 0x0018)
之后定义platform结构体用来调用寄存器:
staticstruct platform_device leddevice = {
       .name = "xhy-led",
       .id = -1,
       .dev = {
              .release = &led_release,
       },
       .num_resources =ARRAY_SIZE(led_resources),
       .resource = led_resources,
       };
结构体中调用的与两个,一个release和一个resources。&led_release为总线释放:
staticvoid led_release(struct device *dev)
{
       printk("led devicereleased!\r\n");
}
resource时一个resources数组用于存放寄存器地址。
staticstruct resource led_resources[] = {
       [0] = {
              .start      = RCC_MP_AHB4ENSETR,
              .end       = (RCC_MP_AHB4ENSETR + REGISTER_LENGTH - 1),
              .flags      = IORESOURCE_MEM,
       },     
       [1] = {
              .start       = GPIOI_MODER,
              .end = (GPIOI_MODER + REGISTER_LENGTH - 1),
              .flags      = IORESOURCE_MEM,
       },
       [2] = {
              .start       = GPIOI_OTYPER,
              .end = (GPIOI_OTYPER + REGISTER_LENGTH - 1),
              .flags      = IORESOURCE_MEM,
       },
       [3] = {
              .start       = GPIOI_OSPEEDR,
              .end = (GPIOI_OSPEEDR + REGISTER_LENGTH - 1),
              .flags      = IORESOURCE_MEM,
       },
       [4] = {
              .start       = GPIOI_PUPDR,
              .end = (GPIOI_PUPDR + REGISTER_LENGTH - 1),
              .flags      = IORESOURCE_MEM,
       },
       [5] = {
              .start       = GPIOI_BSRR,
              .end = (GPIOI_BSRR + REGISTER_LENGTH - 1),
              .flags      = IORESOURCE_MEM,
       },
};

接下来时接口程序:leddevice_init和leddevice_exit,分别是platform的egister和unregister:
staticint __init leddevice_init(void)
{
       returnplatform_device_register(&leddevice);
}
staticvoid __exit leddevice_exit(void)
{
       platform_device_unregister(&leddevice);
}
设备层的程序写好后需要由驱动程序来调用设备程序,驱动程序中的设备寄存器地址设置删除掉,.release由于在设备程序中已定义所以也需要删除。
接口程序和设备驱动一样为platform的egister和unregister,两程序一模一样。
对应设备程序的platform结构体这里也需要定义一个platform结构体:
staticstruct platform_driver led_driver = {
       .driver            ={
              .name     = "xhy-led",                 
       },
       .probe           =led_probe,
       .remove         =led_remove,
};//platform驱动结构体
.name和设备程序中一至,这里定义了两个函数:led_probe和led_remove,
其中led_remove存放原来的leddevice_exit程序,也就是取消映射以及设备的注销。led_probe放原来的leddevice_init用于对设备的初始化。
这里需要改动的时在寄存器映射之前需要从设备程序的leddevice中读取6个寄存器的地址,之后才能把地址映射出来:‘

for (i =0; i < 6; i++) {
              ledsource =platform_get_resource(dev, IORESOURCE_MEM, i); /* 依次MEM类型资源 */
              if (!ledsource) {
                     dev_err(&dev->dev,"No MEM resource for always on\n");
                     return -ENXIO;
              }
              ressize =resource_size(ledsource);      
       }      
        /*寄存器地址映射 */
      MPU_AHB4_PERIPH_RCC_PI= ioremap(ledsource[0]->start, ressize[0]);
       GPIOI_MODER_PI =ioremap(ledsource[1]->start, ressize[1]);
      GPIOI_OTYPER_PI= ioremap(ledsource[2]->start, ressize[2]);
       GPIOI_OSPEEDR_PI =ioremap(ledsource[3]->start, ressize[3]);
       GPIOI_PUPDR_PI =ioremap(ledsource[4]->start, ressize[4]);
       GPIOI_BSRR_PI =ioremap(ledsource[5]->start, ressize[5]); 
编译以及测试
Ubuntu编译的时候需要注意由于这次需要编译两个程序,所以需要进行修改:
obj-m :=led.o   //原来的编译命令
obj-m +=leddevice.o   //后面加上另一个需要编译的程序
编译结束后将led.ko和 leddevice.ko都复制到板子中
cpledApp led.ko leddevice.ko /home/helloxhy/nfs/lib/modules/5.4.56/ -rf
之后在板子上跑程序,需要注意的时这次需要加载led和 leddevice两个驱动:
depmod
modprobeled
modprobeleddevice
./ledApp /dev/newled 0
./ledApp /dev/newled1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值