16494d708SSimon Glass /* 26494d708SSimon Glass * Device manager 36494d708SSimon Glass * 46494d708SSimon Glass * Copyright (c) 2013 Google, Inc 56494d708SSimon Glass * 66494d708SSimon Glass * (C) Copyright 2012 76494d708SSimon Glass * Pavel Herrmann <morpheus.ibis@gmail.com> 86494d708SSimon Glass * 96494d708SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 106494d708SSimon Glass */ 116494d708SSimon Glass 126494d708SSimon Glass #include <common.h> 135a66a8ffSSimon Glass #include <fdtdec.h> 146494d708SSimon Glass #include <malloc.h> 156494d708SSimon Glass #include <dm/device.h> 166494d708SSimon Glass #include <dm/device-internal.h> 176494d708SSimon Glass #include <dm/lists.h> 186494d708SSimon Glass #include <dm/platdata.h> 196494d708SSimon Glass #include <dm/uclass.h> 206494d708SSimon Glass #include <dm/uclass-internal.h> 216494d708SSimon Glass #include <dm/util.h> 226494d708SSimon Glass #include <linux/err.h> 236494d708SSimon Glass #include <linux/list.h> 246494d708SSimon Glass 255a66a8ffSSimon Glass DECLARE_GLOBAL_DATA_PTR; 265a66a8ffSSimon Glass 276494d708SSimon Glass /** 286494d708SSimon Glass * device_chld_unbind() - Unbind all device's children from the device 296494d708SSimon Glass * 306494d708SSimon Glass * On error, the function continues to unbind all children, and reports the 316494d708SSimon Glass * first error. 326494d708SSimon Glass * 336494d708SSimon Glass * @dev: The device that is to be stripped of its children 346494d708SSimon Glass * @return 0 on success, -ve on error 356494d708SSimon Glass */ 3654c5d08aSHeiko Schocher static int device_chld_unbind(struct udevice *dev) 376494d708SSimon Glass { 3854c5d08aSHeiko Schocher struct udevice *pos, *n; 396494d708SSimon Glass int ret, saved_ret = 0; 406494d708SSimon Glass 416494d708SSimon Glass assert(dev); 426494d708SSimon Glass 436494d708SSimon Glass list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { 446494d708SSimon Glass ret = device_unbind(pos); 456494d708SSimon Glass if (ret && !saved_ret) 466494d708SSimon Glass saved_ret = ret; 476494d708SSimon Glass } 486494d708SSimon Glass 496494d708SSimon Glass return saved_ret; 506494d708SSimon Glass } 516494d708SSimon Glass 526494d708SSimon Glass /** 536494d708SSimon Glass * device_chld_remove() - Stop all device's children 546494d708SSimon Glass * @dev: The device whose children are to be removed 556494d708SSimon Glass * @return 0 on success, -ve on error 566494d708SSimon Glass */ 5754c5d08aSHeiko Schocher static int device_chld_remove(struct udevice *dev) 586494d708SSimon Glass { 5954c5d08aSHeiko Schocher struct udevice *pos, *n; 606494d708SSimon Glass int ret; 616494d708SSimon Glass 626494d708SSimon Glass assert(dev); 636494d708SSimon Glass 646494d708SSimon Glass list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { 656494d708SSimon Glass ret = device_remove(pos); 666494d708SSimon Glass if (ret) 676494d708SSimon Glass return ret; 686494d708SSimon Glass } 696494d708SSimon Glass 706494d708SSimon Glass return 0; 716494d708SSimon Glass } 726494d708SSimon Glass 7354c5d08aSHeiko Schocher int device_bind(struct udevice *parent, struct driver *drv, const char *name, 7454c5d08aSHeiko Schocher void *platdata, int of_offset, struct udevice **devp) 756494d708SSimon Glass { 7654c5d08aSHeiko Schocher struct udevice *dev; 776494d708SSimon Glass struct uclass *uc; 786494d708SSimon Glass int ret = 0; 796494d708SSimon Glass 806494d708SSimon Glass *devp = NULL; 816494d708SSimon Glass if (!name) 826494d708SSimon Glass return -EINVAL; 836494d708SSimon Glass 846494d708SSimon Glass ret = uclass_get(drv->id, &uc); 856494d708SSimon Glass if (ret) 866494d708SSimon Glass return ret; 876494d708SSimon Glass 8854c5d08aSHeiko Schocher dev = calloc(1, sizeof(struct udevice)); 896494d708SSimon Glass if (!dev) 906494d708SSimon Glass return -ENOMEM; 916494d708SSimon Glass 926494d708SSimon Glass INIT_LIST_HEAD(&dev->sibling_node); 936494d708SSimon Glass INIT_LIST_HEAD(&dev->child_head); 946494d708SSimon Glass INIT_LIST_HEAD(&dev->uclass_node); 956494d708SSimon Glass dev->platdata = platdata; 966494d708SSimon Glass dev->name = name; 976494d708SSimon Glass dev->of_offset = of_offset; 986494d708SSimon Glass dev->parent = parent; 996494d708SSimon Glass dev->driver = drv; 1006494d708SSimon Glass dev->uclass = uc; 1015a66a8ffSSimon Glass 1025a66a8ffSSimon Glass /* 1035a66a8ffSSimon Glass * For some devices, such as a SPI or I2C bus, the 'reg' property 1045a66a8ffSSimon Glass * is a reasonable indicator of the sequence number. But if there is 1055a66a8ffSSimon Glass * an alias, we use that in preference. In any case, this is just 1065a66a8ffSSimon Glass * a 'requested' sequence, and will be resolved (and ->seq updated) 1075a66a8ffSSimon Glass * when the device is probed. 1085a66a8ffSSimon Glass */ 1095a66a8ffSSimon Glass dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1); 1105a66a8ffSSimon Glass dev->seq = -1; 1115a66a8ffSSimon Glass if (uc->uc_drv->name && of_offset != -1) { 1125a66a8ffSSimon Glass fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset, 1135a66a8ffSSimon Glass &dev->req_seq); 1145a66a8ffSSimon Glass } 1155a66a8ffSSimon Glass 1166494d708SSimon Glass if (!dev->platdata && drv->platdata_auto_alloc_size) 1176494d708SSimon Glass dev->flags |= DM_FLAG_ALLOC_PDATA; 1186494d708SSimon Glass 1196494d708SSimon Glass /* put dev into parent's successor list */ 1206494d708SSimon Glass if (parent) 1216494d708SSimon Glass list_add_tail(&dev->sibling_node, &parent->child_head); 1226494d708SSimon Glass 1236494d708SSimon Glass ret = uclass_bind_device(dev); 1246494d708SSimon Glass if (ret) 1256494d708SSimon Glass goto fail_bind; 1266494d708SSimon Glass 1276494d708SSimon Glass /* if we fail to bind we remove device from successors and free it */ 1286494d708SSimon Glass if (drv->bind) { 1296494d708SSimon Glass ret = drv->bind(dev); 1306494d708SSimon Glass if (ret) { 1316494d708SSimon Glass if (uclass_unbind_device(dev)) { 1326494d708SSimon Glass dm_warn("Failed to unbind dev '%s' on error path\n", 1336494d708SSimon Glass dev->name); 1346494d708SSimon Glass } 1356494d708SSimon Glass goto fail_bind; 1366494d708SSimon Glass } 1376494d708SSimon Glass } 1386494d708SSimon Glass if (parent) 1396494d708SSimon Glass dm_dbg("Bound device %s to %s\n", dev->name, parent->name); 1406494d708SSimon Glass *devp = dev; 1416494d708SSimon Glass 1426494d708SSimon Glass return 0; 1436494d708SSimon Glass 1446494d708SSimon Glass fail_bind: 1456494d708SSimon Glass list_del(&dev->sibling_node); 1466494d708SSimon Glass free(dev); 1476494d708SSimon Glass return ret; 1486494d708SSimon Glass } 1496494d708SSimon Glass 15000606d7eSSimon Glass int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, 15100606d7eSSimon Glass const struct driver_info *info, struct udevice **devp) 1526494d708SSimon Glass { 1536494d708SSimon Glass struct driver *drv; 1546494d708SSimon Glass 1556494d708SSimon Glass drv = lists_driver_lookup_name(info->name); 1566494d708SSimon Glass if (!drv) 1576494d708SSimon Glass return -ENOENT; 15800606d7eSSimon Glass if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) 15900606d7eSSimon Glass return -EPERM; 1606494d708SSimon Glass 1616494d708SSimon Glass return device_bind(parent, drv, info->name, (void *)info->platdata, 1626494d708SSimon Glass -1, devp); 1636494d708SSimon Glass } 1646494d708SSimon Glass 16554c5d08aSHeiko Schocher int device_unbind(struct udevice *dev) 1666494d708SSimon Glass { 1676494d708SSimon Glass struct driver *drv; 1686494d708SSimon Glass int ret; 1696494d708SSimon Glass 1706494d708SSimon Glass if (!dev) 1716494d708SSimon Glass return -EINVAL; 1726494d708SSimon Glass 1736494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 1746494d708SSimon Glass return -EINVAL; 1756494d708SSimon Glass 1766494d708SSimon Glass drv = dev->driver; 1776494d708SSimon Glass assert(drv); 1786494d708SSimon Glass 1796494d708SSimon Glass if (drv->unbind) { 1806494d708SSimon Glass ret = drv->unbind(dev); 1816494d708SSimon Glass if (ret) 1826494d708SSimon Glass return ret; 1836494d708SSimon Glass } 1846494d708SSimon Glass 1856494d708SSimon Glass ret = device_chld_unbind(dev); 1866494d708SSimon Glass if (ret) 1876494d708SSimon Glass return ret; 1886494d708SSimon Glass 1896494d708SSimon Glass ret = uclass_unbind_device(dev); 1906494d708SSimon Glass if (ret) 1916494d708SSimon Glass return ret; 1926494d708SSimon Glass 1936494d708SSimon Glass if (dev->parent) 1946494d708SSimon Glass list_del(&dev->sibling_node); 1956494d708SSimon Glass free(dev); 1966494d708SSimon Glass 1976494d708SSimon Glass return 0; 1986494d708SSimon Glass } 1996494d708SSimon Glass 2006494d708SSimon Glass /** 2016494d708SSimon Glass * device_free() - Free memory buffers allocated by a device 2026494d708SSimon Glass * @dev: Device that is to be started 2036494d708SSimon Glass */ 20454c5d08aSHeiko Schocher static void device_free(struct udevice *dev) 2056494d708SSimon Glass { 2066494d708SSimon Glass int size; 2076494d708SSimon Glass 2086494d708SSimon Glass if (dev->driver->priv_auto_alloc_size) { 2096494d708SSimon Glass free(dev->priv); 2106494d708SSimon Glass dev->priv = NULL; 2116494d708SSimon Glass } 2126494d708SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 2136494d708SSimon Glass free(dev->platdata); 2146494d708SSimon Glass dev->platdata = NULL; 2156494d708SSimon Glass } 2166494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 2176494d708SSimon Glass if (size) { 2186494d708SSimon Glass free(dev->uclass_priv); 2196494d708SSimon Glass dev->uclass_priv = NULL; 2206494d708SSimon Glass } 221e59f458dSSimon Glass if (dev->parent) { 222e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 223e59f458dSSimon Glass if (size) { 224e59f458dSSimon Glass free(dev->parent_priv); 225e59f458dSSimon Glass dev->parent_priv = NULL; 226e59f458dSSimon Glass } 227e59f458dSSimon Glass } 2286494d708SSimon Glass } 2296494d708SSimon Glass 23054c5d08aSHeiko Schocher int device_probe(struct udevice *dev) 2316494d708SSimon Glass { 2326494d708SSimon Glass struct driver *drv; 2336494d708SSimon Glass int size = 0; 2346494d708SSimon Glass int ret; 2355a66a8ffSSimon Glass int seq; 2366494d708SSimon Glass 2376494d708SSimon Glass if (!dev) 2386494d708SSimon Glass return -EINVAL; 2396494d708SSimon Glass 2406494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 2416494d708SSimon Glass return 0; 2426494d708SSimon Glass 2436494d708SSimon Glass drv = dev->driver; 2446494d708SSimon Glass assert(drv); 2456494d708SSimon Glass 2466494d708SSimon Glass /* Allocate private data and platdata if requested */ 2476494d708SSimon Glass if (drv->priv_auto_alloc_size) { 2486494d708SSimon Glass dev->priv = calloc(1, drv->priv_auto_alloc_size); 2496494d708SSimon Glass if (!dev->priv) { 2506494d708SSimon Glass ret = -ENOMEM; 2516494d708SSimon Glass goto fail; 2526494d708SSimon Glass } 2536494d708SSimon Glass } 2546494d708SSimon Glass /* Allocate private data if requested */ 2556494d708SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 2566494d708SSimon Glass dev->platdata = calloc(1, drv->platdata_auto_alloc_size); 2576494d708SSimon Glass if (!dev->platdata) { 2586494d708SSimon Glass ret = -ENOMEM; 2596494d708SSimon Glass goto fail; 2606494d708SSimon Glass } 2616494d708SSimon Glass } 2626494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 2636494d708SSimon Glass if (size) { 2646494d708SSimon Glass dev->uclass_priv = calloc(1, size); 2656494d708SSimon Glass if (!dev->uclass_priv) { 2666494d708SSimon Glass ret = -ENOMEM; 2676494d708SSimon Glass goto fail; 2686494d708SSimon Glass } 2696494d708SSimon Glass } 2706494d708SSimon Glass 2716494d708SSimon Glass /* Ensure all parents are probed */ 2726494d708SSimon Glass if (dev->parent) { 273e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 274e59f458dSSimon Glass if (size) { 275e59f458dSSimon Glass dev->parent_priv = calloc(1, size); 276e59f458dSSimon Glass if (!dev->parent_priv) { 277e59f458dSSimon Glass ret = -ENOMEM; 278e59f458dSSimon Glass goto fail; 279e59f458dSSimon Glass } 280e59f458dSSimon Glass } 281e59f458dSSimon Glass 2826494d708SSimon Glass ret = device_probe(dev->parent); 2836494d708SSimon Glass if (ret) 2846494d708SSimon Glass goto fail; 2856494d708SSimon Glass } 2866494d708SSimon Glass 2875a66a8ffSSimon Glass seq = uclass_resolve_seq(dev); 2885a66a8ffSSimon Glass if (seq < 0) { 2895a66a8ffSSimon Glass ret = seq; 2905a66a8ffSSimon Glass goto fail; 2915a66a8ffSSimon Glass } 2925a66a8ffSSimon Glass dev->seq = seq; 2935a66a8ffSSimon Glass 294*a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_pre_probe) { 295*a327dee0SSimon Glass ret = dev->parent->driver->child_pre_probe(dev); 296*a327dee0SSimon Glass if (ret) 297*a327dee0SSimon Glass goto fail; 298*a327dee0SSimon Glass } 299*a327dee0SSimon Glass 3006494d708SSimon Glass if (drv->ofdata_to_platdata && dev->of_offset >= 0) { 3016494d708SSimon Glass ret = drv->ofdata_to_platdata(dev); 3026494d708SSimon Glass if (ret) 3036494d708SSimon Glass goto fail; 3046494d708SSimon Glass } 3056494d708SSimon Glass 3066494d708SSimon Glass if (drv->probe) { 3076494d708SSimon Glass ret = drv->probe(dev); 3086494d708SSimon Glass if (ret) 3096494d708SSimon Glass goto fail; 3106494d708SSimon Glass } 3116494d708SSimon Glass 3126494d708SSimon Glass dev->flags |= DM_FLAG_ACTIVATED; 3136494d708SSimon Glass 3146494d708SSimon Glass ret = uclass_post_probe_device(dev); 3156494d708SSimon Glass if (ret) { 3166494d708SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3176494d708SSimon Glass goto fail_uclass; 3186494d708SSimon Glass } 3196494d708SSimon Glass 3206494d708SSimon Glass return 0; 3216494d708SSimon Glass fail_uclass: 3226494d708SSimon Glass if (device_remove(dev)) { 3236494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove on error path\n", 3246494d708SSimon Glass __func__, dev->name); 3256494d708SSimon Glass } 3266494d708SSimon Glass fail: 3275a66a8ffSSimon Glass dev->seq = -1; 3286494d708SSimon Glass device_free(dev); 3296494d708SSimon Glass 3306494d708SSimon Glass return ret; 3316494d708SSimon Glass } 3326494d708SSimon Glass 33354c5d08aSHeiko Schocher int device_remove(struct udevice *dev) 3346494d708SSimon Glass { 3356494d708SSimon Glass struct driver *drv; 3366494d708SSimon Glass int ret; 3376494d708SSimon Glass 3386494d708SSimon Glass if (!dev) 3396494d708SSimon Glass return -EINVAL; 3406494d708SSimon Glass 3416494d708SSimon Glass if (!(dev->flags & DM_FLAG_ACTIVATED)) 3426494d708SSimon Glass return 0; 3436494d708SSimon Glass 3446494d708SSimon Glass drv = dev->driver; 3456494d708SSimon Glass assert(drv); 3466494d708SSimon Glass 3476494d708SSimon Glass ret = uclass_pre_remove_device(dev); 3486494d708SSimon Glass if (ret) 3496494d708SSimon Glass return ret; 3506494d708SSimon Glass 3516494d708SSimon Glass ret = device_chld_remove(dev); 3526494d708SSimon Glass if (ret) 3536494d708SSimon Glass goto err; 3546494d708SSimon Glass 3556494d708SSimon Glass if (drv->remove) { 3566494d708SSimon Glass ret = drv->remove(dev); 3576494d708SSimon Glass if (ret) 3586494d708SSimon Glass goto err_remove; 3596494d708SSimon Glass } 3606494d708SSimon Glass 361*a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_post_remove) { 362*a327dee0SSimon Glass ret = dev->parent->driver->child_post_remove(dev); 363*a327dee0SSimon Glass if (ret) { 364*a327dee0SSimon Glass dm_warn("%s: Device '%s' failed child_post_remove()", 365*a327dee0SSimon Glass __func__, dev->name); 366*a327dee0SSimon Glass } 367*a327dee0SSimon Glass } 368*a327dee0SSimon Glass 3696494d708SSimon Glass device_free(dev); 3706494d708SSimon Glass 3715a66a8ffSSimon Glass dev->seq = -1; 3726494d708SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3736494d708SSimon Glass 374*a327dee0SSimon Glass return ret; 3756494d708SSimon Glass 3766494d708SSimon Glass err_remove: 3776494d708SSimon Glass /* We can't put the children back */ 3786494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove, but children are gone\n", 3796494d708SSimon Glass __func__, dev->name); 3806494d708SSimon Glass err: 3816494d708SSimon Glass ret = uclass_post_probe_device(dev); 3826494d708SSimon Glass if (ret) { 3836494d708SSimon Glass dm_warn("%s: Device '%s' failed to post_probe on error path\n", 3846494d708SSimon Glass __func__, dev->name); 3856494d708SSimon Glass } 3866494d708SSimon Glass 3876494d708SSimon Glass return ret; 3886494d708SSimon Glass } 3896494d708SSimon Glass 39054c5d08aSHeiko Schocher void *dev_get_platdata(struct udevice *dev) 3916494d708SSimon Glass { 3926494d708SSimon Glass if (!dev) { 3936494d708SSimon Glass dm_warn("%s: null device", __func__); 3946494d708SSimon Glass return NULL; 3956494d708SSimon Glass } 3966494d708SSimon Glass 3976494d708SSimon Glass return dev->platdata; 3986494d708SSimon Glass } 3996494d708SSimon Glass 40054c5d08aSHeiko Schocher void *dev_get_priv(struct udevice *dev) 4016494d708SSimon Glass { 4026494d708SSimon Glass if (!dev) { 4036494d708SSimon Glass dm_warn("%s: null device", __func__); 4046494d708SSimon Glass return NULL; 4056494d708SSimon Glass } 4066494d708SSimon Glass 4076494d708SSimon Glass return dev->priv; 4086494d708SSimon Glass } 409997c87bbSSimon Glass 410e59f458dSSimon Glass void *dev_get_parentdata(struct udevice *dev) 411e59f458dSSimon Glass { 412e59f458dSSimon Glass if (!dev) { 413e59f458dSSimon Glass dm_warn("%s: null device", __func__); 414e59f458dSSimon Glass return NULL; 415e59f458dSSimon Glass } 416e59f458dSSimon Glass 417e59f458dSSimon Glass return dev->parent_priv; 418e59f458dSSimon Glass } 419e59f458dSSimon Glass 420997c87bbSSimon Glass static int device_get_device_tail(struct udevice *dev, int ret, 421997c87bbSSimon Glass struct udevice **devp) 422997c87bbSSimon Glass { 423997c87bbSSimon Glass if (ret) 424997c87bbSSimon Glass return ret; 425997c87bbSSimon Glass 426997c87bbSSimon Glass ret = device_probe(dev); 427997c87bbSSimon Glass if (ret) 428997c87bbSSimon Glass return ret; 429997c87bbSSimon Glass 430997c87bbSSimon Glass *devp = dev; 431997c87bbSSimon Glass 432997c87bbSSimon Glass return 0; 433997c87bbSSimon Glass } 434997c87bbSSimon Glass 435997c87bbSSimon Glass int device_get_child(struct udevice *parent, int index, struct udevice **devp) 436997c87bbSSimon Glass { 437997c87bbSSimon Glass struct udevice *dev; 438997c87bbSSimon Glass 439997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 440997c87bbSSimon Glass if (!index--) 441997c87bbSSimon Glass return device_get_device_tail(dev, 0, devp); 442997c87bbSSimon Glass } 443997c87bbSSimon Glass 444997c87bbSSimon Glass return -ENODEV; 445997c87bbSSimon Glass } 446997c87bbSSimon Glass 447997c87bbSSimon Glass int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, 448997c87bbSSimon Glass bool find_req_seq, struct udevice **devp) 449997c87bbSSimon Glass { 450997c87bbSSimon Glass struct udevice *dev; 451997c87bbSSimon Glass 452997c87bbSSimon Glass *devp = NULL; 453997c87bbSSimon Glass if (seq_or_req_seq == -1) 454997c87bbSSimon Glass return -ENODEV; 455997c87bbSSimon Glass 456997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 457997c87bbSSimon Glass if ((find_req_seq ? dev->req_seq : dev->seq) == 458997c87bbSSimon Glass seq_or_req_seq) { 459997c87bbSSimon Glass *devp = dev; 460997c87bbSSimon Glass return 0; 461997c87bbSSimon Glass } 462997c87bbSSimon Glass } 463997c87bbSSimon Glass 464997c87bbSSimon Glass return -ENODEV; 465997c87bbSSimon Glass } 466997c87bbSSimon Glass 467997c87bbSSimon Glass int device_get_child_by_seq(struct udevice *parent, int seq, 468997c87bbSSimon Glass struct udevice **devp) 469997c87bbSSimon Glass { 470997c87bbSSimon Glass struct udevice *dev; 471997c87bbSSimon Glass int ret; 472997c87bbSSimon Glass 473997c87bbSSimon Glass *devp = NULL; 474997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, false, &dev); 475997c87bbSSimon Glass if (ret == -ENODEV) { 476997c87bbSSimon Glass /* 477997c87bbSSimon Glass * We didn't find it in probed devices. See if there is one 478997c87bbSSimon Glass * that will request this seq if probed. 479997c87bbSSimon Glass */ 480997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, true, &dev); 481997c87bbSSimon Glass } 482997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 483997c87bbSSimon Glass } 484997c87bbSSimon Glass 485997c87bbSSimon Glass int device_find_child_by_of_offset(struct udevice *parent, int of_offset, 486997c87bbSSimon Glass struct udevice **devp) 487997c87bbSSimon Glass { 488997c87bbSSimon Glass struct udevice *dev; 489997c87bbSSimon Glass 490997c87bbSSimon Glass *devp = NULL; 491997c87bbSSimon Glass 492997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 493997c87bbSSimon Glass if (dev->of_offset == of_offset) { 494997c87bbSSimon Glass *devp = dev; 495997c87bbSSimon Glass return 0; 496997c87bbSSimon Glass } 497997c87bbSSimon Glass } 498997c87bbSSimon Glass 499997c87bbSSimon Glass return -ENODEV; 500997c87bbSSimon Glass } 501997c87bbSSimon Glass 502997c87bbSSimon Glass int device_get_child_by_of_offset(struct udevice *parent, int seq, 503997c87bbSSimon Glass struct udevice **devp) 504997c87bbSSimon Glass { 505997c87bbSSimon Glass struct udevice *dev; 506997c87bbSSimon Glass int ret; 507997c87bbSSimon Glass 508997c87bbSSimon Glass *devp = NULL; 509997c87bbSSimon Glass ret = device_find_child_by_of_offset(parent, seq, &dev); 510997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 511997c87bbSSimon Glass } 512