spi总线

时序

 

spi_master

SPI 主机驱动的核心就是申请 spi_master,然后初始化 spi_master(被赋值的tranfer函数,对于不同soc,寄存器不一样,这个就是soc厂商的驱动开发实现的),通过平台总线match上之后,执行probe--最后调用 spi_bitbang_start 函数(spi_bitbang_start 会调用spi_register_master 函数像内核注册spi_master

 

spi_driver

spi 设备驱动也和 i2c 设备驱动也很类似,Linux 内核使用 spi_driver 结构体来表示 spi 设备驱动,我们在编写 SPI 设备驱动的时候需要实现 spi_driver;spi_driver 注册函数为

spi_register_driver

 

spi_device

在注册spi_master的最后面,会注册spi_device,不管是spi_match_controller_to_boardinfo

调用 spi_new_device生成,还是设备树或者acpi

 

spi_message

spi_message包含一个队列节点。被spi_master的队列头节点相连,用于被master依次处理

 

spi_message有一个transfer链表头节点,链接一个spi_transfer链表

 

spi_message_init 函数初始化 spi_message;

spi_message_add_tail函数将前面设置好的spi_transfer添加到spi_message队列中;

spi_sync 函数完成SPI数据同步传输。

spidev

内核加载spidev.c是一个通用的spi驱动;可以通过这种形式加载

insmod spidev.ko busnum=0 chipselect=1 maxspeed=50000000

static int __init spidev_init(void)
{
    int status;

    /* Claim our 256 reserved device numbers.  Then register a class
     * that will key udev/mdev to add/remove /dev nodes.  Last, register
     * the driver which manages those device numbers.
     */
    BUILD_BUG_ON(N_SPI_MINORS > 256);
    status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
    if (status < 0)
        return status;

    spidev_class = class_create(THIS_MODULE, "spidev");
    if (IS_ERR(spidev_class)) {
        status = PTR_ERR(spidev_class);
        goto error_class;
    }

    status = spi_register_driver(&spidev_spi_driver);
    if (status < 0)
        goto error_register;

    if (busnum != -1 && chipselect != -1) {
        struct spi_board_info chip = {
                    .modalias    = "spidev",
                    .mode        = spimode,
                    .bus_num    = busnum,
                    .chip_select    = chipselect,
                    .max_speed_hz    = maxspeed,
        };

        struct spi_master *master;

        master = spi_busnum_to_master(busnum);
        if (!master) {
            status = -ENODEV;
            goto error_busnum;
        }

        /* We create a virtual device that will sit on the bus */
        spi = spi_new_device(master, &chip);
        if (!spi) {
            status = -EBUSY;
            goto error_mem;
        }
        dev_dbg(&spi->dev, "busnum=%d cs=%d bufsiz=%d maxspeed=%d",
            busnum, chipselect, bufsiz, maxspeed);
    }
    return 0;
error_mem:
error_busnum:
    spi_unregister_driver(&spidev_spi_driver);
error_register:
    class_destroy(spidev_class);
error_class:
    unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
    return status;
}
module_init(spidev_init);

总线对比

 

 

posted on 2022-03-10 20:28  lzd626  阅读(364)  评论(0编辑  收藏  举报