blob: caaf2319214a58ca56387232d74c2bd3213bab7d [file] [log] [blame]
Simon Glass6494d702014-02-26 15:59:18 -07001/*
2 * Device manager
3 *
4 * Copyright (c) 2013 Google, Inc
5 *
6 * (C) Copyright 2012
7 * Pavel Herrmann <morpheus.ibis@gmail.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 */
11
12#include <common.h>
Simon Glass5a66a8f2014-07-23 06:55:12 -060013#include <fdtdec.h>
Simon Glass6494d702014-02-26 15:59:18 -070014#include <malloc.h>
15#include <dm/device.h>
16#include <dm/device-internal.h>
17#include <dm/lists.h>
18#include <dm/platdata.h>
19#include <dm/uclass.h>
20#include <dm/uclass-internal.h>
21#include <dm/util.h>
22#include <linux/err.h>
23#include <linux/list.h>
24
Simon Glass5a66a8f2014-07-23 06:55:12 -060025DECLARE_GLOBAL_DATA_PTR;
26
Simon Glass34792532015-03-25 12:21:54 -060027int device_bind(struct udevice *parent, const struct driver *drv,
28 const char *name, void *platdata, int of_offset,
29 struct udevice **devp)
Simon Glass6494d702014-02-26 15:59:18 -070030{
Heiko Schocher54c5d082014-05-22 12:43:05 +020031 struct udevice *dev;
Simon Glass6494d702014-02-26 15:59:18 -070032 struct uclass *uc;
Przemyslaw Marczak5eaed882015-04-15 13:07:18 +020033 int size, ret = 0;
Simon Glass6494d702014-02-26 15:59:18 -070034
35 *devp = NULL;
36 if (!name)
37 return -EINVAL;
38
39 ret = uclass_get(drv->id, &uc);
40 if (ret)
41 return ret;
42
Heiko Schocher54c5d082014-05-22 12:43:05 +020043 dev = calloc(1, sizeof(struct udevice));
Simon Glass6494d702014-02-26 15:59:18 -070044 if (!dev)
45 return -ENOMEM;
46
47 INIT_LIST_HEAD(&dev->sibling_node);
48 INIT_LIST_HEAD(&dev->child_head);
49 INIT_LIST_HEAD(&dev->uclass_node);
Masahiro Yamadae2282d72015-07-25 21:52:37 +090050#ifdef CONFIG_DEVRES
Masahiro Yamada608f26c2015-07-25 21:52:35 +090051 INIT_LIST_HEAD(&dev->devres_head);
Masahiro Yamadae2282d72015-07-25 21:52:37 +090052#endif
Simon Glass6494d702014-02-26 15:59:18 -070053 dev->platdata = platdata;
54 dev->name = name;
55 dev->of_offset = of_offset;
56 dev->parent = parent;
57 dev->driver = drv;
58 dev->uclass = uc;
Simon Glass5a66a8f2014-07-23 06:55:12 -060059
Simon Glass5a66a8f2014-07-23 06:55:12 -060060 dev->seq = -1;
Simon Glass91cbd792014-09-17 09:02:38 -060061 dev->req_seq = -1;
Simon Glass36fa61d2015-02-27 22:06:30 -070062 if (IS_ENABLED(CONFIG_OF_CONTROL) && IS_ENABLED(CONFIG_DM_SEQ_ALIAS)) {
63 /*
64 * Some devices, such as a SPI bus, I2C bus and serial ports
65 * are numbered using aliases.
66 *
67 * This is just a 'requested' sequence, and will be
68 * resolved (and ->seq updated) when the device is probed.
69 */
70 if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
71 if (uc->uc_drv->name && of_offset != -1) {
72 fdtdec_get_alias_seq(gd->fdt_blob,
73 uc->uc_drv->name, of_offset,
74 &dev->req_seq);
75 }
Simon Glass9cc36a22015-01-25 08:27:05 -070076 }
77 }
Simon Glass36fa61d2015-02-27 22:06:30 -070078
Simon Glassf8a85442015-01-25 08:27:00 -070079 if (!dev->platdata && drv->platdata_auto_alloc_size) {
Simon Glass6494d702014-02-26 15:59:18 -070080 dev->flags |= DM_FLAG_ALLOC_PDATA;
Simon Glassf8a85442015-01-25 08:27:00 -070081 dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
82 if (!dev->platdata) {
83 ret = -ENOMEM;
84 goto fail_alloc1;
85 }
86 }
Simon Glasscdc133b2015-01-25 08:27:01 -070087
Przemyslaw Marczak5eaed882015-04-15 13:07:18 +020088 size = uc->uc_drv->per_device_platdata_auto_alloc_size;
89 if (size) {
90 dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA;
91 dev->uclass_platdata = calloc(1, size);
92 if (!dev->uclass_platdata) {
93 ret = -ENOMEM;
94 goto fail_alloc2;
95 }
96 }
97
98 if (parent) {
99 size = parent->driver->per_child_platdata_auto_alloc_size;
Simon Glassba8da9d2015-01-25 08:27:02 -0700100 if (!size) {
101 size = parent->uclass->uc_drv->
102 per_child_platdata_auto_alloc_size;
103 }
Simon Glasscdc133b2015-01-25 08:27:01 -0700104 if (size) {
105 dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
106 dev->parent_platdata = calloc(1, size);
107 if (!dev->parent_platdata) {
108 ret = -ENOMEM;
Przemyslaw Marczak5eaed882015-04-15 13:07:18 +0200109 goto fail_alloc3;
Simon Glasscdc133b2015-01-25 08:27:01 -0700110 }
111 }
112 }
Simon Glass6494d702014-02-26 15:59:18 -0700113
114 /* put dev into parent's successor list */
115 if (parent)
116 list_add_tail(&dev->sibling_node, &parent->child_head);
117
118 ret = uclass_bind_device(dev);
119 if (ret)
Simon Glass72ebfe82015-01-25 08:26:59 -0700120 goto fail_uclass_bind;
Simon Glass6494d702014-02-26 15:59:18 -0700121
122 /* if we fail to bind we remove device from successors and free it */
123 if (drv->bind) {
124 ret = drv->bind(dev);
Simon Glass72ebfe82015-01-25 08:26:59 -0700125 if (ret)
Simon Glass6494d702014-02-26 15:59:18 -0700126 goto fail_bind;
Simon Glass6494d702014-02-26 15:59:18 -0700127 }
Simon Glass0118ce72015-01-25 08:27:03 -0700128 if (parent && parent->driver->child_post_bind) {
129 ret = parent->driver->child_post_bind(dev);
130 if (ret)
131 goto fail_child_post_bind;
132 }
133
Simon Glass6494d702014-02-26 15:59:18 -0700134 if (parent)
135 dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
136 *devp = dev;
137
Masahiro Yamadaaed1a4d2015-07-25 21:52:34 +0900138 dev->flags |= DM_FLAG_BOUND;
139
Simon Glass6494d702014-02-26 15:59:18 -0700140 return 0;
141
Simon Glass0118ce72015-01-25 08:27:03 -0700142fail_child_post_bind:
Masahiro Yamadaf0f932d2015-04-24 17:28:40 +0900143 if (IS_ENABLED(CONFIG_DM_DEVICE_REMOVE)) {
Simon Glass5a87c412015-02-27 22:06:33 -0700144 if (drv->unbind && drv->unbind(dev)) {
145 dm_warn("unbind() method failed on dev '%s' on error path\n",
146 dev->name);
147 }
Simon Glass0118ce72015-01-25 08:27:03 -0700148 }
149
Simon Glass6494d702014-02-26 15:59:18 -0700150fail_bind:
Masahiro Yamadaf0f932d2015-04-24 17:28:40 +0900151 if (IS_ENABLED(CONFIG_DM_DEVICE_REMOVE)) {
Simon Glass5a87c412015-02-27 22:06:33 -0700152 if (uclass_unbind_device(dev)) {
153 dm_warn("Failed to unbind dev '%s' on error path\n",
154 dev->name);
155 }
Simon Glass72ebfe82015-01-25 08:26:59 -0700156 }
157fail_uclass_bind:
Masahiro Yamadaf0f932d2015-04-24 17:28:40 +0900158 if (IS_ENABLED(CONFIG_DM_DEVICE_REMOVE)) {
Simon Glass5a87c412015-02-27 22:06:33 -0700159 list_del(&dev->sibling_node);
160 if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
161 free(dev->parent_platdata);
162 dev->parent_platdata = NULL;
163 }
Simon Glasscdc133b2015-01-25 08:27:01 -0700164 }
Przemyslaw Marczak5eaed882015-04-15 13:07:18 +0200165fail_alloc3:
166 if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
167 free(dev->uclass_platdata);
168 dev->uclass_platdata = NULL;
169 }
Simon Glasscdc133b2015-01-25 08:27:01 -0700170fail_alloc2:
Simon Glassf8a85442015-01-25 08:27:00 -0700171 if (dev->flags & DM_FLAG_ALLOC_PDATA) {
172 free(dev->platdata);
173 dev->platdata = NULL;
174 }
175fail_alloc1:
Masahiro Yamada608f26c2015-07-25 21:52:35 +0900176 devres_release_all(dev);
177
Simon Glass6494d702014-02-26 15:59:18 -0700178 free(dev);
Simon Glass72ebfe82015-01-25 08:26:59 -0700179
Simon Glass6494d702014-02-26 15:59:18 -0700180 return ret;
181}
182
Simon Glass00606d72014-07-23 06:55:03 -0600183int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
184 const struct driver_info *info, struct udevice **devp)
Simon Glass6494d702014-02-26 15:59:18 -0700185{
186 struct driver *drv;
187
188 drv = lists_driver_lookup_name(info->name);
189 if (!drv)
190 return -ENOENT;
Simon Glass00606d72014-07-23 06:55:03 -0600191 if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
192 return -EPERM;
Simon Glass6494d702014-02-26 15:59:18 -0700193
194 return device_bind(parent, drv, info->name, (void *)info->platdata,
195 -1, devp);
196}
197
Simon Glass2c03c462015-03-25 12:21:53 -0600198static void *alloc_priv(int size, uint flags)
199{
200 void *priv;
201
202 if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
203 priv = memalign(ARCH_DMA_MINALIGN, size);
204 if (priv)
205 memset(priv, '\0', size);
206 } else {
207 priv = calloc(1, size);
208 }
209
210 return priv;
211}
212
Simon Glassaccd4b12014-10-13 23:41:50 -0600213int device_probe_child(struct udevice *dev, void *parent_priv)
Simon Glass6494d702014-02-26 15:59:18 -0700214{
Simon Glass34792532015-03-25 12:21:54 -0600215 const struct driver *drv;
Simon Glass6494d702014-02-26 15:59:18 -0700216 int size = 0;
217 int ret;
Simon Glass5a66a8f2014-07-23 06:55:12 -0600218 int seq;
Simon Glass6494d702014-02-26 15:59:18 -0700219
220 if (!dev)
221 return -EINVAL;
222
223 if (dev->flags & DM_FLAG_ACTIVATED)
224 return 0;
225
226 drv = dev->driver;
227 assert(drv);
228
Simon Glassf8a85442015-01-25 08:27:00 -0700229 /* Allocate private data if requested */
Simon Glass6494d702014-02-26 15:59:18 -0700230 if (drv->priv_auto_alloc_size) {
Simon Glass2c03c462015-03-25 12:21:53 -0600231 dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
Simon Glass6494d702014-02-26 15:59:18 -0700232 if (!dev->priv) {
233 ret = -ENOMEM;
234 goto fail;
235 }
236 }
237 /* Allocate private data if requested */
Simon Glass6494d702014-02-26 15:59:18 -0700238 size = dev->uclass->uc_drv->per_device_auto_alloc_size;
239 if (size) {
240 dev->uclass_priv = calloc(1, size);
241 if (!dev->uclass_priv) {
242 ret = -ENOMEM;
243 goto fail;
244 }
245 }
246
247 /* Ensure all parents are probed */
248 if (dev->parent) {
Simon Glasse59f4582014-07-23 06:55:20 -0600249 size = dev->parent->driver->per_child_auto_alloc_size;
Simon Glassdac8db22015-01-25 08:27:06 -0700250 if (!size) {
251 size = dev->parent->uclass->uc_drv->
252 per_child_auto_alloc_size;
253 }
Simon Glasse59f4582014-07-23 06:55:20 -0600254 if (size) {
Simon Glass2c03c462015-03-25 12:21:53 -0600255 dev->parent_priv = alloc_priv(size, drv->flags);
Simon Glasse59f4582014-07-23 06:55:20 -0600256 if (!dev->parent_priv) {
257 ret = -ENOMEM;
258 goto fail;
259 }
Simon Glassaccd4b12014-10-13 23:41:50 -0600260 if (parent_priv)
261 memcpy(dev->parent_priv, parent_priv, size);
Simon Glasse59f4582014-07-23 06:55:20 -0600262 }
263
Simon Glass6494d702014-02-26 15:59:18 -0700264 ret = device_probe(dev->parent);
265 if (ret)
266 goto fail;
267 }
268
Simon Glass5a66a8f2014-07-23 06:55:12 -0600269 seq = uclass_resolve_seq(dev);
270 if (seq < 0) {
271 ret = seq;
272 goto fail;
273 }
274 dev->seq = seq;
275
Simon Glass206d4d22015-03-25 12:21:56 -0600276 dev->flags |= DM_FLAG_ACTIVATED;
277
Simon Glass02c07b32015-03-05 12:25:22 -0700278 ret = uclass_pre_probe_device(dev);
Simon Glass83c7e432015-01-25 08:27:10 -0700279 if (ret)
280 goto fail;
281
Simon Glassa327dee2014-07-23 06:55:21 -0600282 if (dev->parent && dev->parent->driver->child_pre_probe) {
283 ret = dev->parent->driver->child_pre_probe(dev);
284 if (ret)
285 goto fail;
286 }
287
Simon Glass6494d702014-02-26 15:59:18 -0700288 if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
289 ret = drv->ofdata_to_platdata(dev);
290 if (ret)
291 goto fail;
292 }
293
294 if (drv->probe) {
295 ret = drv->probe(dev);
Simon Glass02eeb1b2015-03-05 12:25:21 -0700296 if (ret) {
297 dev->flags &= ~DM_FLAG_ACTIVATED;
Simon Glass6494d702014-02-26 15:59:18 -0700298 goto fail;
Simon Glass02eeb1b2015-03-05 12:25:21 -0700299 }
Simon Glass6494d702014-02-26 15:59:18 -0700300 }
301
Simon Glass6494d702014-02-26 15:59:18 -0700302 ret = uclass_post_probe_device(dev);
Simon Glass206d4d22015-03-25 12:21:56 -0600303 if (ret)
Simon Glass6494d702014-02-26 15:59:18 -0700304 goto fail_uclass;
Simon Glass6494d702014-02-26 15:59:18 -0700305
306 return 0;
307fail_uclass:
308 if (device_remove(dev)) {
309 dm_warn("%s: Device '%s' failed to remove on error path\n",
310 __func__, dev->name);
311 }
312fail:
Simon Glass206d4d22015-03-25 12:21:56 -0600313 dev->flags &= ~DM_FLAG_ACTIVATED;
314
Simon Glass5a66a8f2014-07-23 06:55:12 -0600315 dev->seq = -1;
Simon Glass6494d702014-02-26 15:59:18 -0700316 device_free(dev);
317
318 return ret;
319}
320
Simon Glassaccd4b12014-10-13 23:41:50 -0600321int device_probe(struct udevice *dev)
322{
323 return device_probe_child(dev, NULL);
324}
325
Heiko Schocher54c5d082014-05-22 12:43:05 +0200326void *dev_get_platdata(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700327{
328 if (!dev) {
Simon Glass964d1532014-12-10 08:55:56 -0700329 dm_warn("%s: null device\n", __func__);
Simon Glass6494d702014-02-26 15:59:18 -0700330 return NULL;
331 }
332
333 return dev->platdata;
334}
335
Simon Glasscdc133b2015-01-25 08:27:01 -0700336void *dev_get_parent_platdata(struct udevice *dev)
337{
338 if (!dev) {
Simon Glass36d7cc12015-07-06 16:47:40 -0600339 dm_warn("%s: null device\n", __func__);
Simon Glasscdc133b2015-01-25 08:27:01 -0700340 return NULL;
341 }
342
343 return dev->parent_platdata;
344}
345
Przemyslaw Marczak5eaed882015-04-15 13:07:18 +0200346void *dev_get_uclass_platdata(struct udevice *dev)
347{
348 if (!dev) {
Simon Glass36d7cc12015-07-06 16:47:40 -0600349 dm_warn("%s: null device\n", __func__);
Przemyslaw Marczak5eaed882015-04-15 13:07:18 +0200350 return NULL;
351 }
352
353 return dev->uclass_platdata;
354}
355
Heiko Schocher54c5d082014-05-22 12:43:05 +0200356void *dev_get_priv(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700357{
358 if (!dev) {
Simon Glass964d1532014-12-10 08:55:56 -0700359 dm_warn("%s: null device\n", __func__);
Simon Glass6494d702014-02-26 15:59:18 -0700360 return NULL;
361 }
362
363 return dev->priv;
364}
Simon Glass997c87b2014-07-23 06:55:19 -0600365
Simon Glasse564f052015-03-05 12:25:20 -0700366void *dev_get_uclass_priv(struct udevice *dev)
367{
368 if (!dev) {
369 dm_warn("%s: null device\n", __func__);
370 return NULL;
371 }
372
373 return dev->uclass_priv;
374}
375
Simon Glasse59f4582014-07-23 06:55:20 -0600376void *dev_get_parentdata(struct udevice *dev)
377{
378 if (!dev) {
Simon Glass964d1532014-12-10 08:55:56 -0700379 dm_warn("%s: null device\n", __func__);
Simon Glasse59f4582014-07-23 06:55:20 -0600380 return NULL;
381 }
382
383 return dev->parent_priv;
384}
385
Simon Glass997c87b2014-07-23 06:55:19 -0600386static int device_get_device_tail(struct udevice *dev, int ret,
387 struct udevice **devp)
388{
389 if (ret)
390 return ret;
391
392 ret = device_probe(dev);
393 if (ret)
394 return ret;
395
396 *devp = dev;
397
398 return 0;
399}
400
401int device_get_child(struct udevice *parent, int index, struct udevice **devp)
402{
403 struct udevice *dev;
404
405 list_for_each_entry(dev, &parent->child_head, sibling_node) {
406 if (!index--)
407 return device_get_device_tail(dev, 0, devp);
408 }
409
410 return -ENODEV;
411}
412
413int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
414 bool find_req_seq, struct udevice **devp)
415{
416 struct udevice *dev;
417
418 *devp = NULL;
419 if (seq_or_req_seq == -1)
420 return -ENODEV;
421
422 list_for_each_entry(dev, &parent->child_head, sibling_node) {
423 if ((find_req_seq ? dev->req_seq : dev->seq) ==
424 seq_or_req_seq) {
425 *devp = dev;
426 return 0;
427 }
428 }
429
430 return -ENODEV;
431}
432
433int device_get_child_by_seq(struct udevice *parent, int seq,
434 struct udevice **devp)
435{
436 struct udevice *dev;
437 int ret;
438
439 *devp = NULL;
440 ret = device_find_child_by_seq(parent, seq, false, &dev);
441 if (ret == -ENODEV) {
442 /*
443 * We didn't find it in probed devices. See if there is one
444 * that will request this seq if probed.
445 */
446 ret = device_find_child_by_seq(parent, seq, true, &dev);
447 }
448 return device_get_device_tail(dev, ret, devp);
449}
450
451int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
452 struct udevice **devp)
453{
454 struct udevice *dev;
455
456 *devp = NULL;
457
458 list_for_each_entry(dev, &parent->child_head, sibling_node) {
459 if (dev->of_offset == of_offset) {
460 *devp = dev;
461 return 0;
462 }
463 }
464
465 return -ENODEV;
466}
467
Simon Glass132f9bf2015-06-23 15:38:38 -0600468int device_get_child_by_of_offset(struct udevice *parent, int node,
Simon Glass997c87b2014-07-23 06:55:19 -0600469 struct udevice **devp)
470{
471 struct udevice *dev;
472 int ret;
473
474 *devp = NULL;
Simon Glass132f9bf2015-06-23 15:38:38 -0600475 ret = device_find_child_by_of_offset(parent, node, &dev);
Simon Glass997c87b2014-07-23 06:55:19 -0600476 return device_get_device_tail(dev, ret, devp);
477}
Simon Glassa8981d42014-10-13 23:41:49 -0600478
Simon Glass26930472015-06-23 15:38:37 -0600479static struct udevice *_device_find_global_by_of_offset(struct udevice *parent,
480 int of_offset)
481{
482 struct udevice *dev, *found;
483
484 if (parent->of_offset == of_offset)
485 return parent;
486
487 list_for_each_entry(dev, &parent->child_head, sibling_node) {
488 found = _device_find_global_by_of_offset(dev, of_offset);
489 if (found)
490 return found;
491 }
492
493 return NULL;
494}
495
496int device_get_global_by_of_offset(int of_offset, struct udevice **devp)
497{
498 struct udevice *dev;
499
500 dev = _device_find_global_by_of_offset(gd->dm_root, of_offset);
501 return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
502}
503
Simon Glassa8981d42014-10-13 23:41:49 -0600504int device_find_first_child(struct udevice *parent, struct udevice **devp)
505{
506 if (list_empty(&parent->child_head)) {
507 *devp = NULL;
508 } else {
509 *devp = list_first_entry(&parent->child_head, struct udevice,
510 sibling_node);
511 }
512
513 return 0;
514}
515
516int device_find_next_child(struct udevice **devp)
517{
518 struct udevice *dev = *devp;
519 struct udevice *parent = dev->parent;
520
521 if (list_is_last(&dev->sibling_node, &parent->child_head)) {
522 *devp = NULL;
523 } else {
524 *devp = list_entry(dev->sibling_node.next, struct udevice,
525 sibling_node);
526 }
527
528 return 0;
529}
Simon Glass2ef249b2014-11-11 10:46:18 -0700530
Simon Glass479728c2014-11-11 10:46:19 -0700531struct udevice *dev_get_parent(struct udevice *child)
532{
533 return child->parent;
534}
535
Simon Glass39de8432015-03-25 12:21:55 -0600536ulong dev_get_driver_data(struct udevice *dev)
Simon Glass2ef249b2014-11-11 10:46:18 -0700537{
Simon Glass39de8432015-03-25 12:21:55 -0600538 return dev->driver_data;
Simon Glass2ef249b2014-11-11 10:46:18 -0700539}
Simon Glassb3670532015-01-25 08:27:04 -0700540
Przemyslaw Marczakcc73d372015-04-15 13:07:24 +0200541const void *dev_get_driver_ops(struct udevice *dev)
542{
543 if (!dev || !dev->driver->ops)
544 return NULL;
545
546 return dev->driver->ops;
547}
548
Simon Glassb3670532015-01-25 08:27:04 -0700549enum uclass_id device_get_uclass_id(struct udevice *dev)
550{
551 return dev->uclass->uc_drv->id;
552}
Peng Fanc9cac3f2015-02-10 14:46:32 +0800553
Przemyslaw Marczakf9c370d2015-04-15 13:07:25 +0200554const char *dev_get_uclass_name(struct udevice *dev)
555{
556 if (!dev)
557 return NULL;
558
559 return dev->uclass->uc_drv->name;
560}
561
Simon Glassf3301772015-07-07 20:53:44 -0600562fdt_addr_t dev_get_addr(struct udevice *dev)
563{
Peng Fanc9cac3f2015-02-10 14:46:32 +0800564#ifdef CONFIG_OF_CONTROL
Simon Glassf3301772015-07-07 20:53:44 -0600565 fdt_addr_t addr;
566
567 addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
568 if (addr != FDT_ADDR_T_NONE) {
569 if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS)
570 addr = simple_bus_translate(dev->parent, addr);
571 }
572
573 return addr;
Peng Fanc9cac3f2015-02-10 14:46:32 +0800574#else
Peng Fanc9cac3f2015-02-10 14:46:32 +0800575 return FDT_ADDR_T_NONE;
Peng Fanc9cac3f2015-02-10 14:46:32 +0800576#endif
Simon Glassf3301772015-07-07 20:53:44 -0600577}
Simon Glassc5785672015-03-25 12:21:57 -0600578
579bool device_has_children(struct udevice *dev)
580{
581 return !list_empty(&dev->child_head);
582}
583
584bool device_has_active_children(struct udevice *dev)
585{
586 struct udevice *child;
587
588 for (device_find_first_child(dev, &child);
589 child;
590 device_find_next_child(&child)) {
591 if (device_active(child))
592 return true;
593 }
594
595 return false;
596}
597
598bool device_is_last_sibling(struct udevice *dev)
599{
600 struct udevice *parent = dev->parent;
601
602 if (!parent)
603 return false;
604 return list_is_last(&dev->sibling_node, &parent->child_head);
605}