Uboot驱动模型之spi-uclass(2/3)

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

概述

spi-uclass提供对SPI总线的访问,并包括SPI所需的操作。spi-uclass只是提供方法,spi的设备驱动需要调用这些方法来驱动设备以及操作总线/设备。

定义uclass driver

如上篇《Uboot驱动模型之框架driver-model(1/3)》分析的那样uclass的定义依赖于uclass_driver。所以使用UCLASS_DIRVER来定义struct uclass_driver spi,即补充struct uclass_driver的各个你需要用到的成员。

spi的struct uclass_driver的定义如下:

471 UCLASS_DRIVER(spi) = {
472     .id     = UCLASS_SPI,
473     .name       = "spi",
474     .flags      = DM_UC_FLAG_SEQ_ALIAS,
475 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
476     .post_bind  = dm_scan_fdt_dev,
477 #endif
478     .post_probe = spi_post_probe,
479     .child_pre_probe = spi_child_pre_probe,
480     .per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
481     .per_child_auto_alloc_size = sizeof(struct spi_slave),
482     .per_child_platdata_auto_alloc_size =
483             sizeof(struct dm_spi_slave_platdata),
484 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
485     .child_post_bind = spi_child_post_bind,
486 #endif
487 };

成员解析:

#if !CONFIG_IS_ENABLED(OF_PLATDATA)

        .post_bind = dm_scan_fdt_dev:

        作用:dm_scan_fdt_dev的作用就是扫描父设备下的子设备,意味着在spi设备绑定spi uclass后会去扫描它的子设备。此时递归下去就会把该设备下的所有子设备,孙设备。

        调用时机:在扫描设备树创建udevice的时候。该阶段比较早,《Uboot驱动模型之框架driver-model(1/3)》中有介绍(Uboot驱动模型之框架driver-model(1/3)_uboot驱动框架-CSDN博客)。

#endif

 33 static int device_bind_common(struct udevice *parent, const struct driver *drv,
 34                   const char *name, void *platdata,
 35                   ulong driver_data, ofnode node,
 36                   uint of_platdata_size, struct udevice **devp)
 37 {
 38     struct udevice *dev;
 39     struct uclass *uc;
 40     int size, ret = 0;
 41
 42     if (devp)
 43         *devp = NULL;
 44     if (!name)
 45         return -EINVAL;
 46
 47     ret = uclass_get(drv->id, &uc);
 48     if (ret) {
 49         debug("Missing uclass for driver %s\n", drv->name);
 50         return ret;
 51     }
 52
 53     dev = calloc(1, sizeof(struct udevice));
 54     if (!dev)
 55         return -ENOMEM;
 56
 57     INIT_LIST_HEAD(&dev->sibling_node);
 58     INIT_LIST_HEAD(&dev->child_head);
 59     INIT_LIST_HEAD(&dev->uclass_node);
 60 #ifdef CONFIG_DEVRES
 61     INIT_LIST_HEAD(&dev->devres_head);
 62 #endif
 63     dev->platdata = platdata;
 64     dev->driver_data = driver_data;
 65     dev->name = name;
 66     dev->node = node;
 67     dev->parent = parent;
 68     dev->driver = drv;
 69     dev->uclass = uc;
 70
 71     dev->seq = -1;
 72     dev->req_seq = -1;
 73
 74     ...
 75
 76     if (parent && parent->driver->child_post_bind) {
 77         ret = parent->driver->child_post_bind(dev);
 78         if (ret)
 79             goto fail_child_post_bind;
 80     }
 81     if (uc->uc_drv->post_bind) {
 82         ret = uc->uc_drv->post_bind(dev);
 83         if (ret)
 84             goto fail_uclass_post_bind;
 85     }
 86
 87     if (parent)
 88         pr_debug("Bound device %s to %s\n", dev->name, parent->name);
 89     if (devp)
 90         *devp = dev;
 91
 92     dev->flags |= DM_FLAG_BOUND;
 93
 94     return 0;

        .post_probe = spi_post_probe:

        作用:主要是读取spi总线支持的最大频率以及看是否需要对定义的spi总线的ops接口重定位。

        调用时机:在触发spi driver的probe后调用(e.g. U_BOOT_DERIVER(xx),device_probe(udevice)后先调用xx.probe(),然后再调用此处post_probe),主要是读dts中的spi-max-frequency节点。

143 static int spi_post_probe(struct udevice *bus)
144 {
145 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
146     struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
147
148     spi->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0);
149 #endif
150 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
151     struct dm_spi_ops *ops = spi_get_ops(bus);
152
153     if (ops->claim_bus)
154         ops->claim_bus += gd->reloc_off;
155     if (ops->release_bus)
156         ops->release_bus += gd->reloc_off;
157     if (ops->set_wordlen)
158         ops->set_wordlen += gd->reloc_off;
159     if (ops->xfer)
160         ops->xfer += gd->reloc_off;
161     if (ops->set_speed)
162         ops->set_speed += gd->reloc_off;
163     if (ops->set_mode)
164         ops->set_mode += gd->reloc_off;
165     if (ops->cs_info)
166         ops->cs_info += gd->reloc_off;
167 #endif
168
172     return 0;
173 }

        .child_pre_probe = spi_child_pre_probe:

        作用:主要是设置这个device(从设备)支持的最大频率,模式(极性,线宽等)

        调用时机:在spi driver的probe调用之前会先调用这个spi device 的uclass的.child_pre_probe执行,然后再调用这个spi device的parent的uclass的.child_pre_probe(即这里的spi_child_pre_probe;spi device的parent是spi控制器,spi控制器的uclass就是这里的UCLASS_DRIVER(spi))执行。

175 static int spi_child_pre_probe(struct udevice *dev)
176 {
177     struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
178     struct spi_slave *slave = dev_get_parent_priv(dev);
179
180     /*
181      * This is needed because we pass struct spi_slave around the place
182      * instead slave->dev (a struct udevice). So we have to have some
183      * way to access the slave udevice given struct spi_slave. Once we
184      * change the SPI API to use udevice instead of spi_slave, we can
185      * drop this.
186      */
187     slave->dev = dev;
188
189     slave->max_hz = plat->max_hz;
190     slave->mode = plat->mode;
191     slave->wordlen = SPI_DEFAULT_WORDLEN;
192
193     return 0;
194 }

        .per_device_auto_alloc_size = sizeof(struct dm_spi_bus):

        作用:保存spi总线的最大频率,在设置device的频率的时候,不能大于总线的频率,dm_spi_claim_bus的时候会做这个处理。dm_spi_bus数据结构如下:

v2019:
 41 /* TODO(sjg@chromium.org): Remove this and use max_hz from struct spi_slave */
 42 struct dm_spi_bus {
 43     uint max_hz;
 44 };
v2023:
 42 /**
 43  * struct dm_spi_bus - SPI bus info
 44  *
 45  * This contains information about a SPI bus. To obtain this structure, use
 46  * dev_get_uclass_priv(bus) where bus is the SPI bus udevice.
 47  *
 48  * @max_hz: Maximum speed that the bus can tolerate.
 49  * @speed:  Current bus speed. This is 0 until the bus is first claimed.
 50  * @mode:   Current bus mode. This is 0 until the bus is first claimed.
 51  *
 52  * TODO(sjg@chromium.org): Remove this and use max_hz from struct spi_slave.
 53  */
 54 struct dm_spi_bus {
 55     uint max_hz;
 56     uint speed;
 57     uint mode;
 58 };

        调用时机:在spi device触发后(device_prob

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值