前言
前面的文章介绍了spi控制器驱动、spi设备驱动、spi应用层的读写操作,本文介绍spi的框架。
驱动文件路径
drivers/spi/spi.c,spi核心初始化、spi控制器驱动的注册、spi设备驱动的注册、spi的读写流程全部在此文件中实现。
spi核心初始化
static int __init spi_init(void)
{
int status;
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);//申请缓存,在spi_write_then_read中使用
if (!buf) {
status = -ENOMEM;
goto err0;
}
status = bus_register(&spi_bus_type);//spi总线注册,后续的spi设备的device和driver都指定spi_bus_type
if (status < 0)
goto err1;
status = class_register(&spi_master_class);//master class 注册
if (status < 0)
goto err2;
if (IS_ENABLED(CONFIG_SPI_SLAVE)) {
status = class_register(&spi_slave_class);//slave class注册
if (status < 0)
goto err3;
}
......
return 0;
}
postcore_initcall(spi_init);
spi核心的初始化完成了如下功能
- 缓存申请,在spi_write_then_read中使用
- spi总线注册,后续的spi设备的device add和driver register都需要指定spi_bus_type
- class 注册,主要在/sys/class/spi目录下创建一些文件
spi控制器驱动注册
int spi_register_controller(struct spi_controller *ctlr)
{
struct device *dev = ctlr->dev.parent;
struct boardinfo *bi;
int status;
int id, first_dynamic;
......
status = spi_controller_check_ops(ctlr);//在注册SPI控制器之前,确保实现了所有必要的钩子函数。
if (status)
return status;
if (ctlr->bus_num >= 0) {//初始化ctlr->bus_num = -1,不执行此条件语句
/* devices with a fixed bus num must check-in with the num */
mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
ctlr->bus_num + 1, GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id == -ENOSPC ? -EBUSY : id;
ctlr->bus_num = id;
} else if (ctlr->dev.of_node) {
/* allocate dynamic bus number using Linux idr */
id = of_alias_get_id(ctlr->dev.of_node, "spi");//若设备树的别名为spi1,则id=1
if (id >= 0) {
ctlr->bus_num = id;
mutex_lock(&board_lock);
id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
ctlr->bus_num + 1, GFP_KERNEL);
mutex_unlock(&board_lock);
if (WARN(id < 0, "couldn't get idr"))
return id == -ENOSPC ? -EBUSY : id;
}
}
if (ctlr->bus_num < 0) {
......
ctlr->bus_num = id;//bus_num赋值
}
......
//初始化队列、自旋锁、互斥锁、完成量
INIT_LIST_HEAD(&ctlr->queue);
spin_lock_init(&ctlr->queue_lock);
spin_lock_init(&ctlr->bus_lock_spinlock);
mutex_init(&ctlr->bus_lock_mutex);
mutex_init(&ctlr->io_mutex);
ctlr->bus_lock_flag = 0;
init_completion(&ctlr->xfer_completion);
if (!ctlr->max_dma_len)
ctlr->max_dma_len = INT_MAX;
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
*/
dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);//dev的name赋值
//从设备树中获取CS对应的GPIO,我们的设备树不涉及,不执行该条件语句
if (!spi_controller_is_slave(ctlr)) {
if (ctlr->use_gpio_descriptors) {
status = spi_get_gpio_descs(ctlr);
if (status)
goto free_bus_id;
/*
* A controller using GPIO descriptors always
* supports SPI_CS_HIGH if need be.
*/
ctlr->mode_bits |= SPI_CS_HIGH;
} else {
/* Legacy code path for GPIOs from DT */
status = of_spi_get_gpio_numbers(ctlr);
if (status)
goto free_bus_id;
}
}
/*
* Even if it's just one always-selected device, there must
* be at least one chipselect.
*/
if (!ctlr->num_chipselect) { //初始化num_chipselect = 1
status = -EINVAL;
goto free_bus_id;
}
status = device_add(&ctlr->dev);//spi控制器设备注册
if (status < 0)
goto free_bus_id;
dev_dbg(dev, "registered %s %s\n",
spi_controller_is_slave(ctlr) ? "slave" : "master",
dev_name(&ctlr->dev));
/*
* If we're using a queued driver, start the queue. Note that we don't
* need the queueing logic if the driver is only supporting high-level
* memory operations.
*/
if (ctlr->transfer) {
dev_info(dev, "controller is unqueued, this is deprecated\n");
} else if (ctlr->transfer_one || ctlr->transfer_one_message) {
status = spi_controller_initialize_queue(ctlr);//初始化队列
if (status) {
device_del(&ctlr->dev);
goto free_bus_id;
}
}
/* add statistics */
spin_lock_init(&ctlr->statistics.lock);
mutex_lock(&board_lock);
list_add_tail(&ctlr->list, &spi_controller_list);
list_for_each_entry(bi, &board_list, list)
spi_match_controller_to_boardinfo(ctlr, &bi->board_info);//不使用
mutex_unlock(&board_lock);
/* Register devices from the device tree and ACPI */
of_register_spi_devices(ctlr);//解析设备树,把spi控制器下的设备全部注册到内核
acpi_register_spi_devices(ctlr);//不使用
return status;
free_bus_id:
mutex_lock(&board_lock);
idr_remove(&spi_master_idr, ctlr->bus_num);
mutex_unlock(&board_lock);
return status;
}
status = spi_controller_check_ops(ctlr);//在注册SPI控制器之前,确保实现了所有必要的钩子函数。 Linux驱动开发 - spi子系统(1) spi master控制器驱动 我们实现了钩子函数master->transfer_one = mtk_spi_transfer_one;
由于我们在__spi_alloc_controller函数中初始化ctlr->bus_num = -1,所以执行第23行的条件语句,然后id = of_alias_get_id(ctlr->dev.of_node, "spi")获取id,若设备树的别名为spi1,则id=1,我们的设备树分别为spi0、spi1、spi2,所以对应的id分别为0、1、2;
第57~74行,从设备树中获取CS对应的GPIO,我们的设备树没有“cs”和"cs-gpios",不执行该条件语句;
第80行,初始化num_chipselect = 1,表示只有一个CS脚;
第85行,status = device_add(&ctlr->dev);//spi控制器设备注册,若为spi0,则在/sys/device/platform/../spi0
第100行,status = spi_controller_initialize_queue(ctlr);//初始化队列,会启动一个新的线程,用于后续的spi数据传输。
第116行,of_register_spi_devices(ctlr);//解析设备树,把spi控制器下的设备全部注册到内核.
of_register_spi_devices
static void of_register_spi_devices(struct spi_controller *ctlr)
{
struct spi_device *spi;
struct device_node *nc;
if (!ctlr->dev.of_node)
return;
for_each_available_child_of_node(ctlr->dev.of_node, nc) { //遍历所有子节点
if (of_node_test_and_set_flag(nc, OF_POPULATED))//设置标志
continue;
spi = of_register_spi_device(ctlr, nc);//注册spi设备
if (IS_ERR(spi)) {
dev_warn(&ctlr->dev,
"Failed to create SPI device for %pOF\n", nc);
of_node_clear_flag(nc, OF_POPULATED);
}
}
}
of_register_spi_device
static struct spi_device *
of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
{
struct spi_device *spi;
int rc;
spi = spi_alloc_device(ctlr); /* 申请spi_device */
......
rc = of_modalias_node(nc, spi->modalias, /* 解析设备树的compatible */
sizeof(spi->modalias));
......
rc = of_spi_parse_dt(ctlr, spi, nc);/* 解析设备树*/
......
rc = spi_add_device(spi); /*注册 spi device */
......
return spi;
......
}
spi_add_device
int spi_add_device(struct spi_device *spi)
{
struct spi_controller *ctlr = spi->controller;
struct device *dev = ctlr->dev.parent;
int status;
/*chip_select是解析设备树中reg得到的, */
if (spi->chip_select >= ctlr->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
ctlr->num_chipselect);
return -EINVAL;
}
/* 比如spi1.0 */
spi_dev_set_name(spi);
mutex_lock(&spi_add_lock);
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
if (status) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
goto done;
}
.......
status = spi_setup(spi);/*最终调用spi-mt65xx.c mtk中的spi_setup*/
......
/* spi 设备添加 */
status = device_add(&spi->dev);
......
return status;
}
spi设备驱动注册
#define spi_register_driver(driver) \
__spi_register_driver(THIS_MODULE, driver)
int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
{
sdrv->driver.owner = owner;
sdrv->driver.bus = &spi_bus_type;
sdrv->driver.probe = spi_drv_probe;
sdrv->driver.remove = spi_drv_remove;
if (sdrv->shutdown)
sdrv->driver.shutdown = spi_drv_shutdown;
return driver_register(&sdrv->driver);
}
首先设置总线spi_bus_type,probe函数spi_drv_probe,最终调用 driver_register注册设备驱动。
spi数据传输spi_sync
Linux驱动开发 - spi子系统(4) spi 设备驱动介绍了spi的读写过程,最终是调用spi_sync,如下
char tx_buffer[1024];
char rx_buffer[1024];
struct spi_transfer xfer = {
.tx_buf = tx_buffer,//指定发送buff
.rx_buf = rx_buffer,//指定接收buff
.len = len + 1, //指定数据长度
};spi_message_init(&msg);//初始化msg
spi_message_add_tail(&xfer, &msg);//add xfer到msg
spi_sync(smi230_gyro_device, &msg);//开始传输
spi_sync调用__spi_sync
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
int ret;
mutex_lock(&spi->controller->bus_lock_mutex);
ret = __spi_sync(spi, message);
mutex_unlock(&spi->controller->bus_lock_mutex);
return ret;
}
__spi_sync
static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);//定义一个完成量
int status;
struct spi_controller *ctlr = spi->controller;
unsigned long flags;
status = __spi_validate(spi, message);//参数有效性检查
if (status != 0)
return status;
message->complete = spi_complete;//完成量回调函数
message->context = &done;
message->spi = spi;
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);
/* If we're not using the legacy transfer method then we will
* try to transfer in the calling context so special case.
* This code would be less tricky if we could remove the
* support for driver implemented message queues.
*/
if (ctlr->transfer == spi_queued_transfer) {
spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);
trace_spi_message_submit(message);
status = __spi_queued_transfer(spi, message, false);//false表示不在新线程中执行
spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
} else {
status = spi_async_locked(spi, message);
}
if (status == 0) {
/* Push out the messages in the calling context if we
* can.
*/
if (ctlr->transfer == spi_queued_transfer) {
SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
spi_sync_immediate);
SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
spi_sync_immediate);
__spi_pump_messages(ctlr, false); //发送spi数据
}
wait_for_completion(&done);//等待完成量
status = message->status;
}
message->context = NULL;
return status;
}
__spi_pump_messages
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
{
struct spi_message *msg;
bool was_busy = false;
unsigned long flags;
int ret;
......
/* Check if the queue is idle */
if (list_empty(&ctlr->queue) || !ctlr->running) {//在其他线程中执行
if (!ctlr->busy) {
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return;
}
/* Only do teardown in the thread */
if (!in_kthread) {
kthread_queue_work(&ctlr->kworker,
&ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return;
}
ctlr->busy = false;
ctlr->idling = true;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
kfree(ctlr->dummy_rx);
ctlr->dummy_rx = NULL;
kfree(ctlr->dummy_tx);
ctlr->dummy_tx = NULL;
if (ctlr->unprepare_transfer_hardware &&
ctlr->unprepare_transfer_hardware(ctlr))
dev_err(&ctlr->dev,
"failed to unprepare transfer hardware\n");
if (ctlr->auto_runtime_pm) {
pm_runtime_mark_last_busy(ctlr->dev.parent);
pm_runtime_put_autosuspend(ctlr->dev.parent);
}
trace_spi_controller_idle(ctlr);
spin_lock_irqsave(&ctlr->queue_lock, flags);
ctlr->idling = false;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
return;
}
/* Extract head of queue */
msg = list_first_entry(&ctlr->queue, struct spi_message, queue);
ctlr->cur_msg = msg;
list_del_init(&msg->queue);
if (ctlr->busy)
was_busy = true;
else
ctlr->busy = true;
spin_unlock_irqrestore(&ctlr->queue_lock, flags);
mutex_lock(&ctlr->io_mutex);
if (!was_busy && ctlr->auto_runtime_pm) {
ret = pm_runtime_get_sync(ctlr->dev.parent);
if (ret < 0) {
pm_runtime_put_noidle(ctlr->dev.parent);
dev_err(&ctlr->dev, "Failed to power device: %d\n",
ret);
mutex_unlock(&ctlr->io_mutex);
return;
}
}
......
if (ctlr->prepare_message) {
ret = ctlr->prepare_message(ctlr, msg);//调用spi-mt65xx.c的mtk_spi_prepare_message
......
ctlr->cur_msg_prepared = true;//标志赋值
}
ret = spi_map_msg(ctlr, msg);
if (ret) {
msg->status = ret;
spi_finalize_current_message(ctlr);
goto out;
}
ret = ctlr->transfer_one_message(ctlr, msg);//调用spi_transfer_one_message
if (ret) {
dev_err(&ctlr->dev,
"failed to transfer one message from queue\n");
goto out;
}
out:
mutex_unlock(&ctlr->io_mutex);
/* Prod the scheduler in case transfer_one() was busy waiting */
if (!ret)
cond_resched();
}
调用关系为:
__spi_pump_messages
transfer_one_message
spi_transfer_one_message
transfer_one
mtk_spi_transfer_one
spi_transfer_one_message中spi_transfer_wait(ctlr, msg, xfer)等待,直到spi_finalize_current_transfer中complete(&ctlr->xfer_completion)退出,完成1次transfer传输
spi_transfer_one_message最后调用了spi_finalize_current_message,而此函数有mesg->complete(mesg->context),发送完成量,此时__spi_sync函数中的wait_for_completion(&done)结束等待,一次数据传输完成。
总结
spi.c文件是SPI子系统的核心文件之一,负责实现SPI设备的注册、注销、数据传输等功能,如下。
1. 结构体定义:spi.c文件中定义了一系列结构体,用于表示SPI总线、SPI设备等信息。包括struct spi_device、struct spi_driver等结构体,用于描述SPI设备和SPI驱动程序之间的关系。
2. 函数实现:spi.c文件中包含了一系列函数的实现,用于处理SPI设备的注册、注销、数据传输等操作。例如,spi_register_driver()函数用于注册SPI设备的驱动程序,spi_unregister_driver()函数用于注销SPI设备的驱动程序。
3. 设备操作:spi.c文件中定义了一系列函数,用于实现SPI设备的操作。包括spi_sync()函数用于进行数据传输,spi_setup()函数用于设置SPI设备的参数等。
4. 总线管理:spi.c文件还包含了一些函数,用于管理SPI总线的注册、注销等操作。例如,spi_register_master()函数用于注册SPI总线的主控制器,spi_unregister_master()函数用于注销SPI总线的主控制器。