Linux 有/无设备树下 platform_driver 驱动框架

文章目录

          • platform 驱动框架
          • platform 设备框架
          • 有设备树下驱动开发注意事项
          • 宏___一行代码创建 platform_driver

platform 驱动框架
  • 首先,定义一个 platform_driver 结构体变量

    /* platform_driver */
    static struct platform_driver xxx_driver = {
        .driver         = {
            /* .name:		  无设备树匹配方式 */
            /* .of_match_table:有设备树匹配方式 */
        },
        .probe          = xxx_probe,
        .remove         = xxx_remove,
    };
    
  • 然后,实现结构体中的各个成员变量,重点是实现匹配方法以及 probe 函数

  • 当驱动和设备匹配成功以后 probe 函数就会执行

  • 具体的驱动程序在 probe 函数里面编写,比如字符设备驱动等等


  • 定义并初始化好 platform_driver 结构体变量以后,要在驱动入口函数里面调用 platform_driver_register 函数向 Linux 内核注册一个 platform 驱动

    /*
     * driver:	要注册的 platform 驱动
     * return:	负数,失败;0,成功
     */
    int platform_driver_register (struct platform_driver *driver);
    
  • 在驱动卸载函数中通过 platform_driver_unregister 函数卸载 platform 驱动

    void platform_driver_unregister(struct platform_driver *drv);
    

  • 对于一个完整的驱动程序,必须提供有设备树和无设备树两种匹配方法

    无设备树: 使用 xxx_driver.driver.name 进行设备匹配

    有设备树: 使用 xxx_driver.driver.of_match_table 进行设备匹配

    key: 匹配列表必须以空项结尾,{ /* Sentinel */ }

    /* 匹配列表 */
    static const struct of_device_id xxx_of_match[] = {
        { .compatible = "xxx" },
        { /* Sentinel */ }
    };
    
    /* 声明 inputkey_of_match 设备匹配表 */
    MODULE_DEVICE_TABLE(of, xxx_of_match);
    
    /* 
     * platform 平台驱动结构体
     */
    static struct platform_driver xxx_driver = {
        .driver = {
            .name = "xxx",
            .of_match_table = xxx_of_match,
        },
        .probe = xxx_probe,
        .remove = xxx_remove,
    };
    
  • proberemove 的实现

    /* platform probe 函数,驱动与设备匹配成功以后此函数就会执行 */
    static int xxx_probe(struct platform_device *dev)
    {
        int ret = 0;
        ...
        /* 完成字符设备注册初始化等 */
        ...
        return 0;
    }
    
    /* platform remove 函数 */
    static int xxx_remove(struct platform_device *dev)
    {
        int ret = 0;
        ...
        /* 完成字符设备删除注销等 */
        ...
        return 0;
    }
    
platform 设备框架
  • platform_device 这个结构体表示 platform 设备

    /* @description		: 释放flatform设备模块的时候此函数会执行	
     * @param - dev 	: 要释放的设备 
     * @return 			: 无
     */
    static void	xxx_release(struct device *dev)
    {
    	printk("xxx device released!\r\n");	
    }
    
    /* 设备资源,xxx 所用寄存器信息 */
    static struct resource xxx_resources[] = {
        [0] = {},
        [1] = {},
    }
    
    /* platform 设备结构体 */
    static struct platform_device xxx_device = {
        .name           = "xxx",           				/* 与驱动相匹配 */
        .id             = -1,
        .dev            = {
            .release    = xxx_release,					/* 卸载设备时执行 */
        },
        .num_resources  = ARRAY_SIZE(xxx_resources),    /* 设备资源长度 */
        .resource       = xxx_resources,                /* 设备资源 */
    };
    
  • platform_device 同样是 模块初始化-退出 框架

    static int __init xxxdevide_init(void)
    {
        /* 注册 platform 设备 */
        return platform_device_register(&xxx_device);
    }
    
    static void __exit xxxdevide_exit(void)
    {
        /* 注销 platform 设备 */
        platform_device_unregister(&xxx_device);
    }
    
    /* 模块入口/出口 */
    module_init(xxxdevide_init);
    module_exit(xxxdevide_exit);
    /* LICENSE AND AUTHOR */
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("tao");
    MODULE_INFO(intree, "Y");
    
有设备树下驱动开发注意事项
  • ST 针对 STM32MP1 提供的 Linux 系统中,其 pinctrl 配置的电气属性只能在 platform 平台下被引用,前面的实验都没用到 platform,所以 pinctrl 配置是不起作用的!

  • 对于 STM32MP1 来说,在使用 pinctrl 的时候需要修改一下 pinctrl-stm32.c 这个文件。

  • 设备树问题

  • 新的设备节点获取方式

宏___一行代码创建 platform_driver

Linux 自带 LED 驱动使用如下一行代码创建一个平台驱动

module_platform_driver(gpio_led_driver);

展开:

static int __init gpio_led_driver_init(void) 
{ 
	return platform_driver_register (&(gpio_led_driver)); 
} 
module_init(gpio_led_driver_init); 
static void __exit gpio_led_driver_exit(void) 
{ 
	platform_driver_unregister (&(gpio_led_driver) ); 
} 
module_exit(gpio_led_driver_exit);

你可能感兴趣的:(arm,stm32,嵌入式硬件,c语言)