版权声明:本文为博主原创文章,任何组织或者个人可以在任何媒介上发表或转载我的文章、图片等.且转载后必须注明出处和邮箱,博客地址(https://blog.csdn.net/u011011827),本人邮箱([email protected]) https://blog.csdn.net/u011011827/article/details/89421832
platform 设备
- 匹配
drivers/base/platform.c platform_match 函数
static int platform_match(struct device *dev, struct device_driver *drv);
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
1. 前提
目前我们都用设备树,并解析设备树并创建设备贺电,这样子得到的 pdev->name 为设备节点名
pdev->driver_override 为 NULL
2. 5种匹配方式
2.1
pdev->driver_override // 对于这一种,为NULL,肯定是不进入的
2.2
OF // 匹配内容 为 compatible 和 .driver.of_match_table[0].compatible 这种匹配方式为多多(两方都可以写多个字符串)匹配,只要有一个匹配上就算成功
2.3
ACPI // 貌似被淘汰了,只是兼容
2.4
pdrv->id_table // id_table->name 和 pdev->name 匹配, 为单单匹配,且匹配的只能为 节点名.
platform_match_id(pdrv->id_table, pdev)
2.5
(strcmp(pdev->name, drv->name) // pdev->name, drv->name 匹配 ,单单匹配,且只能是节点名
2.2 举例
// 驱动端
static const struct of_device_id ids[] = {
{ .compatible = "chip-name"},
{ .compatible = "chip-name2"},
{ }, // 一定要有
};
struct platform_driver pdr =
{
.driver=
{
.name = "somethingSUIBIAN_BUT_MUST_HAVE",
.of_match_table = ids, // 匹配关键
}
.id_table = &p_id_table,
.probe = pdr_probe,
.remove = pdr_remove,
}
platform_driver_register(&pdr);
// 设备端
node-platform-node {
compatible = "vendor-name", "chip-name", "chip-name2","chip-name3";// 匹配关键
}
2.4 举例
// 驱动端
static const struct platform_device_id p_id_table = {
.name = "node-platform-node", //匹配关键
};
struct platform_driver pdr =
{
.driver=
{
.name = "somethingSUIBIAN_BUT_MUST_HAVE",
}
.id_table = &p_id_table,
.probe = pdr_probe,
.remove = pdr_remove,
}
platform_driver_register(&pdr);
// 设备端
node-platform-node { // 匹配关键
compatible = "somethingSUIBIAN_BUT_MUST_HAVE";
}
2.5 举例
// 驱动端
static const struct platform_device_id p_id_table = {
.name = "node-platform-node", //匹配关键
};
struct platform_driver pdr =
{
.driver=
{
.name = "node-platform-node", // 匹配关键
}
.probe = pdr_probe,
.remove = pdr_remove,
}
platform_driver_register(&pdr);
// 设备端
node-platform-node { // 匹配关键
compatible = "somethingSUIBIAN_BUT_MUST_HAVE";
}
- 命令行传参
//传参处
chosen {
bootargs = "node-platform-file.num=100"
};
//定义处
node-platform-file.c 文件中
static int num=10; // 初始化为10,在启动过程中被修改为100
module_param(num,int,S_IRUGO);
// 修改处
kernel/params.c
parse_one
params[i].ops->set(val, ¶ms[i]); // 修改num为 100
- sys 节点
driver 目录
/sys/bus/platform/drivers/xxx //xxx 为 pdr.driver.name
/sys/devices/platform/yyy // yyy 为 设备节点名
sysfs_create_group(&pdev->dev.kobj, &sysfs_demo_attr_group) // 在 /sys/devices/platform/yyy
- 相互获取
从pdev 到 其他
int pdr_probe(struct platform_device * pdev);
获取 dev :pdev->dev
获取 设备树节点 : pdev->dev.of_node
获取驱动 : pdev->dev->driver
从 dev 到其他
struct platform_device *pdev = to_platform_device(dev);
从 drv 到其他
struct platform_driver *pdrv = to_platform_driver(drv);
- pdev 结构体变量
int pdr_probe(struct platform_device * pdev);
name:node-platform-node
id:-1
id_auto:0
num_resources:1
resources:9f59f240
id_entry: (null) // %p为 (null)// 前面有两个空格
driver_override: (null)
- driver sys 目录
/sys/bus/platform/drivers/xxx #
--w------- 1 0 0 4096 Apr 20 10:30 bind // 用来加载驱动 // /sys/devices/platform 下面的文件夹的名字 ,如果加载之后,没有显示出yyy,表示没有匹配到设备
lrwxrwxrwx 1 0 0 0 Apr 20 10:30 yyy -> ../../../../devices/platform/yyy // 匹配的设备名及设备目录 //如果没有此文件,代表该驱动没有匹配到设备
--w------- 1 0 0 4096 Apr 20 10:30 uevent // 传入 add ,用来执行 udevd 规则
--w------- 1 0 0 4096 Apr 20 10:30 unbind // 用来卸载驱动 写入设备名(当前目录下的yyy)
- device sys 目录
/sys/devices/platform/yyy/:
total 0
lrwxrwxrwx 1 0 0 0 Apr 20 10:30 driver -> ../../../bus/platform/drivers/xxx // 已经匹配到驱动,驱动目录
-rw-r--r-- 1 0 0 4096 Apr 20 10:30 driver_override // pdev->driver_override 为 (null)
-r--r--r-- 1 0 0 4096 Apr 20 10:30 modalias // of:Nnode-platform-nodeT<NULL>Cvendor-nameCchip-nameCchip-name2Cchip-name3 // 设备节点名及 compatible 属性值
-rw-r--r-- 1 0 0 4096 Apr 20 10:30 node_one // sysfs_create_group 节点
-r--r--r-- 1 0 0 4096 Apr 20 10:30 node_two // sysfs_create_group 节点
drwxr-xr-x 2 0 0 0 Apr 20 10:30 power // power 目录,power 相关
lrwxrwxrwx 1 0 0 0 Apr 20 10:30 subsystem -> ../../../bus/platform // 隶属总线
-rw-r--r-- 1 0 0 4096 Apr 20 10:30 uevent // 设备下面的这个uevent 属性是干什么的 drivers/base/core.c 中的 uevent_store // 估计也是用来测试 udevd 规则的
//# cat uevent
//DRIVER=noneed_to_fill_in
//OF_NAME=node-platform-node
//OF_FULLNAME=/node-platform-node
//OF_COMPATIBLE_0=vendor-name
//OF_COMPATIBLE_1=chip-name
//OF_COMPATIBLE_2=chip-name2
//OF_COMPATIBLE_3=chip-name3
//OF_COMPATIBLE_N=4
//MODALIAS=of:Nnode-platform-nodeT<NULL>Cvendor-nameCchip-nameCchip-name2Cchip-name3
/sys/devices/platform/yyy/power:
total 0
-rw-r--r-- 1 0 0 4096 Apr 20 10:31 autosuspend_delay_ms
-rw-r--r-- 1 0 0 4096 Apr 20 10:31 control
-r--r--r-- 1 0 0 4096 Apr 20 10:31 runtime_active_time
-r--r--r-- 1 0 0 4096 Apr 20 10:31 runtime_status
-r--r--r-- 1 0 0 4096 Apr 20 10:31 runtime_suspended_time
- 去初始化测试
/sys/bus/platform/drivers/xxx 下面有 bind yyy unbind 表示已经匹配成功
可以通过 echo yyy > unbind 来卸载驱动
然后再 echo yyy > bind 来加载驱动
如果没有什么问题(不会有错误堆栈打出来,不会死机),基本上去初始化是ok的
- 私有数据的存放
// 设置 s2mps11_clks 的数据指向
s2mps11_clks->pdev = pdev;
// 从 s2mps11_clks get 到 pdev
struct platform_device * pdev = s2mps11_clks->pdev
---
// 设置 pdev 的私有数据
platform_set_drvdata(pdev, s2mps11_clks);
// 拿 pdev 的私有数据
struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev);