blob: 5e24927b341f4ed859c552e49868e97ba58dd2a2 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassdd6ab882014-02-26 15:59:18 -07002/*
3 * Copyright (c) 2013 Google, Inc
4 *
5 * (C) Copyright 2012
6 * Pavel Herrmann <morpheus.ibis@gmail.com>
Simon Glassdd6ab882014-02-26 15:59:18 -07007 */
8
Kever Yang5f09a2d2019-10-22 15:39:47 +08009#define LOG_CATEGORY LOGC_DM
10
Simon Glassdd6ab882014-02-26 15:59:18 -070011#include <common.h>
Simon Glassee145d62017-05-18 20:09:09 -060012#include <dm.h>
Simon Glassdd6ab882014-02-26 15:59:18 -070013#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glassdd6ab882014-02-26 15:59:18 -070015#include <malloc.h>
16#include <dm/device.h>
17#include <dm/device-internal.h>
18#include <dm/lists.h>
19#include <dm/uclass.h>
20#include <dm/uclass-internal.h>
21#include <dm/util.h>
22
23DECLARE_GLOBAL_DATA_PTR;
24
25struct uclass *uclass_find(enum uclass_id key)
26{
27 struct uclass *uc;
28
Simon Glassde708672014-07-23 06:55:15 -060029 if (!gd->dm_root)
30 return NULL;
Simon Glassdd6ab882014-02-26 15:59:18 -070031 /*
32 * TODO(sjg@chromium.org): Optimise this, perhaps moving the found
33 * node to the start of the list, or creating a linear array mapping
34 * id to node.
35 */
36 list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
37 if (uc->uc_drv->id == key)
38 return uc;
39 }
40
41 return NULL;
42}
43
44/**
45 * uclass_add() - Create new uclass in list
46 * @id: Id number to create
47 * @ucp: Returns pointer to uclass, or NULL on error
48 * @return 0 on success, -ve on error
49 *
50 * The new uclass is added to the list. There must be only one uclass for
51 * each id.
52 */
53static int uclass_add(enum uclass_id id, struct uclass **ucp)
54{
55 struct uclass_driver *uc_drv;
56 struct uclass *uc;
57 int ret;
58
59 *ucp = NULL;
60 uc_drv = lists_uclass_lookup(id);
61 if (!uc_drv) {
Masahiro Yamada1d06ced2015-07-07 18:51:32 +090062 debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
63 id);
Simon Glass43313de2015-08-30 16:55:16 -060064 /*
65 * Use a strange error to make this case easier to find. When
66 * a uclass is not available it can prevent driver model from
67 * starting up and this failure is otherwise hard to debug.
68 */
69 return -EPFNOSUPPORT;
Simon Glassdd6ab882014-02-26 15:59:18 -070070 }
Simon Glassdd6ab882014-02-26 15:59:18 -070071 uc = calloc(1, sizeof(*uc));
72 if (!uc)
73 return -ENOMEM;
Simon Glass8a2b47f2020-12-03 16:55:17 -070074 if (uc_drv->priv_auto) {
75 uc->priv = calloc(1, uc_drv->priv_auto);
Simon Glassdd6ab882014-02-26 15:59:18 -070076 if (!uc->priv) {
77 ret = -ENOMEM;
78 goto fail_mem;
79 }
80 }
81 uc->uc_drv = uc_drv;
82 INIT_LIST_HEAD(&uc->sibling_node);
83 INIT_LIST_HEAD(&uc->dev_head);
Simon Glass34a1d352014-06-11 23:29:49 -060084 list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST);
Simon Glassdd6ab882014-02-26 15:59:18 -070085
86 if (uc_drv->init) {
87 ret = uc_drv->init(uc);
88 if (ret)
89 goto fail;
90 }
91
92 *ucp = uc;
93
94 return 0;
95fail:
Simon Glass8a2b47f2020-12-03 16:55:17 -070096 if (uc_drv->priv_auto) {
Simon Glassdd6ab882014-02-26 15:59:18 -070097 free(uc->priv);
98 uc->priv = NULL;
99 }
100 list_del(&uc->sibling_node);
101fail_mem:
102 free(uc);
103
104 return ret;
105}
106
107int uclass_destroy(struct uclass *uc)
108{
109 struct uclass_driver *uc_drv;
Simon Glassf33663d2015-04-19 07:20:58 -0600110 struct udevice *dev;
Simon Glassdd6ab882014-02-26 15:59:18 -0700111 int ret;
112
Simon Glassf33663d2015-04-19 07:20:58 -0600113 /*
114 * We cannot use list_for_each_entry_safe() here. If a device in this
115 * uclass has a child device also in this uclass, it will be also be
116 * unbound (by the recursion in the call to device_unbind() below).
117 * We can loop until the list is empty.
118 */
119 while (!list_empty(&uc->dev_head)) {
120 dev = list_first_entry(&uc->dev_head, struct udevice,
121 uclass_node);
Simon Glass42697f52020-03-28 14:03:48 -0600122 ret = device_remove(dev, DM_REMOVE_NORMAL | DM_REMOVE_NO_PD);
Simon Glassdd6ab882014-02-26 15:59:18 -0700123 if (ret)
Simon Glass5f3c9e02020-03-28 14:03:47 -0600124 return log_msg_ret("remove", ret);
Simon Glassdd6ab882014-02-26 15:59:18 -0700125 ret = device_unbind(dev);
126 if (ret)
Simon Glass5f3c9e02020-03-28 14:03:47 -0600127 return log_msg_ret("unbind", ret);
Simon Glassdd6ab882014-02-26 15:59:18 -0700128 }
129
130 uc_drv = uc->uc_drv;
131 if (uc_drv->destroy)
132 uc_drv->destroy(uc);
133 list_del(&uc->sibling_node);
Simon Glass8a2b47f2020-12-03 16:55:17 -0700134 if (uc_drv->priv_auto)
Simon Glassdd6ab882014-02-26 15:59:18 -0700135 free(uc->priv);
136 free(uc);
137
138 return 0;
139}
140
141int uclass_get(enum uclass_id id, struct uclass **ucp)
142{
143 struct uclass *uc;
144
145 *ucp = NULL;
146 uc = uclass_find(id);
147 if (!uc)
148 return uclass_add(id, ucp);
149 *ucp = uc;
150
151 return 0;
152}
153
Simon Glassd19d0732016-10-05 20:42:13 -0600154const char *uclass_get_name(enum uclass_id id)
155{
156 struct uclass *uc;
157
158 if (uclass_get(id, &uc))
159 return NULL;
160 return uc->uc_drv->name;
161}
162
Simon Glass96404c22020-12-22 19:30:26 -0700163void *uclass_get_priv(const struct uclass *uc)
164{
165 return uc->priv;
166}
167
168void uclass_set_priv(struct uclass *uc, void *priv)
169{
170 uc->priv = priv;
171}
172
Simon Glass70e35b42017-12-28 13:14:15 -0700173enum uclass_id uclass_get_by_name(const char *name)
174{
175 int i;
176
177 for (i = 0; i < UCLASS_COUNT; i++) {
178 struct uclass_driver *uc_drv = lists_uclass_lookup(i);
179
180 if (uc_drv && !strcmp(uc_drv->name, name))
181 return i;
182 }
183
184 return UCLASS_INVALID;
185}
186
Jean-Jacques Hiblotc4f02482018-08-09 16:17:42 +0200187int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
188{
189 struct udevice *iter;
190 struct uclass *uc = dev->uclass;
191 int i = 0;
192
193 if (list_empty(&uc->dev_head))
194 return -ENODEV;
195
Liviu Dudau6f386222018-09-28 14:12:55 +0100196 uclass_foreach_dev(iter, uc) {
Jean-Jacques Hiblotc4f02482018-08-09 16:17:42 +0200197 if (iter == dev) {
198 if (ucp)
199 *ucp = uc;
200 return i;
201 }
202 i++;
203 }
204
205 return -ENODEV;
206}
207
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200208int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
Simon Glassdd6ab882014-02-26 15:59:18 -0700209{
210 struct uclass *uc;
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200211 struct udevice *dev;
Simon Glassdd6ab882014-02-26 15:59:18 -0700212 int ret;
213
214 *devp = NULL;
215 ret = uclass_get(id, &uc);
216 if (ret)
217 return ret;
Simon Glass46766df2015-07-31 09:31:19 -0600218 if (list_empty(&uc->dev_head))
219 return -ENODEV;
Simon Glassdd6ab882014-02-26 15:59:18 -0700220
Liviu Dudau6f386222018-09-28 14:12:55 +0100221 uclass_foreach_dev(dev, uc) {
Simon Glassdd6ab882014-02-26 15:59:18 -0700222 if (!index--) {
223 *devp = dev;
224 return 0;
225 }
226 }
227
228 return -ENODEV;
229}
230
Przemyslaw Marczakf9d156e2015-04-15 13:07:17 +0200231int uclass_find_first_device(enum uclass_id id, struct udevice **devp)
232{
233 struct uclass *uc;
234 int ret;
235
236 *devp = NULL;
237 ret = uclass_get(id, &uc);
238 if (ret)
239 return ret;
240 if (list_empty(&uc->dev_head))
Simon Glass0bb44272019-09-25 08:55:55 -0600241 return 0;
Przemyslaw Marczakf9d156e2015-04-15 13:07:17 +0200242
243 *devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
244
245 return 0;
246}
247
248int uclass_find_next_device(struct udevice **devp)
249{
250 struct udevice *dev = *devp;
251
252 *devp = NULL;
253 if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
254 return 0;
255
256 *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node);
257
258 return 0;
259}
260
Przemyslaw Marczak2ffdf142015-04-15 13:07:22 +0200261int uclass_find_device_by_name(enum uclass_id id, const char *name,
262 struct udevice **devp)
263{
264 struct uclass *uc;
265 struct udevice *dev;
266 int ret;
267
268 *devp = NULL;
269 if (!name)
270 return -EINVAL;
271 ret = uclass_get(id, &uc);
272 if (ret)
273 return ret;
274
Liviu Dudau6f386222018-09-28 14:12:55 +0100275 uclass_foreach_dev(dev, uc) {
Peng Fan26d68b22019-05-22 07:08:14 +0000276 if (!strcmp(dev->name, name)) {
Przemyslaw Marczak2ffdf142015-04-15 13:07:22 +0200277 *devp = dev;
278 return 0;
279 }
280 }
281
282 return -ENODEV;
283}
284
Simon Glassb941f562020-12-16 21:20:30 -0700285int uclass_find_next_free_seq(struct uclass *uc)
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100286{
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100287 struct udevice *dev;
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100288 int max = -1;
289
Simon Glassb941f562020-12-16 21:20:30 -0700290 /* If using aliases, start with the highest alias value */
291 if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
292 (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS))
293 max = dev_read_alias_highest_id(uc->uc_drv->name);
294
295 /* Avoid conflict with existing devices */
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100296 list_for_each_entry(dev, &uc->dev_head, uclass_node) {
Simon Glassb941f562020-12-16 21:20:30 -0700297 if (dev->sqq > max)
298 max = dev->sqq;
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100299 }
Simon Glassb941f562020-12-16 21:20:30 -0700300 /*
301 * At this point, max will be -1 if there are no existing aliases or
302 * devices
303 */
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100304
305 return max + 1;
306}
Jean-Jacques Hiblota5da3002018-12-07 14:50:39 +0100307
Simon Glass07e13382020-12-16 21:20:29 -0700308int uclass_find_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
Simon Glassdb6f0202014-07-23 06:55:12 -0600309{
310 struct uclass *uc;
311 struct udevice *dev;
312 int ret;
313
314 *devp = NULL;
Simon Glass07e13382020-12-16 21:20:29 -0700315 log_debug("%d\n", seq);
316 if (seq == -1)
Simon Glassdb6f0202014-07-23 06:55:12 -0600317 return -ENODEV;
318 ret = uclass_get(id, &uc);
319 if (ret)
320 return ret;
321
Liviu Dudau6f386222018-09-28 14:12:55 +0100322 uclass_foreach_dev(dev, uc) {
Simon Glass07e13382020-12-16 21:20:29 -0700323 log_debug(" - %d '%s'\n", dev->sqq, dev->name);
324 if (dev->sqq == seq) {
Simon Glassdb6f0202014-07-23 06:55:12 -0600325 *devp = dev;
Kever Yang5f09a2d2019-10-22 15:39:47 +0800326 log_debug(" - found\n");
Simon Glassdb6f0202014-07-23 06:55:12 -0600327 return 0;
328 }
329 }
Kever Yang5f09a2d2019-10-22 15:39:47 +0800330 log_debug(" - not found\n");
Simon Glassdb6f0202014-07-23 06:55:12 -0600331
332 return -ENODEV;
333}
334
Simon Glass96f04442016-01-21 19:43:57 -0700335int uclass_find_device_by_of_offset(enum uclass_id id, int node,
336 struct udevice **devp)
Simon Glassc1464ab2014-07-23 06:55:14 -0600337{
338 struct uclass *uc;
339 struct udevice *dev;
340 int ret;
341
342 *devp = NULL;
343 if (node < 0)
344 return -ENODEV;
345 ret = uclass_get(id, &uc);
346 if (ret)
347 return ret;
348
Liviu Dudau6f386222018-09-28 14:12:55 +0100349 uclass_foreach_dev(dev, uc) {
Simon Glassdd79d6e2017-01-17 16:52:55 -0700350 if (dev_of_offset(dev) == node) {
Simon Glassc1464ab2014-07-23 06:55:14 -0600351 *devp = dev;
352 return 0;
353 }
354 }
355
356 return -ENODEV;
357}
358
Simon Glassee145d62017-05-18 20:09:09 -0600359int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
360 struct udevice **devp)
361{
362 struct uclass *uc;
363 struct udevice *dev;
364 int ret;
365
Simon Glass5ab533c2018-06-11 13:07:19 -0600366 log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
Simon Glassee145d62017-05-18 20:09:09 -0600367 *devp = NULL;
368 if (!ofnode_valid(node))
369 return -ENODEV;
370 ret = uclass_get(id, &uc);
371 if (ret)
372 return ret;
373
Liviu Dudau6f386222018-09-28 14:12:55 +0100374 uclass_foreach_dev(dev, uc) {
Simon Glass5ab533c2018-06-11 13:07:19 -0600375 log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n",
376 dev->name);
Simon Glassee145d62017-05-18 20:09:09 -0600377 if (ofnode_equal(dev_ofnode(dev), node)) {
378 *devp = dev;
Simon Glass5ab533c2018-06-11 13:07:19 -0600379 goto done;
Simon Glassee145d62017-05-18 20:09:09 -0600380 }
381 }
Simon Glass5ab533c2018-06-11 13:07:19 -0600382 ret = -ENODEV;
Simon Glassee145d62017-05-18 20:09:09 -0600383
Simon Glass5ab533c2018-06-11 13:07:19 -0600384done:
385 log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n",
386 ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret);
387 return ret;
Simon Glassee145d62017-05-18 20:09:09 -0600388}
389
Simon Glass359c4872015-12-19 19:38:55 -0700390#if CONFIG_IS_ENABLED(OF_CONTROL)
Simon Glassdc3efdc2018-11-18 08:14:30 -0700391int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
392 const char *name, struct udevice **devp)
Simon Glass75f00df2015-07-02 18:15:38 -0600393{
394 struct udevice *dev;
395 struct uclass *uc;
396 int find_phandle;
397 int ret;
398
399 *devp = NULL;
Simon Glassbfb6e3d2017-05-18 20:09:12 -0600400 find_phandle = dev_read_u32_default(parent, name, -1);
Simon Glass75f00df2015-07-02 18:15:38 -0600401 if (find_phandle <= 0)
402 return -ENOENT;
403 ret = uclass_get(id, &uc);
404 if (ret)
405 return ret;
406
Liviu Dudau6f386222018-09-28 14:12:55 +0100407 uclass_foreach_dev(dev, uc) {
Simon Glassdd79d6e2017-01-17 16:52:55 -0700408 uint phandle;
409
Simon Glassbfb6e3d2017-05-18 20:09:12 -0600410 phandle = dev_read_phandle(dev);
Simon Glass75f00df2015-07-02 18:15:38 -0600411
412 if (phandle == find_phandle) {
413 *devp = dev;
414 return 0;
415 }
416 }
417
418 return -ENODEV;
419}
Simon Glass359c4872015-12-19 19:38:55 -0700420#endif
Simon Glass75f00df2015-07-02 18:15:38 -0600421
Simon Glass32d8ab62016-07-17 15:23:15 -0600422int uclass_get_device_by_driver(enum uclass_id id,
423 const struct driver *find_drv,
424 struct udevice **devp)
425{
426 struct udevice *dev;
427 struct uclass *uc;
428 int ret;
429
430 ret = uclass_get(id, &uc);
431 if (ret)
432 return ret;
433
Liviu Dudau6f386222018-09-28 14:12:55 +0100434 uclass_foreach_dev(dev, uc) {
Simon Glass32d8ab62016-07-17 15:23:15 -0600435 if (dev->driver == find_drv)
436 return uclass_get_device_tail(dev, 0, devp);
437 }
438
439 return -ENODEV;
440}
441
Simon Glass98c9fb02017-04-23 20:10:43 -0600442int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp)
Simon Glassdd6ab882014-02-26 15:59:18 -0700443{
Simon Glassdd6ab882014-02-26 15:59:18 -0700444 if (ret)
445 return ret;
446
Simon Glass46cc8ba92015-04-24 22:33:07 -0600447 assert(dev);
Simon Glassdd6ab882014-02-26 15:59:18 -0700448 ret = device_probe(dev);
449 if (ret)
450 return ret;
451
452 *devp = dev;
453
454 return 0;
455}
456
Simon Glass4b67cef2014-07-23 06:55:08 -0600457int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
458{
459 struct udevice *dev;
460 int ret;
461
462 *devp = NULL;
463 ret = uclass_find_device(id, index, &dev);
464 return uclass_get_device_tail(dev, ret, devp);
465}
466
Przemyslaw Marczaka12a1f52015-04-15 13:07:23 +0200467int uclass_get_device_by_name(enum uclass_id id, const char *name,
468 struct udevice **devp)
469{
470 struct udevice *dev;
471 int ret;
472
473 *devp = NULL;
474 ret = uclass_find_device_by_name(id, name, &dev);
475 return uclass_get_device_tail(dev, ret, devp);
476}
477
Simon Glassdb6f0202014-07-23 06:55:12 -0600478int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
479{
480 struct udevice *dev;
481 int ret;
482
483 *devp = NULL;
Simon Glass07e13382020-12-16 21:20:29 -0700484 ret = uclass_find_device_by_seq(id, seq, &dev);
485
Simon Glassdb6f0202014-07-23 06:55:12 -0600486 return uclass_get_device_tail(dev, ret, devp);
487}
488
Simon Glassc1464ab2014-07-23 06:55:14 -0600489int uclass_get_device_by_of_offset(enum uclass_id id, int node,
490 struct udevice **devp)
491{
492 struct udevice *dev;
493 int ret;
494
495 *devp = NULL;
496 ret = uclass_find_device_by_of_offset(id, node, &dev);
497 return uclass_get_device_tail(dev, ret, devp);
498}
499
Simon Glassee145d62017-05-18 20:09:09 -0600500int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node,
501 struct udevice **devp)
502{
503 struct udevice *dev;
504 int ret;
505
Simon Glass5ab533c2018-06-11 13:07:19 -0600506 log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node));
Simon Glassee145d62017-05-18 20:09:09 -0600507 *devp = NULL;
508 ret = uclass_find_device_by_ofnode(id, node, &dev);
Simon Glass5ab533c2018-06-11 13:07:19 -0600509 log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n",
510 ofnode_get_name(node), dev ? dev->name : "(none)", ret);
Simon Glassee145d62017-05-18 20:09:09 -0600511
512 return uclass_get_device_tail(dev, ret, devp);
513}
514
Simon Glass359c4872015-12-19 19:38:55 -0700515#if CONFIG_IS_ENABLED(OF_CONTROL)
Kever Yang66a0b5a2018-02-09 10:56:23 +0800516int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
517 struct udevice **devp)
518{
519 struct udevice *dev;
520 struct uclass *uc;
521 int ret;
522
523 *devp = NULL;
524 ret = uclass_get(id, &uc);
525 if (ret)
526 return ret;
527
Liviu Dudau6f386222018-09-28 14:12:55 +0100528 uclass_foreach_dev(dev, uc) {
Kever Yang66a0b5a2018-02-09 10:56:23 +0800529 uint phandle;
530
531 phandle = dev_read_phandle(dev);
532
533 if (phandle == phandle_id) {
534 *devp = dev;
535 return uclass_get_device_tail(dev, ret, devp);
536 }
537 }
538
539 return -ENODEV;
540}
541
Simon Glass75f00df2015-07-02 18:15:38 -0600542int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent,
543 const char *name, struct udevice **devp)
544{
545 struct udevice *dev;
546 int ret;
547
548 *devp = NULL;
549 ret = uclass_find_device_by_phandle(id, parent, name, &dev);
550 return uclass_get_device_tail(dev, ret, devp);
551}
Simon Glass359c4872015-12-19 19:38:55 -0700552#endif
Simon Glass75f00df2015-07-02 18:15:38 -0600553
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200554int uclass_first_device(enum uclass_id id, struct udevice **devp)
Simon Glassdd6ab882014-02-26 15:59:18 -0700555{
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200556 struct udevice *dev;
Simon Glassdd6ab882014-02-26 15:59:18 -0700557 int ret;
558
559 *devp = NULL;
Przemyslaw Marczakf9d156e2015-04-15 13:07:17 +0200560 ret = uclass_find_first_device(id, &dev);
Simon Glass46cc8ba92015-04-24 22:33:07 -0600561 if (!dev)
562 return 0;
Przemyslaw Marczakf9d156e2015-04-15 13:07:17 +0200563 return uclass_get_device_tail(dev, ret, devp);
Simon Glassdd6ab882014-02-26 15:59:18 -0700564}
565
Simon Glass832c3f02016-02-11 13:23:25 -0700566int uclass_first_device_err(enum uclass_id id, struct udevice **devp)
567{
568 int ret;
569
570 ret = uclass_first_device(id, devp);
571 if (ret)
572 return ret;
573 else if (!*devp)
574 return -ENODEV;
575
576 return 0;
577}
578
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200579int uclass_next_device(struct udevice **devp)
Simon Glassdd6ab882014-02-26 15:59:18 -0700580{
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200581 struct udevice *dev = *devp;
Simon Glassdd6ab882014-02-26 15:59:18 -0700582 int ret;
583
584 *devp = NULL;
Przemyslaw Marczakf9d156e2015-04-15 13:07:17 +0200585 ret = uclass_find_next_device(&dev);
Simon Glass46cc8ba92015-04-24 22:33:07 -0600586 if (!dev)
587 return 0;
Przemyslaw Marczakf9d156e2015-04-15 13:07:17 +0200588 return uclass_get_device_tail(dev, ret, devp);
Simon Glassdd6ab882014-02-26 15:59:18 -0700589}
590
Patrice Chotard4dff1782018-10-24 14:10:15 +0200591int uclass_next_device_err(struct udevice **devp)
592{
593 int ret;
594
595 ret = uclass_next_device(devp);
596 if (ret)
597 return ret;
598 else if (!*devp)
599 return -ENODEV;
600
601 return 0;
602}
603
Simon Glass3ff83bc2017-04-23 20:10:45 -0600604int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
605{
606 int ret;
607
608 *devp = NULL;
609 ret = uclass_find_first_device(id, devp);
610 if (ret)
611 return ret;
612 if (!*devp)
613 return 0;
614
615 return device_probe(*devp);
616}
617
618int uclass_next_device_check(struct udevice **devp)
619{
620 int ret;
621
622 ret = uclass_find_next_device(devp);
623 if (ret)
624 return ret;
625 if (!*devp)
626 return 0;
627
628 return device_probe(*devp);
629}
630
Simon Glass35cb2a42020-02-06 09:54:50 -0700631int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data,
632 struct udevice **devp)
633{
634 struct udevice *dev;
635 struct uclass *uc;
636
637 uclass_id_foreach_dev(id, dev, uc) {
638 if (dev_get_driver_data(dev) == driver_data) {
639 *devp = dev;
640
641 return device_probe(dev);
642 }
643 }
644
645 return -ENODEV;
646}
647
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200648int uclass_bind_device(struct udevice *dev)
Simon Glassdd6ab882014-02-26 15:59:18 -0700649{
650 struct uclass *uc;
651 int ret;
652
653 uc = dev->uclass;
Simon Glassdd6ab882014-02-26 15:59:18 -0700654 list_add_tail(&dev->uclass_node, &uc->dev_head);
655
Simon Glassf4c9b3e2015-01-25 08:27:08 -0700656 if (dev->parent) {
657 struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
658
659 if (uc_drv->child_post_bind) {
660 ret = uc_drv->child_post_bind(dev);
661 if (ret)
662 goto err;
663 }
664 }
Simon Glassdd6ab882014-02-26 15:59:18 -0700665
666 return 0;
Simon Glassf4c9b3e2015-01-25 08:27:08 -0700667err:
668 /* There is no need to undo the parent's post_bind call */
669 list_del(&dev->uclass_node);
670
671 return ret;
Simon Glassdd6ab882014-02-26 15:59:18 -0700672}
673
Masahiro Yamada04aa00d2015-08-12 07:31:52 +0900674#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200675int uclass_unbind_device(struct udevice *dev)
Simon Glassdd6ab882014-02-26 15:59:18 -0700676{
677 struct uclass *uc;
678 int ret;
679
680 uc = dev->uclass;
681 if (uc->uc_drv->pre_unbind) {
682 ret = uc->uc_drv->pre_unbind(dev);
683 if (ret)
684 return ret;
685 }
686
687 list_del(&dev->uclass_node);
688 return 0;
689}
Simon Glass8914c8a2015-02-27 22:06:31 -0700690#endif
Simon Glassdd6ab882014-02-26 15:59:18 -0700691
Simon Glass9c1f3822015-03-05 12:25:22 -0700692int uclass_pre_probe_device(struct udevice *dev)
Simon Glass5104b982015-01-25 08:27:10 -0700693{
694 struct uclass_driver *uc_drv;
Simon Glass9c1f3822015-03-05 12:25:22 -0700695 int ret;
696
697 uc_drv = dev->uclass->uc_drv;
698 if (uc_drv->pre_probe) {
699 ret = uc_drv->pre_probe(dev);
700 if (ret)
701 return ret;
702 }
Simon Glass5104b982015-01-25 08:27:10 -0700703
704 if (!dev->parent)
705 return 0;
706 uc_drv = dev->parent->uclass->uc_drv;
Simon Glass256d4022019-09-25 08:55:47 -0600707 if (uc_drv->child_pre_probe) {
708 ret = uc_drv->child_pre_probe(dev);
709 if (ret)
710 return ret;
711 }
Simon Glass5104b982015-01-25 08:27:10 -0700712
713 return 0;
714}
715
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200716int uclass_post_probe_device(struct udevice *dev)
Simon Glassdd6ab882014-02-26 15:59:18 -0700717{
Bin Meng30569cf2018-10-15 02:20:57 -0700718 struct uclass_driver *uc_drv;
719 int ret;
720
721 if (dev->parent) {
722 uc_drv = dev->parent->uclass->uc_drv;
723 if (uc_drv->child_post_probe) {
724 ret = uc_drv->child_post_probe(dev);
725 if (ret)
726 return ret;
727 }
728 }
Simon Glassdd6ab882014-02-26 15:59:18 -0700729
Bin Meng30569cf2018-10-15 02:20:57 -0700730 uc_drv = dev->uclass->uc_drv;
Simon Glass256d4022019-09-25 08:55:47 -0600731 if (uc_drv->post_probe) {
732 ret = uc_drv->post_probe(dev);
733 if (ret)
734 return ret;
735 }
Simon Glassdd6ab882014-02-26 15:59:18 -0700736
737 return 0;
738}
739
Masahiro Yamada04aa00d2015-08-12 07:31:52 +0900740#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200741int uclass_pre_remove_device(struct udevice *dev)
Simon Glassdd6ab882014-02-26 15:59:18 -0700742{
Simon Glassdd6ab882014-02-26 15:59:18 -0700743 struct uclass *uc;
744 int ret;
745
746 uc = dev->uclass;
Simon Glassdd6ab882014-02-26 15:59:18 -0700747 if (uc->uc_drv->pre_remove) {
748 ret = uc->uc_drv->pre_remove(dev);
749 if (ret)
750 return ret;
751 }
Simon Glassdd6ab882014-02-26 15:59:18 -0700752
753 return 0;
754}
Simon Glass8914c8a2015-02-27 22:06:31 -0700755#endif
Jean-Jacques Hiblotdb97c7f2019-07-05 09:33:57 +0200756
757UCLASS_DRIVER(nop) = {
758 .id = UCLASS_NOP,
759 .name = "nop",
760};