]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
d7af6a48 SG |
2 | /* |
3 | * Copyright (c) 2014 Google, Inc | |
d7af6a48 SG |
4 | */ |
5 | ||
46c5391b PD |
6 | #define LOG_CATEGORY UCLASS_SPI |
7 | ||
d7af6a48 SG |
8 | #include <common.h> |
9 | #include <dm.h> | |
10 | #include <errno.h> | |
f7ae49fc | 11 | #include <log.h> |
d7af6a48 SG |
12 | #include <malloc.h> |
13 | #include <spi.h> | |
46c5391b | 14 | #include <dm/device_compat.h> |
401d1c4f | 15 | #include <asm/global_data.h> |
d7af6a48 SG |
16 | #include <dm/device-internal.h> |
17 | #include <dm/uclass-internal.h> | |
d7af6a48 SG |
18 | #include <dm/lists.h> |
19 | #include <dm/util.h> | |
20 | ||
21 | DECLARE_GLOBAL_DATA_PTR; | |
22 | ||
12bfb2e0 SG |
23 | #define SPI_DEFAULT_SPEED_HZ 100000 |
24 | ||
d7af6a48 SG |
25 | static int spi_set_speed_mode(struct udevice *bus, int speed, int mode) |
26 | { | |
27 | struct dm_spi_ops *ops; | |
28 | int ret; | |
29 | ||
30 | ops = spi_get_ops(bus); | |
31 | if (ops->set_speed) | |
32 | ret = ops->set_speed(bus, speed); | |
33 | else | |
34 | ret = -EINVAL; | |
35 | if (ret) { | |
46c5391b | 36 | dev_err(bus, "Cannot set speed (err=%d)\n", ret); |
d7af6a48 SG |
37 | return ret; |
38 | } | |
39 | ||
40 | if (ops->set_mode) | |
41 | ret = ops->set_mode(bus, mode); | |
42 | else | |
43 | ret = -EINVAL; | |
44 | if (ret) { | |
46c5391b | 45 | dev_err(bus, "Cannot set mode (err=%d)\n", ret); |
d7af6a48 SG |
46 | return ret; |
47 | } | |
48 | ||
49 | return 0; | |
50 | } | |
51 | ||
7a3eff4c | 52 | int dm_spi_claim_bus(struct udevice *dev) |
d7af6a48 | 53 | { |
d7af6a48 SG |
54 | struct udevice *bus = dev->parent; |
55 | struct dm_spi_ops *ops = spi_get_ops(bus); | |
e564f054 | 56 | struct dm_spi_bus *spi = dev_get_uclass_priv(bus); |
7a3eff4c | 57 | struct spi_slave *slave = dev_get_parent_priv(dev); |
741280e9 | 58 | uint speed, mode; |
d7af6a48 SG |
59 | |
60 | speed = slave->max_hz; | |
741280e9 OP |
61 | mode = slave->mode; |
62 | ||
d7af6a48 SG |
63 | if (spi->max_hz) { |
64 | if (speed) | |
741280e9 | 65 | speed = min(speed, spi->max_hz); |
d7af6a48 SG |
66 | else |
67 | speed = spi->max_hz; | |
68 | } | |
69 | if (!speed) | |
12bfb2e0 | 70 | speed = SPI_DEFAULT_SPEED_HZ; |
741280e9 OP |
71 | |
72 | if (speed != spi->speed || mode != spi->mode) { | |
24fc1ec2 MS |
73 | int ret = spi_set_speed_mode(bus, speed, slave->mode); |
74 | ||
60e2809a | 75 | if (ret) |
5e24a2ef | 76 | return log_ret(ret); |
741280e9 OP |
77 | |
78 | spi->speed = speed; | |
79 | spi->mode = mode; | |
60e2809a | 80 | } |
d7af6a48 | 81 | |
5e24a2ef | 82 | return log_ret(ops->claim_bus ? ops->claim_bus(dev) : 0); |
d7af6a48 SG |
83 | } |
84 | ||
7a3eff4c | 85 | void dm_spi_release_bus(struct udevice *dev) |
d7af6a48 | 86 | { |
d7af6a48 SG |
87 | struct udevice *bus = dev->parent; |
88 | struct dm_spi_ops *ops = spi_get_ops(bus); | |
89 | ||
90 | if (ops->release_bus) | |
9694b724 | 91 | ops->release_bus(dev); |
d7af6a48 SG |
92 | } |
93 | ||
7a3eff4c PF |
94 | int dm_spi_xfer(struct udevice *dev, unsigned int bitlen, |
95 | const void *dout, void *din, unsigned long flags) | |
d7af6a48 | 96 | { |
d7af6a48 | 97 | struct udevice *bus = dev->parent; |
ccdabd89 | 98 | struct dm_spi_ops *ops = spi_get_ops(bus); |
d7af6a48 SG |
99 | |
100 | if (bus->uclass->uc_drv->id != UCLASS_SPI) | |
101 | return -EOPNOTSUPP; | |
ccdabd89 SG |
102 | if (!ops->xfer) |
103 | return -ENOSYS; | |
d7af6a48 | 104 | |
ccdabd89 | 105 | return ops->xfer(dev, bitlen, dout, din, flags); |
7a3eff4c PF |
106 | } |
107 | ||
c53b318e SG |
108 | int dm_spi_get_mmap(struct udevice *dev, ulong *map_basep, uint *map_sizep, |
109 | uint *offsetp) | |
110 | { | |
111 | struct udevice *bus = dev->parent; | |
112 | struct dm_spi_ops *ops = spi_get_ops(bus); | |
113 | ||
114 | if (bus->uclass->uc_drv->id != UCLASS_SPI) | |
115 | return -EOPNOTSUPP; | |
116 | if (!ops->get_mmap) | |
117 | return -ENOSYS; | |
118 | ||
119 | return ops->get_mmap(dev, map_basep, map_sizep, offsetp); | |
120 | } | |
121 | ||
7a3eff4c PF |
122 | int spi_claim_bus(struct spi_slave *slave) |
123 | { | |
5e24a2ef | 124 | return log_ret(dm_spi_claim_bus(slave->dev)); |
7a3eff4c PF |
125 | } |
126 | ||
127 | void spi_release_bus(struct spi_slave *slave) | |
128 | { | |
129 | dm_spi_release_bus(slave->dev); | |
130 | } | |
131 | ||
132 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
133 | const void *dout, void *din, unsigned long flags) | |
134 | { | |
135 | return dm_spi_xfer(slave->dev, bitlen, dout, din, flags); | |
d7af6a48 SG |
136 | } |
137 | ||
8473b321 JT |
138 | int spi_write_then_read(struct spi_slave *slave, const u8 *opcode, |
139 | size_t n_opcode, const u8 *txbuf, u8 *rxbuf, | |
140 | size_t n_buf) | |
141 | { | |
142 | unsigned long flags = SPI_XFER_BEGIN; | |
143 | int ret; | |
144 | ||
145 | if (n_buf == 0) | |
146 | flags |= SPI_XFER_END; | |
147 | ||
148 | ret = spi_xfer(slave, n_opcode * 8, opcode, NULL, flags); | |
149 | if (ret) { | |
46c5391b PD |
150 | dev_dbg(slave->dev, |
151 | "spi: failed to send command (%zu bytes): %d\n", | |
152 | n_opcode, ret); | |
8473b321 JT |
153 | } else if (n_buf != 0) { |
154 | ret = spi_xfer(slave, n_buf * 8, txbuf, rxbuf, SPI_XFER_END); | |
155 | if (ret) | |
46c5391b PD |
156 | dev_dbg(slave->dev, |
157 | "spi: failed to transfer %zu bytes of data: %d\n", | |
158 | n_buf, ret); | |
8473b321 JT |
159 | } |
160 | ||
161 | return ret; | |
162 | } | |
163 | ||
71634f28 | 164 | #if !CONFIG_IS_ENABLED(OF_PLATDATA) |
6f849c30 | 165 | static int spi_child_post_bind(struct udevice *dev) |
d7af6a48 | 166 | { |
8a8d24bd | 167 | struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); |
d7af6a48 | 168 | |
7d14ee44 | 169 | if (!dev_has_ofnode(dev)) |
d0cff03e SG |
170 | return 0; |
171 | ||
d1998a9f | 172 | return spi_slave_of_to_plat(dev, plat); |
d0cff03e | 173 | } |
71634f28 | 174 | #endif |
d0cff03e | 175 | |
6f849c30 | 176 | static int spi_post_probe(struct udevice *bus) |
d0cff03e | 177 | { |
71634f28 | 178 | #if !CONFIG_IS_ENABLED(OF_PLATDATA) |
e564f054 | 179 | struct dm_spi_bus *spi = dev_get_uclass_priv(bus); |
d0cff03e | 180 | |
279e26f5 | 181 | spi->max_hz = dev_read_u32_default(bus, "spi-max-frequency", 0); |
71634f28 | 182 | #endif |
281f1566 MS |
183 | #if defined(CONFIG_NEEDS_MANUAL_RELOC) |
184 | struct dm_spi_ops *ops = spi_get_ops(bus); | |
4d9b1afa ARS |
185 | static int reloc_done; |
186 | ||
187 | if (!reloc_done) { | |
188 | if (ops->claim_bus) | |
189 | ops->claim_bus += gd->reloc_off; | |
190 | if (ops->release_bus) | |
191 | ops->release_bus += gd->reloc_off; | |
192 | if (ops->set_wordlen) | |
193 | ops->set_wordlen += gd->reloc_off; | |
194 | if (ops->xfer) | |
195 | ops->xfer += gd->reloc_off; | |
196 | if (ops->set_speed) | |
197 | ops->set_speed += gd->reloc_off; | |
198 | if (ops->set_mode) | |
199 | ops->set_mode += gd->reloc_off; | |
200 | if (ops->cs_info) | |
201 | ops->cs_info += gd->reloc_off; | |
202 | reloc_done++; | |
203 | } | |
281f1566 MS |
204 | #endif |
205 | ||
d7af6a48 SG |
206 | return 0; |
207 | } | |
208 | ||
6f849c30 | 209 | static int spi_child_pre_probe(struct udevice *dev) |
440714ee | 210 | { |
8a8d24bd | 211 | struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); |
bcbe3d15 | 212 | struct spi_slave *slave = dev_get_parent_priv(dev); |
440714ee | 213 | |
d0cff03e SG |
214 | /* |
215 | * This is needed because we pass struct spi_slave around the place | |
216 | * instead slave->dev (a struct udevice). So we have to have some | |
217 | * way to access the slave udevice given struct spi_slave. Once we | |
218 | * change the SPI API to use udevice instead of spi_slave, we can | |
219 | * drop this. | |
220 | */ | |
440714ee SG |
221 | slave->dev = dev; |
222 | ||
d0cff03e SG |
223 | slave->max_hz = plat->max_hz; |
224 | slave->mode = plat->mode; | |
674f3609 | 225 | slave->wordlen = SPI_DEFAULT_WORDLEN; |
d0cff03e | 226 | |
440714ee SG |
227 | return 0; |
228 | } | |
229 | ||
d7af6a48 SG |
230 | int spi_chip_select(struct udevice *dev) |
231 | { | |
8a8d24bd | 232 | struct dm_spi_slave_plat *plat = dev_get_parent_plat(dev); |
d7af6a48 | 233 | |
d0cff03e | 234 | return plat ? plat->cs : -ENOENT; |
d7af6a48 SG |
235 | } |
236 | ||
ff56bba2 | 237 | int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) |
d7af6a48 | 238 | { |
7bacce52 BM |
239 | struct dm_spi_ops *ops; |
240 | struct spi_cs_info info; | |
d7af6a48 | 241 | struct udevice *dev; |
7bacce52 BM |
242 | int ret; |
243 | ||
244 | /* | |
245 | * Ask the driver. For the moment we don't have CS info. | |
246 | * When we do we could provide the driver with a helper function | |
247 | * to figure out what chip selects are valid, or just handle the | |
248 | * request. | |
249 | */ | |
250 | ops = spi_get_ops(bus); | |
251 | if (ops->cs_info) { | |
252 | ret = ops->cs_info(bus, cs, &info); | |
253 | } else { | |
254 | /* | |
255 | * We could assume there is at least one valid chip select. | |
256 | * The driver didn't care enough to tell us. | |
257 | */ | |
258 | ret = 0; | |
259 | } | |
260 | ||
261 | if (ret) { | |
46c5391b | 262 | dev_err(bus, "Invalid cs %d (err=%d)\n", cs, ret); |
7bacce52 BM |
263 | return ret; |
264 | } | |
d7af6a48 SG |
265 | |
266 | for (device_find_first_child(bus, &dev); dev; | |
267 | device_find_next_child(&dev)) { | |
8a8d24bd | 268 | struct dm_spi_slave_plat *plat; |
d7af6a48 | 269 | |
caa4daa2 | 270 | plat = dev_get_parent_plat(dev); |
46c5391b | 271 | dev_dbg(bus, "%s: plat=%p, cs=%d\n", __func__, plat, plat->cs); |
d0cff03e | 272 | if (plat->cs == cs) { |
d7af6a48 SG |
273 | *devp = dev; |
274 | return 0; | |
275 | } | |
276 | } | |
277 | ||
278 | return -ENODEV; | |
279 | } | |
280 | ||
281 | int spi_cs_is_valid(unsigned int busnum, unsigned int cs) | |
282 | { | |
283 | struct spi_cs_info info; | |
284 | struct udevice *bus; | |
285 | int ret; | |
286 | ||
99175919 | 287 | ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, &bus); |
d7af6a48 | 288 | if (ret) { |
46c5391b | 289 | log_debug("%s: No bus %d\n", __func__, busnum); |
d7af6a48 SG |
290 | return ret; |
291 | } | |
292 | ||
293 | return spi_cs_info(bus, cs, &info); | |
294 | } | |
295 | ||
296 | int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info) | |
297 | { | |
298 | struct spi_cs_info local_info; | |
d7af6a48 SG |
299 | int ret; |
300 | ||
301 | if (!info) | |
302 | info = &local_info; | |
303 | ||
304 | /* If there is a device attached, return it */ | |
305 | info->dev = NULL; | |
306 | ret = spi_find_chip_select(bus, cs, &info->dev); | |
7bacce52 | 307 | return ret == -ENODEV ? 0 : ret; |
d7af6a48 SG |
308 | } |
309 | ||
d7af6a48 SG |
310 | int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, |
311 | struct udevice **devp) | |
312 | { | |
313 | struct udevice *bus, *dev; | |
314 | int ret; | |
315 | ||
99175919 | 316 | ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, &bus); |
d7af6a48 | 317 | if (ret) { |
46c5391b | 318 | log_debug("%s: No bus %d\n", __func__, busnum); |
d7af6a48 SG |
319 | return ret; |
320 | } | |
321 | ret = spi_find_chip_select(bus, cs, &dev); | |
322 | if (ret) { | |
46c5391b | 323 | dev_dbg(bus, "%s: No cs %d\n", __func__, cs); |
d7af6a48 SG |
324 | return ret; |
325 | } | |
326 | *busp = bus; | |
327 | *devp = dev; | |
328 | ||
329 | return ret; | |
330 | } | |
331 | ||
332 | int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, | |
333 | const char *drv_name, const char *dev_name, | |
334 | struct udevice **busp, struct spi_slave **devp) | |
335 | { | |
336 | struct udevice *bus, *dev; | |
8a8d24bd | 337 | struct dm_spi_slave_plat *plat; |
741280e9 | 338 | struct dm_spi_bus *bus_data; |
f7dd5370 | 339 | struct spi_slave *slave; |
d7af6a48 SG |
340 | bool created = false; |
341 | int ret; | |
342 | ||
640abba5 | 343 | #if CONFIG_IS_ENABLED(OF_PLATDATA) |
71634f28 SG |
344 | ret = uclass_first_device_err(UCLASS_SPI, &bus); |
345 | #else | |
d7af6a48 | 346 | ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); |
71634f28 | 347 | #endif |
d7af6a48 | 348 | if (ret) { |
46c5391b | 349 | log_err("Invalid bus %d (err=%d)\n", busnum, ret); |
d7af6a48 SG |
350 | return ret; |
351 | } | |
352 | ret = spi_find_chip_select(bus, cs, &dev); | |
353 | ||
354 | /* | |
355 | * If there is no such device, create one automatically. This means | |
356 | * that we don't need a device tree node or platform data for the | |
357 | * SPI flash chip - we will bind to the correct driver. | |
358 | */ | |
359 | if (ret == -ENODEV && drv_name) { | |
46c5391b PD |
360 | dev_dbg(bus, "%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n", |
361 | __func__, dev_name, busnum, cs, drv_name); | |
6b18656a | 362 | ret = device_bind_driver(bus, drv_name, dev_name, &dev); |
28f98858 | 363 | if (ret) { |
46c5391b PD |
364 | dev_dbg(bus, "%s: Unable to bind driver (ret=%d)\n", |
365 | __func__, ret); | |
d7af6a48 | 366 | return ret; |
28f98858 | 367 | } |
caa4daa2 | 368 | plat = dev_get_parent_plat(dev); |
d0cff03e | 369 | plat->cs = cs; |
12bfb2e0 SG |
370 | if (speed) { |
371 | plat->max_hz = speed; | |
372 | } else { | |
46c5391b PD |
373 | dev_warn(bus, |
374 | "Warning: SPI speed fallback to %u kHz\n", | |
375 | SPI_DEFAULT_SPEED_HZ / 1000); | |
12bfb2e0 SG |
376 | plat->max_hz = SPI_DEFAULT_SPEED_HZ; |
377 | } | |
d0cff03e | 378 | plat->mode = mode; |
d7af6a48 SG |
379 | created = true; |
380 | } else if (ret) { | |
46c5391b | 381 | dev_err(bus, "Invalid chip select %d:%d (err=%d)\n", busnum, cs, ret); |
d7af6a48 SG |
382 | return ret; |
383 | } | |
384 | ||
385 | if (!device_active(dev)) { | |
d0cff03e | 386 | struct spi_slave *slave; |
d7af6a48 | 387 | |
d0cff03e | 388 | ret = device_probe(dev); |
d7af6a48 SG |
389 | if (ret) |
390 | goto err; | |
bcbe3d15 | 391 | slave = dev_get_parent_priv(dev); |
d7af6a48 | 392 | slave->dev = dev; |
d7af6a48 SG |
393 | } |
394 | ||
f7dd5370 | 395 | slave = dev_get_parent_priv(dev); |
741280e9 | 396 | bus_data = dev_get_uclass_priv(bus); |
b0cc1b84 | 397 | |
f7dd5370 MW |
398 | /* |
399 | * In case the operation speed is not yet established by | |
400 | * dm_spi_claim_bus() ensure the bus is configured properly. | |
401 | */ | |
741280e9 | 402 | if (!bus_data->speed) { |
f7dd5370 MW |
403 | ret = spi_claim_bus(slave); |
404 | if (ret) | |
405 | goto err; | |
96907c0f | 406 | } |
d7af6a48 SG |
407 | |
408 | *busp = bus; | |
f7dd5370 | 409 | *devp = slave; |
46c5391b | 410 | log_debug("%s: bus=%p, slave=%p\n", __func__, bus, *devp); |
d7af6a48 SG |
411 | |
412 | return 0; | |
413 | ||
414 | err: | |
46c5391b PD |
415 | log_debug("%s: Error path, created=%d, device '%s'\n", __func__, |
416 | created, dev->name); | |
d7af6a48 | 417 | if (created) { |
706865af | 418 | device_remove(dev, DM_REMOVE_NORMAL); |
d7af6a48 SG |
419 | device_unbind(dev); |
420 | } | |
421 | ||
422 | return ret; | |
423 | } | |
424 | ||
d7af6a48 SG |
425 | /* Compatibility function - to be removed */ |
426 | struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, | |
427 | unsigned int speed, unsigned int mode) | |
428 | { | |
429 | struct spi_slave *slave; | |
430 | struct udevice *dev; | |
431 | int ret; | |
432 | ||
433 | ret = spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev, | |
279e26f5 | 434 | &slave); |
d7af6a48 SG |
435 | if (ret) |
436 | return NULL; | |
437 | ||
438 | return slave; | |
439 | } | |
440 | ||
441 | void spi_free_slave(struct spi_slave *slave) | |
442 | { | |
706865af | 443 | device_remove(slave->dev, DM_REMOVE_NORMAL); |
d7af6a48 SG |
444 | } |
445 | ||
8a8d24bd | 446 | int spi_slave_of_to_plat(struct udevice *dev, struct dm_spi_slave_plat *plat) |
d7af6a48 | 447 | { |
08fe9c29 | 448 | int mode = 0; |
f8e2f92d | 449 | int value; |
d7af6a48 | 450 | |
279e26f5 | 451 | plat->cs = dev_read_u32_default(dev, "reg", -1); |
12bfb2e0 SG |
452 | plat->max_hz = dev_read_u32_default(dev, "spi-max-frequency", |
453 | SPI_DEFAULT_SPEED_HZ); | |
279e26f5 | 454 | if (dev_read_bool(dev, "spi-cpol")) |
d7af6a48 | 455 | mode |= SPI_CPOL; |
279e26f5 | 456 | if (dev_read_bool(dev, "spi-cpha")) |
d7af6a48 | 457 | mode |= SPI_CPHA; |
279e26f5 | 458 | if (dev_read_bool(dev, "spi-cs-high")) |
d7af6a48 | 459 | mode |= SPI_CS_HIGH; |
279e26f5 | 460 | if (dev_read_bool(dev, "spi-3wire")) |
379b49d8 | 461 | mode |= SPI_3WIRE; |
279e26f5 | 462 | if (dev_read_bool(dev, "spi-half-duplex")) |
d7af6a48 | 463 | mode |= SPI_PREAMBLE; |
f8e2f92d M |
464 | |
465 | /* Device DUAL/QUAD mode */ | |
279e26f5 | 466 | value = dev_read_u32_default(dev, "spi-tx-bus-width", 1); |
f8e2f92d M |
467 | switch (value) { |
468 | case 1: | |
469 | break; | |
470 | case 2: | |
471 | mode |= SPI_TX_DUAL; | |
472 | break; | |
473 | case 4: | |
474 | mode |= SPI_TX_QUAD; | |
475 | break; | |
658df8bd VR |
476 | case 8: |
477 | mode |= SPI_TX_OCTAL; | |
478 | break; | |
f8e2f92d | 479 | default: |
1b7c28f5 | 480 | warn_non_spl("spi-tx-bus-width %d not supported\n", value); |
f8e2f92d M |
481 | break; |
482 | } | |
483 | ||
279e26f5 | 484 | value = dev_read_u32_default(dev, "spi-rx-bus-width", 1); |
f8e2f92d M |
485 | switch (value) { |
486 | case 1: | |
487 | break; | |
488 | case 2: | |
08fe9c29 | 489 | mode |= SPI_RX_DUAL; |
f8e2f92d M |
490 | break; |
491 | case 4: | |
08fe9c29 | 492 | mode |= SPI_RX_QUAD; |
f8e2f92d | 493 | break; |
658df8bd VR |
494 | case 8: |
495 | mode |= SPI_RX_OCTAL; | |
496 | break; | |
f8e2f92d | 497 | default: |
1b7c28f5 | 498 | warn_non_spl("spi-rx-bus-width %d not supported\n", value); |
f8e2f92d M |
499 | break; |
500 | } | |
501 | ||
08fe9c29 | 502 | plat->mode = mode; |
f8e2f92d | 503 | |
d7af6a48 SG |
504 | return 0; |
505 | } | |
506 | ||
507 | UCLASS_DRIVER(spi) = { | |
508 | .id = UCLASS_SPI, | |
509 | .name = "spi", | |
9cc36a2b | 510 | .flags = DM_UC_FLAG_SEQ_ALIAS, |
280af011 | 511 | #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) |
91195485 | 512 | .post_bind = dm_scan_fdt_dev, |
71634f28 | 513 | #endif |
d7af6a48 | 514 | .post_probe = spi_post_probe, |
440714ee | 515 | .child_pre_probe = spi_child_pre_probe, |
41575d8e SG |
516 | .per_device_auto = sizeof(struct dm_spi_bus), |
517 | .per_child_auto = sizeof(struct spi_slave), | |
8a8d24bd | 518 | .per_child_plat_auto = sizeof(struct dm_spi_slave_plat), |
71634f28 | 519 | #if !CONFIG_IS_ENABLED(OF_PLATDATA) |
d0cff03e | 520 | .child_post_bind = spi_child_post_bind, |
71634f28 | 521 | #endif |
d7af6a48 SG |
522 | }; |
523 | ||
524 | UCLASS_DRIVER(spi_generic) = { | |
525 | .id = UCLASS_SPI_GENERIC, | |
526 | .name = "spi_generic", | |
527 | }; | |
528 | ||
529 | U_BOOT_DRIVER(spi_generic_drv) = { | |
530 | .name = "spi_generic_drv", | |
531 | .id = UCLASS_SPI_GENERIC, | |
532 | }; |