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->seq = -1; 110*91cbd792SSimon Glass #ifdef CONFIG_OF_CONTROL 111*91cbd792SSimon Glass dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1); 1125a66a8ffSSimon Glass if (uc->uc_drv->name && of_offset != -1) { 1135a66a8ffSSimon Glass fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset, 1145a66a8ffSSimon Glass &dev->req_seq); 1155a66a8ffSSimon Glass } 116*91cbd792SSimon Glass #else 117*91cbd792SSimon Glass dev->req_seq = -1; 118*91cbd792SSimon Glass #endif 1196494d708SSimon Glass if (!dev->platdata && drv->platdata_auto_alloc_size) 1206494d708SSimon Glass dev->flags |= DM_FLAG_ALLOC_PDATA; 1216494d708SSimon Glass 1226494d708SSimon Glass /* put dev into parent's successor list */ 1236494d708SSimon Glass if (parent) 1246494d708SSimon Glass list_add_tail(&dev->sibling_node, &parent->child_head); 1256494d708SSimon Glass 1266494d708SSimon Glass ret = uclass_bind_device(dev); 1276494d708SSimon Glass if (ret) 1286494d708SSimon Glass goto fail_bind; 1296494d708SSimon Glass 1306494d708SSimon Glass /* if we fail to bind we remove device from successors and free it */ 1316494d708SSimon Glass if (drv->bind) { 1326494d708SSimon Glass ret = drv->bind(dev); 1336494d708SSimon Glass if (ret) { 1346494d708SSimon Glass if (uclass_unbind_device(dev)) { 1356494d708SSimon Glass dm_warn("Failed to unbind dev '%s' on error path\n", 1366494d708SSimon Glass dev->name); 1376494d708SSimon Glass } 1386494d708SSimon Glass goto fail_bind; 1396494d708SSimon Glass } 1406494d708SSimon Glass } 1416494d708SSimon Glass if (parent) 1426494d708SSimon Glass dm_dbg("Bound device %s to %s\n", dev->name, parent->name); 1436494d708SSimon Glass *devp = dev; 1446494d708SSimon Glass 1456494d708SSimon Glass return 0; 1466494d708SSimon Glass 1476494d708SSimon Glass fail_bind: 1486494d708SSimon Glass list_del(&dev->sibling_node); 1496494d708SSimon Glass free(dev); 1506494d708SSimon Glass return ret; 1516494d708SSimon Glass } 1526494d708SSimon Glass 15300606d7eSSimon Glass int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, 15400606d7eSSimon Glass const struct driver_info *info, struct udevice **devp) 1556494d708SSimon Glass { 1566494d708SSimon Glass struct driver *drv; 1576494d708SSimon Glass 1586494d708SSimon Glass drv = lists_driver_lookup_name(info->name); 1596494d708SSimon Glass if (!drv) 1606494d708SSimon Glass return -ENOENT; 16100606d7eSSimon Glass if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) 16200606d7eSSimon Glass return -EPERM; 1636494d708SSimon Glass 1646494d708SSimon Glass return device_bind(parent, drv, info->name, (void *)info->platdata, 1656494d708SSimon Glass -1, devp); 1666494d708SSimon Glass } 1676494d708SSimon Glass 16854c5d08aSHeiko Schocher int device_unbind(struct udevice *dev) 1696494d708SSimon Glass { 1706494d708SSimon Glass struct driver *drv; 1716494d708SSimon Glass int ret; 1726494d708SSimon Glass 1736494d708SSimon Glass if (!dev) 1746494d708SSimon Glass return -EINVAL; 1756494d708SSimon Glass 1766494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 1776494d708SSimon Glass return -EINVAL; 1786494d708SSimon Glass 1796494d708SSimon Glass drv = dev->driver; 1806494d708SSimon Glass assert(drv); 1816494d708SSimon Glass 1826494d708SSimon Glass if (drv->unbind) { 1836494d708SSimon Glass ret = drv->unbind(dev); 1846494d708SSimon Glass if (ret) 1856494d708SSimon Glass return ret; 1866494d708SSimon Glass } 1876494d708SSimon Glass 1886494d708SSimon Glass ret = device_chld_unbind(dev); 1896494d708SSimon Glass if (ret) 1906494d708SSimon Glass return ret; 1916494d708SSimon Glass 1926494d708SSimon Glass ret = uclass_unbind_device(dev); 1936494d708SSimon Glass if (ret) 1946494d708SSimon Glass return ret; 1956494d708SSimon Glass 1966494d708SSimon Glass if (dev->parent) 1976494d708SSimon Glass list_del(&dev->sibling_node); 1986494d708SSimon Glass free(dev); 1996494d708SSimon Glass 2006494d708SSimon Glass return 0; 2016494d708SSimon Glass } 2026494d708SSimon Glass 2036494d708SSimon Glass /** 2046494d708SSimon Glass * device_free() - Free memory buffers allocated by a device 2056494d708SSimon Glass * @dev: Device that is to be started 2066494d708SSimon Glass */ 20754c5d08aSHeiko Schocher static void device_free(struct udevice *dev) 2086494d708SSimon Glass { 2096494d708SSimon Glass int size; 2106494d708SSimon Glass 2116494d708SSimon Glass if (dev->driver->priv_auto_alloc_size) { 2126494d708SSimon Glass free(dev->priv); 2136494d708SSimon Glass dev->priv = NULL; 2146494d708SSimon Glass } 2156494d708SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 2166494d708SSimon Glass free(dev->platdata); 2176494d708SSimon Glass dev->platdata = NULL; 2186494d708SSimon Glass } 2196494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 2206494d708SSimon Glass if (size) { 2216494d708SSimon Glass free(dev->uclass_priv); 2226494d708SSimon Glass dev->uclass_priv = NULL; 2236494d708SSimon Glass } 224e59f458dSSimon Glass if (dev->parent) { 225e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 226e59f458dSSimon Glass if (size) { 227e59f458dSSimon Glass free(dev->parent_priv); 228e59f458dSSimon Glass dev->parent_priv = NULL; 229e59f458dSSimon Glass } 230e59f458dSSimon Glass } 2316494d708SSimon Glass } 2326494d708SSimon Glass 23354c5d08aSHeiko Schocher int device_probe(struct udevice *dev) 2346494d708SSimon Glass { 2356494d708SSimon Glass struct driver *drv; 2366494d708SSimon Glass int size = 0; 2376494d708SSimon Glass int ret; 2385a66a8ffSSimon Glass int seq; 2396494d708SSimon Glass 2406494d708SSimon Glass if (!dev) 2416494d708SSimon Glass return -EINVAL; 2426494d708SSimon Glass 2436494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 2446494d708SSimon Glass return 0; 2456494d708SSimon Glass 2466494d708SSimon Glass drv = dev->driver; 2476494d708SSimon Glass assert(drv); 2486494d708SSimon Glass 2496494d708SSimon Glass /* Allocate private data and platdata if requested */ 2506494d708SSimon Glass if (drv->priv_auto_alloc_size) { 2516494d708SSimon Glass dev->priv = calloc(1, drv->priv_auto_alloc_size); 2526494d708SSimon Glass if (!dev->priv) { 2536494d708SSimon Glass ret = -ENOMEM; 2546494d708SSimon Glass goto fail; 2556494d708SSimon Glass } 2566494d708SSimon Glass } 2576494d708SSimon Glass /* Allocate private data if requested */ 2586494d708SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 2596494d708SSimon Glass dev->platdata = calloc(1, drv->platdata_auto_alloc_size); 2606494d708SSimon Glass if (!dev->platdata) { 2616494d708SSimon Glass ret = -ENOMEM; 2626494d708SSimon Glass goto fail; 2636494d708SSimon Glass } 2646494d708SSimon Glass } 2656494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 2666494d708SSimon Glass if (size) { 2676494d708SSimon Glass dev->uclass_priv = calloc(1, size); 2686494d708SSimon Glass if (!dev->uclass_priv) { 2696494d708SSimon Glass ret = -ENOMEM; 2706494d708SSimon Glass goto fail; 2716494d708SSimon Glass } 2726494d708SSimon Glass } 2736494d708SSimon Glass 2746494d708SSimon Glass /* Ensure all parents are probed */ 2756494d708SSimon Glass if (dev->parent) { 276e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 277e59f458dSSimon Glass if (size) { 278e59f458dSSimon Glass dev->parent_priv = calloc(1, size); 279e59f458dSSimon Glass if (!dev->parent_priv) { 280e59f458dSSimon Glass ret = -ENOMEM; 281e59f458dSSimon Glass goto fail; 282e59f458dSSimon Glass } 283e59f458dSSimon Glass } 284e59f458dSSimon Glass 2856494d708SSimon Glass ret = device_probe(dev->parent); 2866494d708SSimon Glass if (ret) 2876494d708SSimon Glass goto fail; 2886494d708SSimon Glass } 2896494d708SSimon Glass 2905a66a8ffSSimon Glass seq = uclass_resolve_seq(dev); 2915a66a8ffSSimon Glass if (seq < 0) { 2925a66a8ffSSimon Glass ret = seq; 2935a66a8ffSSimon Glass goto fail; 2945a66a8ffSSimon Glass } 2955a66a8ffSSimon Glass dev->seq = seq; 2965a66a8ffSSimon Glass 297a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_pre_probe) { 298a327dee0SSimon Glass ret = dev->parent->driver->child_pre_probe(dev); 299a327dee0SSimon Glass if (ret) 300a327dee0SSimon Glass goto fail; 301a327dee0SSimon Glass } 302a327dee0SSimon Glass 3036494d708SSimon Glass if (drv->ofdata_to_platdata && dev->of_offset >= 0) { 3046494d708SSimon Glass ret = drv->ofdata_to_platdata(dev); 3056494d708SSimon Glass if (ret) 3066494d708SSimon Glass goto fail; 3076494d708SSimon Glass } 3086494d708SSimon Glass 3096494d708SSimon Glass if (drv->probe) { 3106494d708SSimon Glass ret = drv->probe(dev); 3116494d708SSimon Glass if (ret) 3126494d708SSimon Glass goto fail; 3136494d708SSimon Glass } 3146494d708SSimon Glass 3156494d708SSimon Glass dev->flags |= DM_FLAG_ACTIVATED; 3166494d708SSimon Glass 3176494d708SSimon Glass ret = uclass_post_probe_device(dev); 3186494d708SSimon Glass if (ret) { 3196494d708SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3206494d708SSimon Glass goto fail_uclass; 3216494d708SSimon Glass } 3226494d708SSimon Glass 3236494d708SSimon Glass return 0; 3246494d708SSimon Glass fail_uclass: 3256494d708SSimon Glass if (device_remove(dev)) { 3266494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove on error path\n", 3276494d708SSimon Glass __func__, dev->name); 3286494d708SSimon Glass } 3296494d708SSimon Glass fail: 3305a66a8ffSSimon Glass dev->seq = -1; 3316494d708SSimon Glass device_free(dev); 3326494d708SSimon Glass 3336494d708SSimon Glass return ret; 3346494d708SSimon Glass } 3356494d708SSimon Glass 33654c5d08aSHeiko Schocher int device_remove(struct udevice *dev) 3376494d708SSimon Glass { 3386494d708SSimon Glass struct driver *drv; 3396494d708SSimon Glass int ret; 3406494d708SSimon Glass 3416494d708SSimon Glass if (!dev) 3426494d708SSimon Glass return -EINVAL; 3436494d708SSimon Glass 3446494d708SSimon Glass if (!(dev->flags & DM_FLAG_ACTIVATED)) 3456494d708SSimon Glass return 0; 3466494d708SSimon Glass 3476494d708SSimon Glass drv = dev->driver; 3486494d708SSimon Glass assert(drv); 3496494d708SSimon Glass 3506494d708SSimon Glass ret = uclass_pre_remove_device(dev); 3516494d708SSimon Glass if (ret) 3526494d708SSimon Glass return ret; 3536494d708SSimon Glass 3546494d708SSimon Glass ret = device_chld_remove(dev); 3556494d708SSimon Glass if (ret) 3566494d708SSimon Glass goto err; 3576494d708SSimon Glass 3586494d708SSimon Glass if (drv->remove) { 3596494d708SSimon Glass ret = drv->remove(dev); 3606494d708SSimon Glass if (ret) 3616494d708SSimon Glass goto err_remove; 3626494d708SSimon Glass } 3636494d708SSimon Glass 364a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_post_remove) { 365a327dee0SSimon Glass ret = dev->parent->driver->child_post_remove(dev); 366a327dee0SSimon Glass if (ret) { 367a327dee0SSimon Glass dm_warn("%s: Device '%s' failed child_post_remove()", 368a327dee0SSimon Glass __func__, dev->name); 369a327dee0SSimon Glass } 370a327dee0SSimon Glass } 371a327dee0SSimon Glass 3726494d708SSimon Glass device_free(dev); 3736494d708SSimon Glass 3745a66a8ffSSimon Glass dev->seq = -1; 3756494d708SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3766494d708SSimon Glass 377a327dee0SSimon Glass return ret; 3786494d708SSimon Glass 3796494d708SSimon Glass err_remove: 3806494d708SSimon Glass /* We can't put the children back */ 3816494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove, but children are gone\n", 3826494d708SSimon Glass __func__, dev->name); 3836494d708SSimon Glass err: 3846494d708SSimon Glass ret = uclass_post_probe_device(dev); 3856494d708SSimon Glass if (ret) { 3866494d708SSimon Glass dm_warn("%s: Device '%s' failed to post_probe on error path\n", 3876494d708SSimon Glass __func__, dev->name); 3886494d708SSimon Glass } 3896494d708SSimon Glass 3906494d708SSimon Glass return ret; 3916494d708SSimon Glass } 3926494d708SSimon Glass 39354c5d08aSHeiko Schocher void *dev_get_platdata(struct udevice *dev) 3946494d708SSimon Glass { 3956494d708SSimon Glass if (!dev) { 3966494d708SSimon Glass dm_warn("%s: null device", __func__); 3976494d708SSimon Glass return NULL; 3986494d708SSimon Glass } 3996494d708SSimon Glass 4006494d708SSimon Glass return dev->platdata; 4016494d708SSimon Glass } 4026494d708SSimon Glass 40354c5d08aSHeiko Schocher void *dev_get_priv(struct udevice *dev) 4046494d708SSimon Glass { 4056494d708SSimon Glass if (!dev) { 4066494d708SSimon Glass dm_warn("%s: null device", __func__); 4076494d708SSimon Glass return NULL; 4086494d708SSimon Glass } 4096494d708SSimon Glass 4106494d708SSimon Glass return dev->priv; 4116494d708SSimon Glass } 412997c87bbSSimon Glass 413e59f458dSSimon Glass void *dev_get_parentdata(struct udevice *dev) 414e59f458dSSimon Glass { 415e59f458dSSimon Glass if (!dev) { 416e59f458dSSimon Glass dm_warn("%s: null device", __func__); 417e59f458dSSimon Glass return NULL; 418e59f458dSSimon Glass } 419e59f458dSSimon Glass 420e59f458dSSimon Glass return dev->parent_priv; 421e59f458dSSimon Glass } 422e59f458dSSimon Glass 423997c87bbSSimon Glass static int device_get_device_tail(struct udevice *dev, int ret, 424997c87bbSSimon Glass struct udevice **devp) 425997c87bbSSimon Glass { 426997c87bbSSimon Glass if (ret) 427997c87bbSSimon Glass return ret; 428997c87bbSSimon Glass 429997c87bbSSimon Glass ret = device_probe(dev); 430997c87bbSSimon Glass if (ret) 431997c87bbSSimon Glass return ret; 432997c87bbSSimon Glass 433997c87bbSSimon Glass *devp = dev; 434997c87bbSSimon Glass 435997c87bbSSimon Glass return 0; 436997c87bbSSimon Glass } 437997c87bbSSimon Glass 438997c87bbSSimon Glass int device_get_child(struct udevice *parent, int index, struct udevice **devp) 439997c87bbSSimon Glass { 440997c87bbSSimon Glass struct udevice *dev; 441997c87bbSSimon Glass 442997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 443997c87bbSSimon Glass if (!index--) 444997c87bbSSimon Glass return device_get_device_tail(dev, 0, devp); 445997c87bbSSimon Glass } 446997c87bbSSimon Glass 447997c87bbSSimon Glass return -ENODEV; 448997c87bbSSimon Glass } 449997c87bbSSimon Glass 450997c87bbSSimon Glass int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, 451997c87bbSSimon Glass bool find_req_seq, struct udevice **devp) 452997c87bbSSimon Glass { 453997c87bbSSimon Glass struct udevice *dev; 454997c87bbSSimon Glass 455997c87bbSSimon Glass *devp = NULL; 456997c87bbSSimon Glass if (seq_or_req_seq == -1) 457997c87bbSSimon Glass return -ENODEV; 458997c87bbSSimon Glass 459997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 460997c87bbSSimon Glass if ((find_req_seq ? dev->req_seq : dev->seq) == 461997c87bbSSimon Glass seq_or_req_seq) { 462997c87bbSSimon Glass *devp = dev; 463997c87bbSSimon Glass return 0; 464997c87bbSSimon Glass } 465997c87bbSSimon Glass } 466997c87bbSSimon Glass 467997c87bbSSimon Glass return -ENODEV; 468997c87bbSSimon Glass } 469997c87bbSSimon Glass 470997c87bbSSimon Glass int device_get_child_by_seq(struct udevice *parent, int seq, 471997c87bbSSimon Glass struct udevice **devp) 472997c87bbSSimon Glass { 473997c87bbSSimon Glass struct udevice *dev; 474997c87bbSSimon Glass int ret; 475997c87bbSSimon Glass 476997c87bbSSimon Glass *devp = NULL; 477997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, false, &dev); 478997c87bbSSimon Glass if (ret == -ENODEV) { 479997c87bbSSimon Glass /* 480997c87bbSSimon Glass * We didn't find it in probed devices. See if there is one 481997c87bbSSimon Glass * that will request this seq if probed. 482997c87bbSSimon Glass */ 483997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, true, &dev); 484997c87bbSSimon Glass } 485997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 486997c87bbSSimon Glass } 487997c87bbSSimon Glass 488997c87bbSSimon Glass int device_find_child_by_of_offset(struct udevice *parent, int of_offset, 489997c87bbSSimon Glass struct udevice **devp) 490997c87bbSSimon Glass { 491997c87bbSSimon Glass struct udevice *dev; 492997c87bbSSimon Glass 493997c87bbSSimon Glass *devp = NULL; 494997c87bbSSimon Glass 495997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 496997c87bbSSimon Glass if (dev->of_offset == of_offset) { 497997c87bbSSimon Glass *devp = dev; 498997c87bbSSimon Glass return 0; 499997c87bbSSimon Glass } 500997c87bbSSimon Glass } 501997c87bbSSimon Glass 502997c87bbSSimon Glass return -ENODEV; 503997c87bbSSimon Glass } 504997c87bbSSimon Glass 505997c87bbSSimon Glass int device_get_child_by_of_offset(struct udevice *parent, int seq, 506997c87bbSSimon Glass struct udevice **devp) 507997c87bbSSimon Glass { 508997c87bbSSimon Glass struct udevice *dev; 509997c87bbSSimon Glass int ret; 510997c87bbSSimon Glass 511997c87bbSSimon Glass *devp = NULL; 512997c87bbSSimon Glass ret = device_find_child_by_of_offset(parent, seq, &dev); 513997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 514997c87bbSSimon Glass } 515