Linux SPI驱动框架理解

linux对spi、I2C、USB等子系统使用分离设计思想:主机驱动和外设驱动分离,主机只负责产生总线上的输出波形,外设通过标准接口让主机已适当的波形访问自己。
1. 主机驱动
2. 主机与外设的连接
3. 外设驱动
4. 板级逻辑

spi控制器驱动
spi_master描述一个spi主机控制器驱动

spi设备驱动
spi_driver描述一个spi外设驱动

spi_transfer
描述spi总线数据传输

spi_message
spi_message是对spi_transfer进行组织,将spi_message加入spi_message队列中

---------------------------------------------------------------------------------------------------

SPI驱动理解:
SPI子系统从上到下分为:spi设备驱动层,核心层和master驱动层。其中master驱动抽象出spi控制器的相关操作,而spi设备驱动层抽象出了用户空间API。
platform_device结构中描述了SPI控制器的相关资源,同时在板级信息中将会添加spi设备的相关信息。master驱动将以platform_driver形式体现出来,也就是说
在主控制器(master)和主控制器驱动将挂载到platform总线上。platform_driver的probe函数中将注册spi_master,同时将会获取在板级信息中添加的spi设备,将该
信息转换成spi_device,然后注册spi_device到spi总线上。spi_driver结构用于描述spi设备驱动,也将挂载到spi总线上。连同spi_driver一起注册的是字符设备,该
字符设备将提供5个API给用户空间。通过API,用户空间可以执行半双工读、半双工写和全双工读写。

SPI驱动框架可以分为SPI核心层、SPI控制器驱动层、SPI设备驱动层

SPI核心层(SPI总线层):
    SPI核心层负责注册SPI总线,主要定义了总线类型和主控制器设备类

    总线类型:
        struct bus_type spi_bus_type = {
            .name        = "spi",
            .dev_attrs    = spi_dev_attrs,
            .match        = spi_match_device,
            .uevent        = spi_uevent,
            .pm        = &spi_pm,
        };
        SPI总线类型,通过bus_register()函数,将SPI总线注册进总线,成功注册后在sys/bus下即可找到spi节点

        // spi总线注册过程
        postcore_initcall(spi_init);
            spi_init(void)
                bus_register(&spi_bus_type);            //注册spi总线
                
        成功注册后在sys/bus下即可找到spi节点

        spi_bus_type中的spi_match_device函数负责匹配spi总线上的device和driver    
        static int spi_match_device(struct device *dev, struct device_driver *drv)
        {
            const struct spi_device    *spi = to_spi_device(dev);
            const struct spi_driver    *sdrv = to_spi_driver(drv);

            /* Attempt an OF style match */
            if (of_driver_match_device(dev, drv))
                return 1;

            if (sdrv->id_table)
                return !!spi_match_id(sdrv->id_table, spi);

            return strcmp(spi->modalias, drv->name) == 0;
        }
        
    控制器设备类:
        static struct class spi_master_class = {
            .name        = "spi_master",
            .owner        = THIS_MODULE,
            .dev_release    = spi_master_release,
        };
        主要定义了SPI总线主控制器的设备类,通过调用class_register()函数注册设备类,成功注册后,在/sys/class目录下即可找到spi_master文件节点。

        // spi MASTER
        postcore_initcall(spi_init);
            spi_init(void)
                bus_register(&spi_bus_type);            //注册spi总线
                    class_register(&spi_master_class);  //class_register()函数注册设备类,成功注册后,在/sys/class目录下即可找到spi_master文件节点。
        
SPI控制器驱动层
    struct spi_master
    问:struct spi_master谁会用到?
    答:用到spi_master的代码基本都在内核drivers\spi目录下,drivers\spi目录下是各类spi主控制驱动实现

    对driver\spi\spi_s3c24xx.c进行分析
    定义s3c24xx_spi_driver:
        static struct platform_driver s3c24xx_spi_driver = {
            .remove        = __exit_p(s3c24xx_spi_remove),
            .driver        = {
                .name    = "s3c2410-spi",
                .owner    = THIS_MODULE,
                .pm    = S3C24XX_SPI_PMOPS,
            },
        };
    
    主控制器驱动注册到platform总线
    s3c24xx_spi_init
        platform_driver_probe(struct platform_driver *drv, int (*probe)(struct platform_device *))
            platform_driver_register(struct platform_driver *drv)


    SPI主控制机设备注册到platform总线
        在arch\arm\plat-s3c24xx\devs.c中,定义了platform_device设备s3c_device_spi0
            struct platform_device s3c_device_spi0 = {
                .name          = "s3c2410-spi",
                .id          = 0,
                .num_resources      = ARRAY_SIZE(s3c_spi0_resource),
                .resource      = s3c_spi0_resource,
                    .dev              = {
                            .dma_mask = &s3c_device_spi0_dmamask,
                            .coherent_dma_mask = 0xffffffffUL
                    }
            };

        s3c_device_spi0加入到arch\arm\plat-s3c24xx\mach-nexcoder.c中的struct platform_device *nexcoder_devices[]数组中
            static struct platform_device *nexcoder_devices[] __initdata = {
                ....
                &s3c_device_spi0,
                ....
            };
            nexcoder_devices[]被同文件中的nexcoder_init调用,nexcoder_init再调用platform_add_devices加入到platform总线上。
            
SPI设备驱动层
    在外设驱动实现中调用spi_register_driver(struct spi_driver *sdrv),向spi总线挂载spi_driver,该函数在drivers\spi\spi.c中实现
    如:
    static struct spi_driver mc33880_driver = {
        .driver = {
            .name        = DRIVER_NAME,
            .owner        = THIS_MODULE,
        },
        .probe        = mc33880_probe,
        .remove        = __devexit_p(mc33880_remove),
    };
    在mc33880_init中调用spi_register_driver(&mc33880_driver)将mc33880_driver注册到spi总线,向struct spi_driver的probe接口传入对应的mc33880_probe函数
    调用过程如下:
    mc33880_init(void)
        spi_register_driver(&mc33880_driver);
            driver_register(&sdrv->driver);
                bus_add_driver(drv);
                    driver_attach(drv);
                        bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
                            driver_match_device(drv, dev) // 调用spi总线spi_bus_type中的math函数
                            driver_probe_device(drv, dev);
                                really_probe(dev, drv)
                                    dev->bus->probe(dev) 或者 drv->probe(dev);

SPI外设注册

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值