文章目录
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-gpio" }, { /* Sentinel */ } }; /* 声明 inputkey_of_match 设备匹配表 */ MODULE_DEVICE_TABLE(of, xxx_of_match); /* * platform 平台驱动结构体 */ static struct platform_driver xxx_driver = { .driver = { .name = "xxx-gpio", .of_match_table = xxx_of_match, }, .probe = xxx_probe, .remove = xxx_remove, };
-
probe 和 remove 的实现
/* 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("led device released!\r\n"); } /* 设备资源,xxx 所用寄存器信息 */ static struct resource led_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);