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);
总线对比