概述
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驱动框架-优快云博客)。
#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

最低0.47元/天 解锁文章
963

被折叠的 条评论
为什么被折叠?



