关于linux驱动开发中的platform设备驱动模型介绍

本文探讨了Linux下平台设备驱动的分隔与分层策略,强调了通过I2C总线驱动和统一接口API简化驱动开发,介绍了platform_driver与platform_device的概念,并通过实例展示了如何创建平台驱动框架及配合设备树。驱动分层让开发更高效,设备信息独立于驱动,利用bus_type和platform总线进行管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

介绍linux的platform设备驱动(平台设备驱动)

Linux驱动的分离与分层

驱动的分隔和分离

如果对驱动不进行分隔和分离,则会产生以下影响,如表。

主机驱动设备驱动
A平台主机驱动MPU6050驱动
B平台主机驱动MPU6050驱动
C平台主机驱动MPU6050驱动

在三个平台A,B,C上均要编写MOU6050驱动,那么此时就要编写三个不同的设备驱动,因此我们可以通过一个统一的接口(主机驱动),每个设备也只提供一个驱动程序(设备驱动),每个设备通过统一的I2C接口驱动来访问,这样就可以大大简化驱动文件。

主机驱动核心层设备驱动
A平台I2C主机驱动统一接口APII2C设备1(MPU驱动)
B平台I2C主机驱动统一接口APII2C设备2)
C平台I2C主机驱动统一接口APII2C设备3

这样就实现了驱动的分隔,也就是将主机驱动和设备驱动层分割开来,比如I2C和SPI等等都会采用驱动分隔的方式来简化驱动的开发。实际驱动开发中。主机驱动半导体厂家编写好了,设备驱动也由设备器件的厂家编写好了,我们只需要提供设备信息,比如I2C设备的话提供设备连接到了哪个I2C接口上,I2C的速度是多少等等。相当于将设备信息从设备驱动中剥离开来,驱动使用标准方法去获取到设备信息(设备树),也就是驱动负责驱动,设备负责设备。这就是Linux中的总线,驱动,设备模型,如下。

驱动总线设备信息
驱动1总线设备1
驱动2总线设备2
驱动3总线设备3

驱动的分层

linux驱动是分层的,分层的目的是为了在不同的层处理不同的内容。

platform平台驱动模型简介

由于soc中有些外设是没有总线这个概念,但是又要使用到总线,驱动和设备模型。为此,linux提出了platform这个虚拟总线,相应就有platform_driver 和 platform_device。

platform 总线

linux系统内核使用bus_type结构体表示总线,此结构体定义在文件include/linux/device.h

驱动和设备匹配方法有四种

  1. of类型匹配。
  2. ACPI匹配方式
  3. id_table匹配
  4. 驱动和设备的name字段匹配

platform驱动

platform_driver结构体表示platform驱动,定义在文件include/linux/platform_device.h

struct platform_driver{
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    int (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *,pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
    bool prevent_deferred_probe;
};

probe函数,驱动与设备匹配成功后Probe函数就会执行,非常重要的函数。
driver成员,为device_driver结构体变量,device_driver相当于基类,提供了最基础的驱动框架。platform_driver继承了这个基类,然后在此基础上又添加了一些特有的成员变量。

编写platform驱动的时候,首先定义一个platform_driver结构体变量,然后实现结构中的各个成员变量,重点是实现匹配方法和probe函数。当驱动和设备匹配成功后probe函数就会执行。当我们定义好platform_driver结构体变量以后,需要在驱动入口函数里面调用platform_driver_register函数向linux内核注册一个platform驱动,同样需要在驱动卸载函数中通过platform_driver_unregister函数卸载platform驱动。

这里写一个platform驱动框架

/**
*platform驱动并不是独立于字符设备驱动,块设备驱动,网络设备驱动
*/
struct xxx_dev{
    struct cdev cdev;
    /* 设备结构体其他具体内容 */
};

struct xxx_dev xxxdev;      //设备实例化

static int xxx_open(struct inode *inode,struct file *filp){
    return 0;
}

static int xxx_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt){
    return 0;
}

//字符设备驱动操作集
static struct file_operations xxx_fops ={
    .owner = THIS_MODULE,
    .open = xxx_open,
    .write = xxx_write,
};

/**
*platform驱动的probe函数
*驱动与设备匹配成功以后此函数就会执行
*/
static int xxx_probe(struct platform_device *dev){
    cdev_init(&xxxdev.cdev,&xxx_fops);      /* 注册字符驱动设备 */
    return 0;
}

static int xxx_remove(struct platform_device *dev){
    cdev_del(&xxxdev.cdev)'
    return 0;
}

/* 匹配列表 */
static const struct of_device_id xxx_of_match[] = {
    {.compatible = "xxx-gpio"},
    {/* Sentinel */}
};

/**
*platform平台驱动结构
*/
static struct platform_driver xxx_driver = {
    .driver = {
        .name = "xxx",
        .of_match_table = xxx_of_match,
    },
    .probe = xxx_probe,
    .remove = xxx_remove,
};

/* 驱动模块加载 */
static int __init xxxdriver_init(void){
    return platform_driver_register(&xxx_driver);
}

/* 驱动模块卸载 */
static int __exit xxxdriver_exit(void){
    platform_driver_unregister(&xxx_driver);
}

module_init(xxxdriver_init);
module_exit(xxxdriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Domic");

platform设备

platform 驱动写好后还需要platform设备,否则单单一个驱动也做不了什么。如果支持设备树就不用使用platform_device来描述设备,因为改用设备树去描述了,

platform_device这个结构体表示platform设备

platform_device结构体定义在文件include/linux/platform_device.h

struct platform_device{
    const char *name;
    int id;
    bool id_auto;
    struct device dev;
    u32 num_resources;
    struct resource *resource;
    
    const char platform_device_id *id_entry;
    char *driver_override;

    struct mfd_cell *mfd_cell;
    struct pdev_archdate archdata;
};

/* 资源resource */
static struct resource xxx_resources[] = {
    [0] = {
        .start = PERIPH1_REGISTER_BASE,
        .end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1),
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = PERIPH2_REGISTER_BASE,
        .end = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1),
        .flags = IORESOURCE_MEM,
    },
};

static struct platform_device xxxdevice = {
    .name = "xxx-gpio",         // 和platform_driver 的name 要匹配
    .id = -1;
    .num_resources = ARRAY_SIZE(xxx_resources),
    .resource = xxx_resources,
};

/* 设备模块加载 */
static int __init xxxdevice_init(void){
    return platform_driver_register(&xxxdevice);
}

/* 设备模块卸载 */
static int __exit xxxdevice_exit(void){
    platform_driver_unregister(&xxxdevice);
}

module_init(xxxdevice_init);
module_exit(xxxdevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Domic");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值