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; 11091cbd792SSimon Glass #ifdef CONFIG_OF_CONTROL 11191cbd792SSimon Glass dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1); 112cae025aaSRobert Baldyga if (!IS_ERR_VALUE(dev->req_seq)) 113cae025aaSRobert Baldyga dev->req_seq &= INT_MAX; 1145a66a8ffSSimon Glass if (uc->uc_drv->name && of_offset != -1) { 1155a66a8ffSSimon Glass fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset, 1165a66a8ffSSimon Glass &dev->req_seq); 1175a66a8ffSSimon Glass } 11891cbd792SSimon Glass #else 11991cbd792SSimon Glass dev->req_seq = -1; 12091cbd792SSimon Glass #endif 1216494d708SSimon Glass if (!dev->platdata && drv->platdata_auto_alloc_size) 1226494d708SSimon Glass dev->flags |= DM_FLAG_ALLOC_PDATA; 1236494d708SSimon Glass 1246494d708SSimon Glass /* put dev into parent's successor list */ 1256494d708SSimon Glass if (parent) 1266494d708SSimon Glass list_add_tail(&dev->sibling_node, &parent->child_head); 1276494d708SSimon Glass 1286494d708SSimon Glass ret = uclass_bind_device(dev); 1296494d708SSimon Glass if (ret) 1306494d708SSimon Glass goto fail_bind; 1316494d708SSimon Glass 1326494d708SSimon Glass /* if we fail to bind we remove device from successors and free it */ 1336494d708SSimon Glass if (drv->bind) { 1346494d708SSimon Glass ret = drv->bind(dev); 1356494d708SSimon Glass if (ret) { 1366494d708SSimon Glass if (uclass_unbind_device(dev)) { 1376494d708SSimon Glass dm_warn("Failed to unbind dev '%s' on error path\n", 1386494d708SSimon Glass dev->name); 1396494d708SSimon Glass } 1406494d708SSimon Glass goto fail_bind; 1416494d708SSimon Glass } 1426494d708SSimon Glass } 1436494d708SSimon Glass if (parent) 1446494d708SSimon Glass dm_dbg("Bound device %s to %s\n", dev->name, parent->name); 1456494d708SSimon Glass *devp = dev; 1466494d708SSimon Glass 1476494d708SSimon Glass return 0; 1486494d708SSimon Glass 1496494d708SSimon Glass fail_bind: 1506494d708SSimon Glass list_del(&dev->sibling_node); 1516494d708SSimon Glass free(dev); 1526494d708SSimon Glass return ret; 1536494d708SSimon Glass } 1546494d708SSimon Glass 15500606d7eSSimon Glass int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, 15600606d7eSSimon Glass const struct driver_info *info, struct udevice **devp) 1576494d708SSimon Glass { 1586494d708SSimon Glass struct driver *drv; 1596494d708SSimon Glass 1606494d708SSimon Glass drv = lists_driver_lookup_name(info->name); 1616494d708SSimon Glass if (!drv) 1626494d708SSimon Glass return -ENOENT; 16300606d7eSSimon Glass if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) 16400606d7eSSimon Glass return -EPERM; 1656494d708SSimon Glass 1666494d708SSimon Glass return device_bind(parent, drv, info->name, (void *)info->platdata, 1676494d708SSimon Glass -1, devp); 1686494d708SSimon Glass } 1696494d708SSimon Glass 17054c5d08aSHeiko Schocher int device_unbind(struct udevice *dev) 1716494d708SSimon Glass { 1726494d708SSimon Glass struct driver *drv; 1736494d708SSimon Glass int ret; 1746494d708SSimon Glass 1756494d708SSimon Glass if (!dev) 1766494d708SSimon Glass return -EINVAL; 1776494d708SSimon Glass 1786494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 1796494d708SSimon Glass return -EINVAL; 1806494d708SSimon Glass 1816494d708SSimon Glass drv = dev->driver; 1826494d708SSimon Glass assert(drv); 1836494d708SSimon Glass 1846494d708SSimon Glass if (drv->unbind) { 1856494d708SSimon Glass ret = drv->unbind(dev); 1866494d708SSimon Glass if (ret) 1876494d708SSimon Glass return ret; 1886494d708SSimon Glass } 1896494d708SSimon Glass 1906494d708SSimon Glass ret = device_chld_unbind(dev); 1916494d708SSimon Glass if (ret) 1926494d708SSimon Glass return ret; 1936494d708SSimon Glass 1946494d708SSimon Glass ret = uclass_unbind_device(dev); 1956494d708SSimon Glass if (ret) 1966494d708SSimon Glass return ret; 1976494d708SSimon Glass 1986494d708SSimon Glass if (dev->parent) 1996494d708SSimon Glass list_del(&dev->sibling_node); 2006494d708SSimon Glass free(dev); 2016494d708SSimon Glass 2026494d708SSimon Glass return 0; 2036494d708SSimon Glass } 2046494d708SSimon Glass 2056494d708SSimon Glass /** 2066494d708SSimon Glass * device_free() - Free memory buffers allocated by a device 2076494d708SSimon Glass * @dev: Device that is to be started 2086494d708SSimon Glass */ 20954c5d08aSHeiko Schocher static void device_free(struct udevice *dev) 2106494d708SSimon Glass { 2116494d708SSimon Glass int size; 2126494d708SSimon Glass 2136494d708SSimon Glass if (dev->driver->priv_auto_alloc_size) { 2146494d708SSimon Glass free(dev->priv); 2156494d708SSimon Glass dev->priv = NULL; 2166494d708SSimon Glass } 2176494d708SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 2186494d708SSimon Glass free(dev->platdata); 2196494d708SSimon Glass dev->platdata = NULL; 2206494d708SSimon Glass } 2216494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 2226494d708SSimon Glass if (size) { 2236494d708SSimon Glass free(dev->uclass_priv); 2246494d708SSimon Glass dev->uclass_priv = NULL; 2256494d708SSimon Glass } 226e59f458dSSimon Glass if (dev->parent) { 227e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 228e59f458dSSimon Glass if (size) { 229e59f458dSSimon Glass free(dev->parent_priv); 230e59f458dSSimon Glass dev->parent_priv = NULL; 231e59f458dSSimon Glass } 232e59f458dSSimon Glass } 2336494d708SSimon Glass } 2346494d708SSimon Glass 235*accd4b19SSimon Glass int device_probe_child(struct udevice *dev, void *parent_priv) 2366494d708SSimon Glass { 2376494d708SSimon Glass struct driver *drv; 2386494d708SSimon Glass int size = 0; 2396494d708SSimon Glass int ret; 2405a66a8ffSSimon Glass int seq; 2416494d708SSimon Glass 2426494d708SSimon Glass if (!dev) 2436494d708SSimon Glass return -EINVAL; 2446494d708SSimon Glass 2456494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED) 2466494d708SSimon Glass return 0; 2476494d708SSimon Glass 2486494d708SSimon Glass drv = dev->driver; 2496494d708SSimon Glass assert(drv); 2506494d708SSimon Glass 2516494d708SSimon Glass /* Allocate private data and platdata if requested */ 2526494d708SSimon Glass if (drv->priv_auto_alloc_size) { 2536494d708SSimon Glass dev->priv = calloc(1, drv->priv_auto_alloc_size); 2546494d708SSimon Glass if (!dev->priv) { 2556494d708SSimon Glass ret = -ENOMEM; 2566494d708SSimon Glass goto fail; 2576494d708SSimon Glass } 2586494d708SSimon Glass } 2596494d708SSimon Glass /* Allocate private data if requested */ 2606494d708SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) { 2616494d708SSimon Glass dev->platdata = calloc(1, drv->platdata_auto_alloc_size); 2626494d708SSimon Glass if (!dev->platdata) { 2636494d708SSimon Glass ret = -ENOMEM; 2646494d708SSimon Glass goto fail; 2656494d708SSimon Glass } 2666494d708SSimon Glass } 2676494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size; 2686494d708SSimon Glass if (size) { 2696494d708SSimon Glass dev->uclass_priv = calloc(1, size); 2706494d708SSimon Glass if (!dev->uclass_priv) { 2716494d708SSimon Glass ret = -ENOMEM; 2726494d708SSimon Glass goto fail; 2736494d708SSimon Glass } 2746494d708SSimon Glass } 2756494d708SSimon Glass 2766494d708SSimon Glass /* Ensure all parents are probed */ 2776494d708SSimon Glass if (dev->parent) { 278e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size; 279e59f458dSSimon Glass if (size) { 280e59f458dSSimon Glass dev->parent_priv = calloc(1, size); 281e59f458dSSimon Glass if (!dev->parent_priv) { 282e59f458dSSimon Glass ret = -ENOMEM; 283e59f458dSSimon Glass goto fail; 284e59f458dSSimon Glass } 285*accd4b19SSimon Glass if (parent_priv) 286*accd4b19SSimon Glass memcpy(dev->parent_priv, parent_priv, size); 287e59f458dSSimon Glass } 288e59f458dSSimon Glass 2896494d708SSimon Glass ret = device_probe(dev->parent); 2906494d708SSimon Glass if (ret) 2916494d708SSimon Glass goto fail; 2926494d708SSimon Glass } 2936494d708SSimon Glass 2945a66a8ffSSimon Glass seq = uclass_resolve_seq(dev); 2955a66a8ffSSimon Glass if (seq < 0) { 2965a66a8ffSSimon Glass ret = seq; 2975a66a8ffSSimon Glass goto fail; 2985a66a8ffSSimon Glass } 2995a66a8ffSSimon Glass dev->seq = seq; 3005a66a8ffSSimon Glass 301a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_pre_probe) { 302a327dee0SSimon Glass ret = dev->parent->driver->child_pre_probe(dev); 303a327dee0SSimon Glass if (ret) 304a327dee0SSimon Glass goto fail; 305a327dee0SSimon Glass } 306a327dee0SSimon Glass 3076494d708SSimon Glass if (drv->ofdata_to_platdata && dev->of_offset >= 0) { 3086494d708SSimon Glass ret = drv->ofdata_to_platdata(dev); 3096494d708SSimon Glass if (ret) 3106494d708SSimon Glass goto fail; 3116494d708SSimon Glass } 3126494d708SSimon Glass 3136494d708SSimon Glass if (drv->probe) { 3146494d708SSimon Glass ret = drv->probe(dev); 3156494d708SSimon Glass if (ret) 3166494d708SSimon Glass goto fail; 3176494d708SSimon Glass } 3186494d708SSimon Glass 3196494d708SSimon Glass dev->flags |= DM_FLAG_ACTIVATED; 3206494d708SSimon Glass 3216494d708SSimon Glass ret = uclass_post_probe_device(dev); 3226494d708SSimon Glass if (ret) { 3236494d708SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3246494d708SSimon Glass goto fail_uclass; 3256494d708SSimon Glass } 3266494d708SSimon Glass 3276494d708SSimon Glass return 0; 3286494d708SSimon Glass fail_uclass: 3296494d708SSimon Glass if (device_remove(dev)) { 3306494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove on error path\n", 3316494d708SSimon Glass __func__, dev->name); 3326494d708SSimon Glass } 3336494d708SSimon Glass fail: 3345a66a8ffSSimon Glass dev->seq = -1; 3356494d708SSimon Glass device_free(dev); 3366494d708SSimon Glass 3376494d708SSimon Glass return ret; 3386494d708SSimon Glass } 3396494d708SSimon Glass 340*accd4b19SSimon Glass int device_probe(struct udevice *dev) 341*accd4b19SSimon Glass { 342*accd4b19SSimon Glass return device_probe_child(dev, NULL); 343*accd4b19SSimon Glass } 344*accd4b19SSimon Glass 34554c5d08aSHeiko Schocher int device_remove(struct udevice *dev) 3466494d708SSimon Glass { 3476494d708SSimon Glass struct driver *drv; 3486494d708SSimon Glass int ret; 3496494d708SSimon Glass 3506494d708SSimon Glass if (!dev) 3516494d708SSimon Glass return -EINVAL; 3526494d708SSimon Glass 3536494d708SSimon Glass if (!(dev->flags & DM_FLAG_ACTIVATED)) 3546494d708SSimon Glass return 0; 3556494d708SSimon Glass 3566494d708SSimon Glass drv = dev->driver; 3576494d708SSimon Glass assert(drv); 3586494d708SSimon Glass 3596494d708SSimon Glass ret = uclass_pre_remove_device(dev); 3606494d708SSimon Glass if (ret) 3616494d708SSimon Glass return ret; 3626494d708SSimon Glass 3636494d708SSimon Glass ret = device_chld_remove(dev); 3646494d708SSimon Glass if (ret) 3656494d708SSimon Glass goto err; 3666494d708SSimon Glass 3676494d708SSimon Glass if (drv->remove) { 3686494d708SSimon Glass ret = drv->remove(dev); 3696494d708SSimon Glass if (ret) 3706494d708SSimon Glass goto err_remove; 3716494d708SSimon Glass } 3726494d708SSimon Glass 373a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_post_remove) { 374a327dee0SSimon Glass ret = dev->parent->driver->child_post_remove(dev); 375a327dee0SSimon Glass if (ret) { 376a327dee0SSimon Glass dm_warn("%s: Device '%s' failed child_post_remove()", 377a327dee0SSimon Glass __func__, dev->name); 378a327dee0SSimon Glass } 379a327dee0SSimon Glass } 380a327dee0SSimon Glass 3816494d708SSimon Glass device_free(dev); 3826494d708SSimon Glass 3835a66a8ffSSimon Glass dev->seq = -1; 3846494d708SSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED; 3856494d708SSimon Glass 386a327dee0SSimon Glass return ret; 3876494d708SSimon Glass 3886494d708SSimon Glass err_remove: 3896494d708SSimon Glass /* We can't put the children back */ 3906494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove, but children are gone\n", 3916494d708SSimon Glass __func__, dev->name); 3926494d708SSimon Glass err: 3936494d708SSimon Glass ret = uclass_post_probe_device(dev); 3946494d708SSimon Glass if (ret) { 3956494d708SSimon Glass dm_warn("%s: Device '%s' failed to post_probe on error path\n", 3966494d708SSimon Glass __func__, dev->name); 3976494d708SSimon Glass } 3986494d708SSimon Glass 3996494d708SSimon Glass return ret; 4006494d708SSimon Glass } 4016494d708SSimon Glass 40254c5d08aSHeiko Schocher void *dev_get_platdata(struct udevice *dev) 4036494d708SSimon Glass { 4046494d708SSimon Glass if (!dev) { 4056494d708SSimon Glass dm_warn("%s: null device", __func__); 4066494d708SSimon Glass return NULL; 4076494d708SSimon Glass } 4086494d708SSimon Glass 4096494d708SSimon Glass return dev->platdata; 4106494d708SSimon Glass } 4116494d708SSimon Glass 41254c5d08aSHeiko Schocher void *dev_get_priv(struct udevice *dev) 4136494d708SSimon Glass { 4146494d708SSimon Glass if (!dev) { 4156494d708SSimon Glass dm_warn("%s: null device", __func__); 4166494d708SSimon Glass return NULL; 4176494d708SSimon Glass } 4186494d708SSimon Glass 4196494d708SSimon Glass return dev->priv; 4206494d708SSimon Glass } 421997c87bbSSimon Glass 422e59f458dSSimon Glass void *dev_get_parentdata(struct udevice *dev) 423e59f458dSSimon Glass { 424e59f458dSSimon Glass if (!dev) { 425e59f458dSSimon Glass dm_warn("%s: null device", __func__); 426e59f458dSSimon Glass return NULL; 427e59f458dSSimon Glass } 428e59f458dSSimon Glass 429e59f458dSSimon Glass return dev->parent_priv; 430e59f458dSSimon Glass } 431e59f458dSSimon Glass 432997c87bbSSimon Glass static int device_get_device_tail(struct udevice *dev, int ret, 433997c87bbSSimon Glass struct udevice **devp) 434997c87bbSSimon Glass { 435997c87bbSSimon Glass if (ret) 436997c87bbSSimon Glass return ret; 437997c87bbSSimon Glass 438997c87bbSSimon Glass ret = device_probe(dev); 439997c87bbSSimon Glass if (ret) 440997c87bbSSimon Glass return ret; 441997c87bbSSimon Glass 442997c87bbSSimon Glass *devp = dev; 443997c87bbSSimon Glass 444997c87bbSSimon Glass return 0; 445997c87bbSSimon Glass } 446997c87bbSSimon Glass 447997c87bbSSimon Glass int device_get_child(struct udevice *parent, int index, struct udevice **devp) 448997c87bbSSimon Glass { 449997c87bbSSimon Glass struct udevice *dev; 450997c87bbSSimon Glass 451997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 452997c87bbSSimon Glass if (!index--) 453997c87bbSSimon Glass return device_get_device_tail(dev, 0, devp); 454997c87bbSSimon Glass } 455997c87bbSSimon Glass 456997c87bbSSimon Glass return -ENODEV; 457997c87bbSSimon Glass } 458997c87bbSSimon Glass 459997c87bbSSimon Glass int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, 460997c87bbSSimon Glass bool find_req_seq, struct udevice **devp) 461997c87bbSSimon Glass { 462997c87bbSSimon Glass struct udevice *dev; 463997c87bbSSimon Glass 464997c87bbSSimon Glass *devp = NULL; 465997c87bbSSimon Glass if (seq_or_req_seq == -1) 466997c87bbSSimon Glass return -ENODEV; 467997c87bbSSimon Glass 468997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 469997c87bbSSimon Glass if ((find_req_seq ? dev->req_seq : dev->seq) == 470997c87bbSSimon Glass seq_or_req_seq) { 471997c87bbSSimon Glass *devp = dev; 472997c87bbSSimon Glass return 0; 473997c87bbSSimon Glass } 474997c87bbSSimon Glass } 475997c87bbSSimon Glass 476997c87bbSSimon Glass return -ENODEV; 477997c87bbSSimon Glass } 478997c87bbSSimon Glass 479997c87bbSSimon Glass int device_get_child_by_seq(struct udevice *parent, int seq, 480997c87bbSSimon Glass struct udevice **devp) 481997c87bbSSimon Glass { 482997c87bbSSimon Glass struct udevice *dev; 483997c87bbSSimon Glass int ret; 484997c87bbSSimon Glass 485997c87bbSSimon Glass *devp = NULL; 486997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, false, &dev); 487997c87bbSSimon Glass if (ret == -ENODEV) { 488997c87bbSSimon Glass /* 489997c87bbSSimon Glass * We didn't find it in probed devices. See if there is one 490997c87bbSSimon Glass * that will request this seq if probed. 491997c87bbSSimon Glass */ 492997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, true, &dev); 493997c87bbSSimon Glass } 494997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 495997c87bbSSimon Glass } 496997c87bbSSimon Glass 497997c87bbSSimon Glass int device_find_child_by_of_offset(struct udevice *parent, int of_offset, 498997c87bbSSimon Glass struct udevice **devp) 499997c87bbSSimon Glass { 500997c87bbSSimon Glass struct udevice *dev; 501997c87bbSSimon Glass 502997c87bbSSimon Glass *devp = NULL; 503997c87bbSSimon Glass 504997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) { 505997c87bbSSimon Glass if (dev->of_offset == of_offset) { 506997c87bbSSimon Glass *devp = dev; 507997c87bbSSimon Glass return 0; 508997c87bbSSimon Glass } 509997c87bbSSimon Glass } 510997c87bbSSimon Glass 511997c87bbSSimon Glass return -ENODEV; 512997c87bbSSimon Glass } 513997c87bbSSimon Glass 514997c87bbSSimon Glass int device_get_child_by_of_offset(struct udevice *parent, int seq, 515997c87bbSSimon Glass struct udevice **devp) 516997c87bbSSimon Glass { 517997c87bbSSimon Glass struct udevice *dev; 518997c87bbSSimon Glass int ret; 519997c87bbSSimon Glass 520997c87bbSSimon Glass *devp = NULL; 521997c87bbSSimon Glass ret = device_find_child_by_of_offset(parent, seq, &dev); 522997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp); 523997c87bbSSimon Glass } 524a8981d4fSSimon Glass 525a8981d4fSSimon Glass int device_find_first_child(struct udevice *parent, struct udevice **devp) 526a8981d4fSSimon Glass { 527a8981d4fSSimon Glass if (list_empty(&parent->child_head)) { 528a8981d4fSSimon Glass *devp = NULL; 529a8981d4fSSimon Glass } else { 530a8981d4fSSimon Glass *devp = list_first_entry(&parent->child_head, struct udevice, 531a8981d4fSSimon Glass sibling_node); 532a8981d4fSSimon Glass } 533a8981d4fSSimon Glass 534a8981d4fSSimon Glass return 0; 535a8981d4fSSimon Glass } 536a8981d4fSSimon Glass 537a8981d4fSSimon Glass int device_find_next_child(struct udevice **devp) 538a8981d4fSSimon Glass { 539a8981d4fSSimon Glass struct udevice *dev = *devp; 540a8981d4fSSimon Glass struct udevice *parent = dev->parent; 541a8981d4fSSimon Glass 542a8981d4fSSimon Glass if (list_is_last(&dev->sibling_node, &parent->child_head)) { 543a8981d4fSSimon Glass *devp = NULL; 544a8981d4fSSimon Glass } else { 545a8981d4fSSimon Glass *devp = list_entry(dev->sibling_node.next, struct udevice, 546a8981d4fSSimon Glass sibling_node); 547a8981d4fSSimon Glass } 548a8981d4fSSimon Glass 549a8981d4fSSimon Glass return 0; 550a8981d4fSSimon Glass } 551