Linux驱动SPI-3-注册流程spi4
首先是gpio模拟的spi注册:
1.注册SPI总线类型和注册对应类。
[ 0.308540] spi_init: entered [ 0.308701] SPI bus type 'spi' registered [ 0.308768] SPI master class 'spi_master' registered对应代码:
static int __init spi_init(void) { int status; printk(KERN_INFO "spi_init: entered\n"); buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); if (!buf) { status = -ENOMEM; goto err0; } //注册 SPI 总线类型 status = bus_register(&spi_bus_type); if (status < 0) goto err1; printk(KERN_INFO "SPI bus type '%s' registered\n", spi_bus_type.name); //注册 SPI master类 status = class_register(&spi_master_class); if (status < 0) goto err2; printk(KERN_INFO "SPI master class '%s' registered\n", spi_master_class.name); /* 热插拔: 根据内核配置选项, 有条件地注册动态重新配置通知器,以便 SPI 子系统能够响应设备树(Device Tree) 或 ACPI 表的动态变化。*/ if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); if (IS_ENABLED(CONFIG_ACPI)) WARN_ON(acpi_reconfig_notifier_register(&spi_acpi_notifier)); return 0; err2: bus_unregister(&spi_bus_type); err1: kfree(buf); buf = NULL; err0: return status; }2.内核解析设备树,找到匹配的驱动后,调用probe
从设备树往下数,首先注册的是spi4:
设备树是:
spi4 { compatible = "spi-gpio"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi4>; pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>; status = "okay"; gpio-sck = <&gpio5 11 0>; gpio-mosi = <&gpio5 10 0>; cs-gpios = <&gpio5 7 0>; num-chipselects = <1>; #address-cells = <1>; #size-cells = <0>; gpio_spi: gpio_spi@0 { compatible = "fairchild,74hc595"; gpio-controller; #gpio-cells = <2>; reg = <0>; registers-number = <1>; registers-default = /bits/ 8 <0x57>; spi-max-frequency = <10000>; }; };总线上挂载的只有一个74hc595,查了一下是扩展引脚的。没有输入,设备上也没配置输入。
static struct platform_driver spi_gpio_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(spi_gpio_dt_ids), }, .probe = spi_gpio_probe, .remove = spi_gpio_remove, }; static const struct of_device_id spi_gpio_dt_ids[] = { { .compatible = "spi-gpio" }, {} };static int spi_gpio_probe(struct platform_device *pdev)这个函数大体干了什么:
从设备树节点中获取 GPIO 引脚配置并申请资源,配置master结构体各种标志位和回调函数
[ 2.302414] spi_gpio spi4: gpio-miso property not found, switching to no-rx mode [ 2.310158] spi_gpio spi4: spi_alloc_master enter! [ 2.315209] spi_master (null): spi_bitbang_start: entered (bus_num=-1)master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +
(sizeof(unsigned long) * num_devices));
/* 相当于注册spi master设备:把回调函数都设置好,然后注册设备 */ int spi_bitbang_start(struct spi_bitbang *bitbang)bitbang_start继续配置master各种回调函数,然后注册主设备spi_register_master。
此时还没分配总线。
3.分配主线,然后根据配置好的结构体注册主设备
int spi_register_master(struct spi_master *master) { static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); struct device *dev = master->dev.parent; struct boardinfo *bi; int status = -ENODEV; int dynamic = 0; if (!dev) return -ENODEV; dev_info(&master->dev,"is master->dev\n"); dev_info(dev,"is master->dev.parent\n"); dev_info(&master->dev, "spi_register_master: entered\n"); /* 解析设备树节点中的 cs-gpios 属性, 并将这些 GPIO 信息保存到 struct spi_master 中*/ status = of_spi_register_master(master); if (status) return status; dev_info(&master->dev, "cs-gpios get %d!\n",master->num_chipselect); /* even if it's just one always-selected device, there must * be at least one chipselect 如果没有片选引脚,直接报错 */ if (master->num_chipselect == 0) return -EINVAL; /* 静态分配:有设备节点且没有总线编号:分配一个 spiX的X*/ if ((master->bus_num < 0) && master->dev.of_node) master->bus_num = of_alias_get_id(master->dev.of_node, "spi"); dev_info(&master->dev, "master->bus_num get! %d \n", master->bus_num); /* convention: dynamically assigned bus IDs count down from the max 按照惯例,动态分配的总线 ID(bus_num)从最大值开始向下递减。 */ if (master->bus_num < 0) { /* FIXME switch to an IDR based scheme, something like * I2C now uses, so we can't run out of "dynamic" IDs 这是一个待改进的注释(FIXME),建议将来改用 IDR(ID 分配器)机制, 类似于 I2C 子系统现在的做法,这样可以避免“动态 ID”耗尽的问题 */ master->bus_num = atomic_dec_return(&dyn_bus_id); dynamic = 1; } /* 将 master->queue 初始化为一个空的双向循环链表头。*/ INIT_LIST_HEAD(&master->queue); /* 初始化一个自旋锁 queue_lock,用于保护对 master->queue 的并发访问。 初始化一个自旋锁 bus_lock_spinlock,用于保护 SPI 总线的短时原子访问。*/ spin_lock_init(&master->queue_lock); spin_lock_init(&master->bus_lock_spinlock); /* 初始化互斥锁 */ mutex_init(&master->bus_lock_mutex); mutex_init(&master->io_mutex); master->bus_lock_flag = 0; init_completion(&master->xfer_completion); /* 如果设备树没设置DMA最大长度,设置成默认最大 */ if (!master->max_dma_len) master->max_dma_len = INT_MAX; /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ /* 改名:这里将设备名格式化为 spi0 */ dev_info(&master->dev, "will be renamed \n"); dev_set_name(&master->dev, "spi%u", master->bus_num); dev_info(&master->dev, "is new name \n"); /* 将device注册到设备模型中 */ status = device_add(&master->dev); if (status < 0) goto done; dev_info(&master->dev, "has been device_add \n"); /* 注册成功后,使用 dev_dbg 输出调试日志,记录已注册的主控制器名称*/ dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), dynamic ? " (dynamic)" : ""); dev_info(dev, "registered master %s%s\n", dev_name(&master->dev), dynamic ? " (dynamic)" : ""); /* If we're using a queued driver, start the queue */ /* 判断驱动类型并初始化传输队列 */ if (master->transfer) dev_info(dev, "master is unqueued, this is deprecated\n"); else { /* 启动队列机制 */ status = spi_master_initialize_queue(master); if (status) { device_del(&master->dev); goto done; } } /* add statistics 统计信息锁 记录该控制器的传输次数、字节数、错误计数等运行时统计信息 */ spin_lock_init(&master->statistics.lock); /* 板级描述(非设备树)的 SPI 从设备注册机制:自旋锁 */ mutex_lock(&board_lock); /* 将当前 SPI 主控制器添加到全局链表 spi_master_list 中 */ list_add_tail(&master->list, &spi_master_list); /* 历 board_list,该链表保存了通过传统板级代码 注册的 SPI 从设备信息(struct boardinfo*/ list_for_each_entry(bi, &board_list, list) /* 老方式注册从设备: 对每个板级信息,调用该函数检查当前 master 是否匹配 该从设备所指定的 SPI 总线号.如果匹配,注册一个动态从设备(绑定)*/ spi_match_master_to_boardinfo(master, &bi->board_info); mutex_unlock(&board_lock); /* Register devices from the device tree and ACPI 新方式注册从设备: 从设备树 和 ACPI 表中注册 SPI 从设备 */ of_register_spi_devices(master); acpi_register_spi_devices(master); done: return status; }[ 2.321785] spi_master (null): is master->dev [ 2.326244] spi_gpio spi4: is master->dev.parent [ 2.330906] spi_master (null): spi_register_master: entered [ 2.336566] spi_master (null): of_spi_register_master enter! [ 2.342391] spi_master (null): cs-gpios get 1! [ 2.346935] spi_master (null): master->bus_num get! -19 /* 总线设备没有设置,所以转入动态分配了 */ [ 2.352289] spi_master (null): will be renamed [ 2.357004] spi_master spi32766: is new name [ 2.362151] spi_master spi32766: has been device_add /* 这步注册完后就能看见spi4设备了 */ [ 2.367327] spi_gpio spi4: registered master spi32766 (dynamic)4.初始化spi master的消息队列机制,开启队列
[ 2.373290] spi_master spi32766: spi_master_initialize_queue enter! [ 2.379737] spi_master spi32766: set spi_transfer_one_message! [ 2.386026] spi_master spi32766: spi_init_queue! [ 2.390786] spi_master spi32766: spi_start_queue enter! [ 2.396304] spi_master spi32766: put pump_messages to kworker!/* 初始化spi master的消息队列机制 */ static int spi_master_initialize_queue(struct spi_master *master) { int ret; dev_info(&master->dev, "spi_master_initialize_queue enter! \n"); master->transfer = spi_queued_transfer;//传输函数 if (!master->transfer_one_message) /* 硬件层传输函数 */ master->transfer_one_message = spi_transfer_one_message; dev_info(&master->dev, "set spi_transfer_one_message! \n"); /* Initialize and start queue 初始化队列数据结构 */ ret = spi_init_queue(master); if (ret) { dev_err(&master->dev, "problem initializing queue\n"); goto err_init_queue; } dev_info(&master->dev, "spi_init_queue! \n"); master->queued = true;//成功初始化标志 ret = spi_start_queue(master);//启动队列,启动失败就删除 if (ret) { dev_err(&master->dev, "problem starting queue\n"); goto err_start_queue; } return 0; err_start_queue: spi_destroy_queue(master); err_init_queue: return ret; } /* 开启工作线程:上锁,变量置位,开锁,把pump_messages工作扔给kworker*/ static int spi_start_queue(struct spi_master *master) { unsigned long flags; dev_info(&master->dev, "spi_start_queue enter! \n"); spin_lock_irqsave(&master->queue_lock, flags); if (master->running || master->busy) { spin_unlock_irqrestore(&master->queue_lock, flags); return -EBUSY; } master->running = true; master->cur_msg = NULL; spin_unlock_irqrestore(&master->queue_lock, flags); kthread_queue_work(&master->kworker, &master->pump_messages); dev_info(&master->dev, "put pump_messages to kworker! \n"); return 0; }至此主设备注册和初始化所有需要配置的东西都配完了,下面是从设备树解析然后注册从设备。
5.查找设备树并注册从设备spi_device
[ 2.402274] spi_master spi32766: of_register_spi_devices enter! [ 2.408389] spi_master spi32766: of_register_spi_device enter! /* 这个函数中spi_add_device注册从设备然后等待驱动匹配 */ [ 2.414675] spi_master spi32766: find modalias for /spi4/gpio_spi@0 [ 2.420991] spi_master spi32766: /spi4/gpio_spi@0 has 'reg' property (0) spi->chip_select is 0 [ 2.429714] spi_master spi32766: /spi4/gpio_spi@0 has spi-max-frequency is 10000/spi4/gpio_spi@0 就是驱动匹配的名字
reg就是片选名,从设备树上的reg取到,片选0
还有一些模式配置:clock phase/polarity,UAL/QUAD mode这些,还有频率
把这些都配置完就进入spi_add_device,往spi4虚拟总线上添加从设备。
注册从设备函数:
int spi_add_device(struct spi_device *spi)在新建设备前要保证这个片选没有其他设备使用。设置好片选后使用spi_setup新建设备。
[ 2.437227] spi spi32766.0: spi_setup: entered [ 2.441718] spi spi32766.0: spi_gpio_setup: entered [ 2.446710] spi spi32766.0: spi_bitbang_setup: entered [ 2.451890] spi spi32766.0: spi_bitbang_setup_transfer: entered [ 2.457906] spi spi32766.0: spi_bitbang_setup, 100000 nsec/bit [ 2.463848] spi spi32766.0: setup mode 0, 8 bits/w, 10000 Hz max --> 0 /* dev_info(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n", (int) (spi->mode & (SPI_CPOL | SPI_CPHA)), (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "", (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "", (spi->mode & SPI_3WIRE) ? "3wire, " : "", (spi->mode & SPI_LOOP) ? "loopback, " : "", spi->bits_per_word, spi->max_speed_hz, status); */spi_setup:对一个 SPI 设备(从设备)进行初始化设置,确保其工作参数正确并与 SPI 主机控制器兼容
spi_gpio_setup:初始化片选引脚,调用bitbang的setup
spi_bitbang_setup:根据模式设置bitbang->txrx_word消息传输方式,还有setup_transfer在每次发送/接收消息时对从设备的设置。
然后通过device_add将新建的设备加入到总线上去。
6.加入新的从设备后自动匹配驱动,根据驱动的probe重新设置一遍
[ 2.471135] spi spi32766.0: spi_match_device: matching driver 'mc13xxx' [ 2.477891] spi spi32766.0: trying ID table match... [ 2.483078] spi spi32766.0: spi_match_device: matching driver '74x164' [ 2.489706] spi spi32766.0: OF match succeeded //从设备树匹配74x164成功了匹配上驱动后,根据驱动的probe,重新配置一遍设备(这个驱动在/drivers/gpio中)
static int gen_74x164_probe(struct spi_device *spi) { struct gen_74x164_chip *chip; u32 nregs; int ret; /* * bits_per_word cannot be configured in platform data */ spi->bits_per_word = 8; ret = spi_setup(spi); if (ret < 0) return ret; if (of_property_read_u32(spi->dev.of_node, "registers-number", &nregs)) { dev_err(&spi->dev, "Missing registers-number property in the DT.\n"); return -EINVAL; } chip = devm_kzalloc(&spi->dev, sizeof(*chip) + nregs, GFP_KERNEL); if (!chip) return -ENOMEM; spi_set_drvdata(spi, chip); chip->gpio_chip.label = spi->modalias; chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; chip->gpio_chip.set_multiple = gen_74x164_set_multiple; chip->gpio_chip.base = -1; chip->registers = nregs; chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers; of_property_read_u8_array(spi->dev.of_node, "registers-default", chip->buffer, chip->registers); chip->gpio_chip.can_sleep = true; chip->gpio_chip.parent = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; mutex_init(&chip->lock); ret = __gen_74x164_write_config(chip); if (ret) { dev_err(&spi->dev, "Failed writing: %d\n", ret); goto exit_destroy; } ret = gpiochip_add_data(&chip->gpio_chip, chip); if (!ret) return 0; exit_destroy: mutex_destroy(&chip->lock); return ret; }[ 2.494533] 74x164 spi32766.0: spi_setup: entered [ 2.499282] 74x164 spi32766.0: spi_gpio_setup: entered [ 2.504631] 74x164 spi32766.0: spi_bitbang_setup: entered [ 2.510081] 74x164 spi32766.0: spi_bitbang_setup_transfer: entered [ 2.516370] 74x164 spi32766.0: spi_bitbang_setup, 100000 nsec/bit [ 2.522576] 74x164 spi32766.0: setup mode 0, 8 bits/w, 10000 Hz max --> 0根据驱动配置好设备后,根据设备树配置发送0x57
[ 2.529481] spi_master spi32766: __spi_queued_transfer enter! pump mesg! [ 2.536386] 74x164 spi32766.0: spi_bitbang_setup_transfer: entered注册完毕!
[ 2.543700] spi_master spi32766: spi_device registered! /spi4/gpio_spi@0