平台总线开发笔记

设备驱动模型:bus, driver, device
struct bus_type :总线对象,描述一个总线,管理device和driver,完成匹配
struct bus_type {
    const char        *name;
    int (*match)(struct device *dev, struct device_driver *drv);
}
注册和注销
    int bus_register(struct bus_type *bus)
    void bus_unregister(struct bus_type *bus)


device对象:设备对象,描述设备信息,包括地址,中断号,甚至其他自定义的数据
struct device {
    struct kobject kobj;  //所有对象的父类
    const char        *init_name; 
    // 在总线中会有一个名字,用于做匹配,在/sys/bus/mybus/devices/名字
    struct bus_type    *bus; //指向该device对象依附于总线的对象
    void        *platform_data; // 自定义的数据,指向任何类型数据

注册和注销的方法:
    int device_register(struct device *dev)
    void device_unregister(struct device *dev)


driver对象:描述设备驱动的方法(代码逻辑)
struct device_driver {
    const char        *name;
    // 在总线中会有一个名字,用于做匹配,在/sys/bus/mybus/drivers/名字
    struct bus_type        *bus;//指向该driver对象依附于总线的对象
    int (*probe) (struct device *dev); // 如果device和driver匹配之后,driver要做的事情
    int (*remove) (struct device *dev); // 如果device和driver从总线移除之后,driver要做的事情
}
注册和注销:
    int driver_register(struct device_driver *drv)
    void driver_unregister(struct device_driver *drv)

如何实现总线匹配,匹配成功之后会自动调用driver的probe方法:
    1, 实现bus对象中 match方法
    2, 保证driver和device中名字要一样


====================================================================
平台总线模型:
    为什么会有平台总线:
        用于平台升级:三星: 2410, 2440, 6410, s5pc100  s5pv210  4412
            硬件平台升级的时候,部分的模块的控制方式,基本上是类似的
            但是模块的地址是不一样

            gpio控制逻辑: 1, 配置gpio的输入输出功能: gpxxconf
                           2, 给gpio的数据寄存器设置高低电平: gpxxdata
                        逻辑操作基本上是一样的
                        但是地址不一样
            
            uart控制:1,设置8n1,115200, no AFC
                        UCON,ULCON, UMODOEN, UDIV
                    
                    逻辑基本上是一样的
                    但是地址不一样
    
    问题:
        当soc升级的时候, 对于相似的设备驱动,需要编写很多次(如果不用平台总线)
        但是会有大部分重复代码

    解决:引入平台总线    
            device(中断/地址)和driver(操作逻辑) 分离
        在升级的时候,只需要修改device中信息即可(中断/地址)
        实现一个driver代码能够驱动多个平台相似的模块,并且修改的代码量很少
        

平台总线中的三元素:
1, bus
    platform_bus:不需要自己创建,开机的时候自动创建

    struct bus_type platform_bus_type = {
        .name        = "platform",
        .dev_groups    = platform_dev_groups,
        .match        = platform_match,
        .uevent        = platform_uevent,
        .pm        = &platform_dev_pm_ops,
    };
    匹配方法:
        1,优先匹配pdriver中的id_table,里面包含了支持不同的平台的名字
        2,直接匹配driver中名字和device中名字

        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);
        if (pdrv->id_table)// 如果pdrv中有idtable,平台列表名字和pdev中的名字
            return platform_match_id(pdrv->id_table, pdev) != NULL;

        /* fall-back to driver name match */
        return (strcmp(pdev->name, drv->name) == 0);

2,device对象:
    struct platform_device {
        const char    *name;  //用于做匹配
        int        id;  // 一般都是直接给-1
        struct device    dev; // 继承了device父类
        u32        num_resources; // 资源的个数
        struct resource    *resource; // 资源:包括了一个设备的地址和中断
    }
    注册和注销
        int  platform_device_register(struct platform_device * pdev);
        void  platform_device_unregister(struct platform_device * pdev)

3,driver对象
    struct platform_driver {
            int (*probe)(struct platform_device *); //匹配成功之后被调用的函数
            int (*remove)(struct platform_device *);//device移除的时候调用的函数
            struct device_driver driver; //继承了driver父类
                                |
                                const char        *name;
            const struct platform_device_id *id_table; //如果driver支持多个平台,在列表中写出来
    }
    注册和注销
        int platform_driver_register(struct platform_driver *drv);
        void platform_driver_unregister(struct platform_driver *drv)

==========================================
编写代码: 编写一个能在多个平台下使用的led驱动
1,注册一个platform_device,定义资源:地址和中断
            struct resource {
                resource_size_t start; // 开始
                resource_size_t end; //结束
                const char *name; //描述,自定义
                unsigned long flags; //区分当前资源描述的是中断(IORESOURCE_IRQ)还是内存(IORESOURCE_MEM)
                struct resource *parent, *sibling, *child;
            };

2,注册一个platform_driver,实现操作设备的代码
        注册完毕,同时如果和pdev匹配成功,自动调用probe方法:
                probe方法: 对硬件进行操作
                        a,注册设备号,并且注册fops--为用户提供一个设备标示,同时提供文件操作io接口
                        b, 创建设备节点
                        c, 初始化硬件
                                    ioremap(地址);  //地址从pdev需要获取
                                    readl/writle();
                        d,实现各种io接口: xxx_open, xxx_read, ..
            获取资源的方式:        
            //获取资源
            // 参数1: 从哪个pdev中获取资源
            // 参数2:  资源类型
            // 参数3: 表示获取同种资源的第几个
                struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)

猜你喜欢

转载自blog.csdn.net/weixin_39148042/article/details/82495343