16494d708SSimon Glass /* 26494d708SSimon Glass * Copyright (c) 2013 Google, Inc 36494d708SSimon Glass * 46494d708SSimon Glass * (C) Copyright 2012 56494d708SSimon Glass * Pavel Herrmann <morpheus.ibis@gmail.com> 66494d708SSimon Glass * 76494d708SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 86494d708SSimon Glass */ 96494d708SSimon Glass 106494d708SSimon Glass #include <common.h> 116494d708SSimon Glass #include <errno.h> 126494d708SSimon Glass #include <malloc.h> 136494d708SSimon Glass #include <dm/device.h> 146494d708SSimon Glass #include <dm/device-internal.h> 156494d708SSimon Glass #include <dm/lists.h> 166494d708SSimon Glass #include <dm/uclass.h> 176494d708SSimon Glass #include <dm/uclass-internal.h> 186494d708SSimon Glass #include <dm/util.h> 196494d708SSimon Glass 206494d708SSimon Glass DECLARE_GLOBAL_DATA_PTR; 216494d708SSimon Glass 226494d708SSimon Glass struct uclass *uclass_find(enum uclass_id key) 236494d708SSimon Glass { 246494d708SSimon Glass struct uclass *uc; 256494d708SSimon Glass 26c910e2e2SSimon Glass if (!gd->dm_root) 27c910e2e2SSimon Glass return NULL; 286494d708SSimon Glass /* 296494d708SSimon Glass * TODO(sjg@chromium.org): Optimise this, perhaps moving the found 306494d708SSimon Glass * node to the start of the list, or creating a linear array mapping 316494d708SSimon Glass * id to node. 326494d708SSimon Glass */ 336494d708SSimon Glass list_for_each_entry(uc, &gd->uclass_root, sibling_node) { 346494d708SSimon Glass if (uc->uc_drv->id == key) 356494d708SSimon Glass return uc; 366494d708SSimon Glass } 376494d708SSimon Glass 386494d708SSimon Glass return NULL; 396494d708SSimon Glass } 406494d708SSimon Glass 416494d708SSimon Glass /** 426494d708SSimon Glass * uclass_add() - Create new uclass in list 436494d708SSimon Glass * @id: Id number to create 446494d708SSimon Glass * @ucp: Returns pointer to uclass, or NULL on error 456494d708SSimon Glass * @return 0 on success, -ve on error 466494d708SSimon Glass * 476494d708SSimon Glass * The new uclass is added to the list. There must be only one uclass for 486494d708SSimon Glass * each id. 496494d708SSimon Glass */ 506494d708SSimon Glass static int uclass_add(enum uclass_id id, struct uclass **ucp) 516494d708SSimon Glass { 526494d708SSimon Glass struct uclass_driver *uc_drv; 536494d708SSimon Glass struct uclass *uc; 546494d708SSimon Glass int ret; 556494d708SSimon Glass 566494d708SSimon Glass *ucp = NULL; 576494d708SSimon Glass uc_drv = lists_uclass_lookup(id); 586494d708SSimon Glass if (!uc_drv) { 59643e6902SMasahiro Yamada debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n", 606494d708SSimon Glass id); 613346c876SSimon Glass /* 623346c876SSimon Glass * Use a strange error to make this case easier to find. When 633346c876SSimon Glass * a uclass is not available it can prevent driver model from 643346c876SSimon Glass * starting up and this failure is otherwise hard to debug. 653346c876SSimon Glass */ 663346c876SSimon Glass return -EPFNOSUPPORT; 676494d708SSimon Glass } 686494d708SSimon Glass uc = calloc(1, sizeof(*uc)); 696494d708SSimon Glass if (!uc) 706494d708SSimon Glass return -ENOMEM; 716494d708SSimon Glass if (uc_drv->priv_auto_alloc_size) { 726494d708SSimon Glass uc->priv = calloc(1, uc_drv->priv_auto_alloc_size); 736494d708SSimon Glass if (!uc->priv) { 746494d708SSimon Glass ret = -ENOMEM; 756494d708SSimon Glass goto fail_mem; 766494d708SSimon Glass } 776494d708SSimon Glass } 786494d708SSimon Glass uc->uc_drv = uc_drv; 796494d708SSimon Glass INIT_LIST_HEAD(&uc->sibling_node); 806494d708SSimon Glass INIT_LIST_HEAD(&uc->dev_head); 8189876a55SSimon Glass list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST); 826494d708SSimon Glass 836494d708SSimon Glass if (uc_drv->init) { 846494d708SSimon Glass ret = uc_drv->init(uc); 856494d708SSimon Glass if (ret) 866494d708SSimon Glass goto fail; 876494d708SSimon Glass } 886494d708SSimon Glass 896494d708SSimon Glass *ucp = uc; 906494d708SSimon Glass 916494d708SSimon Glass return 0; 926494d708SSimon Glass fail: 936494d708SSimon Glass if (uc_drv->priv_auto_alloc_size) { 946494d708SSimon Glass free(uc->priv); 956494d708SSimon Glass uc->priv = NULL; 966494d708SSimon Glass } 976494d708SSimon Glass list_del(&uc->sibling_node); 986494d708SSimon Glass fail_mem: 996494d708SSimon Glass free(uc); 1006494d708SSimon Glass 1016494d708SSimon Glass return ret; 1026494d708SSimon Glass } 1036494d708SSimon Glass 1046494d708SSimon Glass int uclass_destroy(struct uclass *uc) 1056494d708SSimon Glass { 1066494d708SSimon Glass struct uclass_driver *uc_drv; 10707d260e0SSimon Glass struct udevice *dev; 1086494d708SSimon Glass int ret; 1096494d708SSimon Glass 11007d260e0SSimon Glass /* 11107d260e0SSimon Glass * We cannot use list_for_each_entry_safe() here. If a device in this 11207d260e0SSimon Glass * uclass has a child device also in this uclass, it will be also be 11307d260e0SSimon Glass * unbound (by the recursion in the call to device_unbind() below). 11407d260e0SSimon Glass * We can loop until the list is empty. 11507d260e0SSimon Glass */ 11607d260e0SSimon Glass while (!list_empty(&uc->dev_head)) { 11707d260e0SSimon Glass dev = list_first_entry(&uc->dev_head, struct udevice, 11807d260e0SSimon Glass uclass_node); 1196494d708SSimon Glass ret = device_remove(dev); 1206494d708SSimon Glass if (ret) 1216494d708SSimon Glass return ret; 1226494d708SSimon Glass ret = device_unbind(dev); 1236494d708SSimon Glass if (ret) 1246494d708SSimon Glass return ret; 1256494d708SSimon Glass } 1266494d708SSimon Glass 1276494d708SSimon Glass uc_drv = uc->uc_drv; 1286494d708SSimon Glass if (uc_drv->destroy) 1296494d708SSimon Glass uc_drv->destroy(uc); 1306494d708SSimon Glass list_del(&uc->sibling_node); 1316494d708SSimon Glass if (uc_drv->priv_auto_alloc_size) 1326494d708SSimon Glass free(uc->priv); 1336494d708SSimon Glass free(uc); 1346494d708SSimon Glass 1356494d708SSimon Glass return 0; 1366494d708SSimon Glass } 1376494d708SSimon Glass 1386494d708SSimon Glass int uclass_get(enum uclass_id id, struct uclass **ucp) 1396494d708SSimon Glass { 1406494d708SSimon Glass struct uclass *uc; 1416494d708SSimon Glass 1426494d708SSimon Glass *ucp = NULL; 1436494d708SSimon Glass uc = uclass_find(id); 1446494d708SSimon Glass if (!uc) 1456494d708SSimon Glass return uclass_add(id, ucp); 1466494d708SSimon Glass *ucp = uc; 1476494d708SSimon Glass 1486494d708SSimon Glass return 0; 1496494d708SSimon Glass } 1506494d708SSimon Glass 15154c5d08aSHeiko Schocher int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) 1526494d708SSimon Glass { 1536494d708SSimon Glass struct uclass *uc; 15454c5d08aSHeiko Schocher struct udevice *dev; 1556494d708SSimon Glass int ret; 1566494d708SSimon Glass 1576494d708SSimon Glass *devp = NULL; 1586494d708SSimon Glass ret = uclass_get(id, &uc); 1596494d708SSimon Glass if (ret) 1606494d708SSimon Glass return ret; 1612fda14aeSSimon Glass if (list_empty(&uc->dev_head)) 1622fda14aeSSimon Glass return -ENODEV; 1636494d708SSimon Glass 1646494d708SSimon Glass list_for_each_entry(dev, &uc->dev_head, uclass_node) { 1656494d708SSimon Glass if (!index--) { 1666494d708SSimon Glass *devp = dev; 1676494d708SSimon Glass return 0; 1686494d708SSimon Glass } 1696494d708SSimon Glass } 1706494d708SSimon Glass 1716494d708SSimon Glass return -ENODEV; 1726494d708SSimon Glass } 1736494d708SSimon Glass 174c1d6f919SPrzemyslaw Marczak int uclass_find_first_device(enum uclass_id id, struct udevice **devp) 175c1d6f919SPrzemyslaw Marczak { 176c1d6f919SPrzemyslaw Marczak struct uclass *uc; 177c1d6f919SPrzemyslaw Marczak int ret; 178c1d6f919SPrzemyslaw Marczak 179c1d6f919SPrzemyslaw Marczak *devp = NULL; 180c1d6f919SPrzemyslaw Marczak ret = uclass_get(id, &uc); 181c1d6f919SPrzemyslaw Marczak if (ret) 182c1d6f919SPrzemyslaw Marczak return ret; 183c1d6f919SPrzemyslaw Marczak if (list_empty(&uc->dev_head)) 184c1d6f919SPrzemyslaw Marczak return 0; 185c1d6f919SPrzemyslaw Marczak 186c1d6f919SPrzemyslaw Marczak *devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node); 187c1d6f919SPrzemyslaw Marczak 188c1d6f919SPrzemyslaw Marczak return 0; 189c1d6f919SPrzemyslaw Marczak } 190c1d6f919SPrzemyslaw Marczak 191c1d6f919SPrzemyslaw Marczak int uclass_find_next_device(struct udevice **devp) 192c1d6f919SPrzemyslaw Marczak { 193c1d6f919SPrzemyslaw Marczak struct udevice *dev = *devp; 194c1d6f919SPrzemyslaw Marczak 195c1d6f919SPrzemyslaw Marczak *devp = NULL; 196c1d6f919SPrzemyslaw Marczak if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head)) 197c1d6f919SPrzemyslaw Marczak return 0; 198c1d6f919SPrzemyslaw Marczak 199c1d6f919SPrzemyslaw Marczak *devp = list_entry(dev->uclass_node.next, struct udevice, uclass_node); 200c1d6f919SPrzemyslaw Marczak 201c1d6f919SPrzemyslaw Marczak return 0; 202c1d6f919SPrzemyslaw Marczak } 203c1d6f919SPrzemyslaw Marczak 204e0735a4cSPrzemyslaw Marczak int uclass_find_device_by_name(enum uclass_id id, const char *name, 205e0735a4cSPrzemyslaw Marczak struct udevice **devp) 206e0735a4cSPrzemyslaw Marczak { 207e0735a4cSPrzemyslaw Marczak struct uclass *uc; 208e0735a4cSPrzemyslaw Marczak struct udevice *dev; 209e0735a4cSPrzemyslaw Marczak int ret; 210e0735a4cSPrzemyslaw Marczak 211e0735a4cSPrzemyslaw Marczak *devp = NULL; 212e0735a4cSPrzemyslaw Marczak if (!name) 213e0735a4cSPrzemyslaw Marczak return -EINVAL; 214e0735a4cSPrzemyslaw Marczak ret = uclass_get(id, &uc); 215e0735a4cSPrzemyslaw Marczak if (ret) 216e0735a4cSPrzemyslaw Marczak return ret; 217e0735a4cSPrzemyslaw Marczak 218e0735a4cSPrzemyslaw Marczak list_for_each_entry(dev, &uc->dev_head, uclass_node) { 219e0735a4cSPrzemyslaw Marczak if (!strncmp(dev->name, name, strlen(name))) { 220e0735a4cSPrzemyslaw Marczak *devp = dev; 221e0735a4cSPrzemyslaw Marczak return 0; 222e0735a4cSPrzemyslaw Marczak } 223e0735a4cSPrzemyslaw Marczak } 224e0735a4cSPrzemyslaw Marczak 225e0735a4cSPrzemyslaw Marczak return -ENODEV; 226e0735a4cSPrzemyslaw Marczak } 227e0735a4cSPrzemyslaw Marczak 2285a66a8ffSSimon Glass int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, 2295a66a8ffSSimon Glass bool find_req_seq, struct udevice **devp) 2305a66a8ffSSimon Glass { 2315a66a8ffSSimon Glass struct uclass *uc; 2325a66a8ffSSimon Glass struct udevice *dev; 2335a66a8ffSSimon Glass int ret; 2345a66a8ffSSimon Glass 2355a66a8ffSSimon Glass *devp = NULL; 2365a66a8ffSSimon Glass debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq); 2375a66a8ffSSimon Glass if (seq_or_req_seq == -1) 2385a66a8ffSSimon Glass return -ENODEV; 2395a66a8ffSSimon Glass ret = uclass_get(id, &uc); 2405a66a8ffSSimon Glass if (ret) 2415a66a8ffSSimon Glass return ret; 2425a66a8ffSSimon Glass 2435a66a8ffSSimon Glass list_for_each_entry(dev, &uc->dev_head, uclass_node) { 2445a66a8ffSSimon Glass debug(" - %d %d\n", dev->req_seq, dev->seq); 2455a66a8ffSSimon Glass if ((find_req_seq ? dev->req_seq : dev->seq) == 2465a66a8ffSSimon Glass seq_or_req_seq) { 2475a66a8ffSSimon Glass *devp = dev; 2485a66a8ffSSimon Glass debug(" - found\n"); 2495a66a8ffSSimon Glass return 0; 2505a66a8ffSSimon Glass } 2515a66a8ffSSimon Glass } 2525a66a8ffSSimon Glass debug(" - not found\n"); 2535a66a8ffSSimon Glass 2545a66a8ffSSimon Glass return -ENODEV; 2555a66a8ffSSimon Glass } 2565a66a8ffSSimon Glass 2571b30d61dSSimon Glass int uclass_find_device_by_of_offset(enum uclass_id id, int node, 258f4cdead2SSimon Glass struct udevice **devp) 259f4cdead2SSimon Glass { 260f4cdead2SSimon Glass struct uclass *uc; 261f4cdead2SSimon Glass struct udevice *dev; 262f4cdead2SSimon Glass int ret; 263f4cdead2SSimon Glass 264f4cdead2SSimon Glass *devp = NULL; 265f4cdead2SSimon Glass if (node < 0) 266f4cdead2SSimon Glass return -ENODEV; 267f4cdead2SSimon Glass ret = uclass_get(id, &uc); 268f4cdead2SSimon Glass if (ret) 269f4cdead2SSimon Glass return ret; 270f4cdead2SSimon Glass 271f4cdead2SSimon Glass list_for_each_entry(dev, &uc->dev_head, uclass_node) { 272f4cdead2SSimon Glass if (dev->of_offset == node) { 273f4cdead2SSimon Glass *devp = dev; 274f4cdead2SSimon Glass return 0; 275f4cdead2SSimon Glass } 276f4cdead2SSimon Glass } 277f4cdead2SSimon Glass 278f4cdead2SSimon Glass return -ENODEV; 279f4cdead2SSimon Glass } 280f4cdead2SSimon Glass 281c275dfefSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) 282d82ba4c0SSimon Glass static int uclass_find_device_by_phandle(enum uclass_id id, 283d82ba4c0SSimon Glass struct udevice *parent, 284d82ba4c0SSimon Glass const char *name, 285d82ba4c0SSimon Glass struct udevice **devp) 286d82ba4c0SSimon Glass { 287d82ba4c0SSimon Glass struct udevice *dev; 288d82ba4c0SSimon Glass struct uclass *uc; 289d82ba4c0SSimon Glass int find_phandle; 290d82ba4c0SSimon Glass int ret; 291d82ba4c0SSimon Glass 292d82ba4c0SSimon Glass *devp = NULL; 293d82ba4c0SSimon Glass find_phandle = fdtdec_get_int(gd->fdt_blob, parent->of_offset, name, 294d82ba4c0SSimon Glass -1); 295d82ba4c0SSimon Glass if (find_phandle <= 0) 296d82ba4c0SSimon Glass return -ENOENT; 297d82ba4c0SSimon Glass ret = uclass_get(id, &uc); 298d82ba4c0SSimon Glass if (ret) 299d82ba4c0SSimon Glass return ret; 300d82ba4c0SSimon Glass 301d82ba4c0SSimon Glass list_for_each_entry(dev, &uc->dev_head, uclass_node) { 302d82ba4c0SSimon Glass uint phandle = fdt_get_phandle(gd->fdt_blob, dev->of_offset); 303d82ba4c0SSimon Glass 304d82ba4c0SSimon Glass if (phandle == find_phandle) { 305d82ba4c0SSimon Glass *devp = dev; 306d82ba4c0SSimon Glass return 0; 307d82ba4c0SSimon Glass } 308d82ba4c0SSimon Glass } 309d82ba4c0SSimon Glass 310d82ba4c0SSimon Glass return -ENODEV; 311d82ba4c0SSimon Glass } 312c275dfefSSimon Glass #endif 313d82ba4c0SSimon Glass 314794d5219SPrzemyslaw Marczak int uclass_get_device_tail(struct udevice *dev, int ret, 3159ca296a1SSimon Glass struct udevice **devp) 3166494d708SSimon Glass { 3176494d708SSimon Glass if (ret) 3186494d708SSimon Glass return ret; 3196494d708SSimon Glass 320f66529f9SSimon Glass assert(dev); 3216494d708SSimon Glass ret = device_probe(dev); 3226494d708SSimon Glass if (ret) 3236494d708SSimon Glass return ret; 3246494d708SSimon Glass 3256494d708SSimon Glass *devp = dev; 3266494d708SSimon Glass 3276494d708SSimon Glass return 0; 3286494d708SSimon Glass } 3296494d708SSimon Glass 3309ca296a1SSimon Glass int uclass_get_device(enum uclass_id id, int index, struct udevice **devp) 3319ca296a1SSimon Glass { 3329ca296a1SSimon Glass struct udevice *dev; 3339ca296a1SSimon Glass int ret; 3349ca296a1SSimon Glass 3359ca296a1SSimon Glass *devp = NULL; 3369ca296a1SSimon Glass ret = uclass_find_device(id, index, &dev); 3379ca296a1SSimon Glass return uclass_get_device_tail(dev, ret, devp); 3389ca296a1SSimon Glass } 3399ca296a1SSimon Glass 340b7af1a2dSPrzemyslaw Marczak int uclass_get_device_by_name(enum uclass_id id, const char *name, 341b7af1a2dSPrzemyslaw Marczak struct udevice **devp) 342b7af1a2dSPrzemyslaw Marczak { 343b7af1a2dSPrzemyslaw Marczak struct udevice *dev; 344b7af1a2dSPrzemyslaw Marczak int ret; 345b7af1a2dSPrzemyslaw Marczak 346b7af1a2dSPrzemyslaw Marczak *devp = NULL; 347b7af1a2dSPrzemyslaw Marczak ret = uclass_find_device_by_name(id, name, &dev); 348b7af1a2dSPrzemyslaw Marczak return uclass_get_device_tail(dev, ret, devp); 349b7af1a2dSPrzemyslaw Marczak } 350b7af1a2dSPrzemyslaw Marczak 3515a66a8ffSSimon Glass int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp) 3525a66a8ffSSimon Glass { 3535a66a8ffSSimon Glass struct udevice *dev; 3545a66a8ffSSimon Glass int ret; 3555a66a8ffSSimon Glass 3565a66a8ffSSimon Glass *devp = NULL; 3575a66a8ffSSimon Glass ret = uclass_find_device_by_seq(id, seq, false, &dev); 3585a66a8ffSSimon Glass if (ret == -ENODEV) { 3595a66a8ffSSimon Glass /* 3605a66a8ffSSimon Glass * We didn't find it in probed devices. See if there is one 3615a66a8ffSSimon Glass * that will request this seq if probed. 3625a66a8ffSSimon Glass */ 3635a66a8ffSSimon Glass ret = uclass_find_device_by_seq(id, seq, true, &dev); 3645a66a8ffSSimon Glass } 3655a66a8ffSSimon Glass return uclass_get_device_tail(dev, ret, devp); 3665a66a8ffSSimon Glass } 3675a66a8ffSSimon Glass 368f4cdead2SSimon Glass int uclass_get_device_by_of_offset(enum uclass_id id, int node, 369f4cdead2SSimon Glass struct udevice **devp) 370f4cdead2SSimon Glass { 371f4cdead2SSimon Glass struct udevice *dev; 372f4cdead2SSimon Glass int ret; 373f4cdead2SSimon Glass 374f4cdead2SSimon Glass *devp = NULL; 375f4cdead2SSimon Glass ret = uclass_find_device_by_of_offset(id, node, &dev); 376f4cdead2SSimon Glass return uclass_get_device_tail(dev, ret, devp); 377f4cdead2SSimon Glass } 378f4cdead2SSimon Glass 379c275dfefSSimon Glass #if CONFIG_IS_ENABLED(OF_CONTROL) 380d82ba4c0SSimon Glass int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, 381d82ba4c0SSimon Glass const char *name, struct udevice **devp) 382d82ba4c0SSimon Glass { 383d82ba4c0SSimon Glass struct udevice *dev; 384d82ba4c0SSimon Glass int ret; 385d82ba4c0SSimon Glass 386d82ba4c0SSimon Glass *devp = NULL; 387d82ba4c0SSimon Glass ret = uclass_find_device_by_phandle(id, parent, name, &dev); 388d82ba4c0SSimon Glass return uclass_get_device_tail(dev, ret, devp); 389d82ba4c0SSimon Glass } 390c275dfefSSimon Glass #endif 391d82ba4c0SSimon Glass 39254c5d08aSHeiko Schocher int uclass_first_device(enum uclass_id id, struct udevice **devp) 3936494d708SSimon Glass { 39454c5d08aSHeiko Schocher struct udevice *dev; 3956494d708SSimon Glass int ret; 3966494d708SSimon Glass 3976494d708SSimon Glass *devp = NULL; 398c1d6f919SPrzemyslaw Marczak ret = uclass_find_first_device(id, &dev); 399f66529f9SSimon Glass if (!dev) 400f66529f9SSimon Glass return 0; 401c1d6f919SPrzemyslaw Marczak return uclass_get_device_tail(dev, ret, devp); 4026494d708SSimon Glass } 4036494d708SSimon Glass 404*b0675050SSimon Glass int uclass_first_device_err(enum uclass_id id, struct udevice **devp) 405*b0675050SSimon Glass { 406*b0675050SSimon Glass int ret; 407*b0675050SSimon Glass 408*b0675050SSimon Glass ret = uclass_first_device(id, devp); 409*b0675050SSimon Glass if (ret) 410*b0675050SSimon Glass return ret; 411*b0675050SSimon Glass else if (!*devp) 412*b0675050SSimon Glass return -ENODEV; 413*b0675050SSimon Glass 414*b0675050SSimon Glass return 0; 415*b0675050SSimon Glass } 416*b0675050SSimon Glass 41754c5d08aSHeiko Schocher int uclass_next_device(struct udevice **devp) 4186494d708SSimon Glass { 41954c5d08aSHeiko Schocher struct udevice *dev = *devp; 4206494d708SSimon Glass int ret; 4216494d708SSimon Glass 4226494d708SSimon Glass *devp = NULL; 423c1d6f919SPrzemyslaw Marczak ret = uclass_find_next_device(&dev); 424f66529f9SSimon Glass if (!dev) 425f66529f9SSimon Glass return 0; 426c1d6f919SPrzemyslaw Marczak return uclass_get_device_tail(dev, ret, devp); 4276494d708SSimon Glass } 4286494d708SSimon Glass 42954c5d08aSHeiko Schocher int uclass_bind_device(struct udevice *dev) 4306494d708SSimon Glass { 4316494d708SSimon Glass struct uclass *uc; 4326494d708SSimon Glass int ret; 4336494d708SSimon Glass 4346494d708SSimon Glass uc = dev->uclass; 4356494d708SSimon Glass list_add_tail(&dev->uclass_node, &uc->dev_head); 4366494d708SSimon Glass 437081f2fcbSSimon Glass if (dev->parent) { 438081f2fcbSSimon Glass struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv; 439081f2fcbSSimon Glass 440081f2fcbSSimon Glass if (uc_drv->child_post_bind) { 441081f2fcbSSimon Glass ret = uc_drv->child_post_bind(dev); 442081f2fcbSSimon Glass if (ret) 443081f2fcbSSimon Glass goto err; 444081f2fcbSSimon Glass } 445081f2fcbSSimon Glass } 4466494d708SSimon Glass 4476494d708SSimon Glass return 0; 448081f2fcbSSimon Glass err: 449081f2fcbSSimon Glass /* There is no need to undo the parent's post_bind call */ 450081f2fcbSSimon Glass list_del(&dev->uclass_node); 451081f2fcbSSimon Glass 452081f2fcbSSimon Glass return ret; 4536494d708SSimon Glass } 4546494d708SSimon Glass 4550a5804b5SMasahiro Yamada #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) 45654c5d08aSHeiko Schocher int uclass_unbind_device(struct udevice *dev) 4576494d708SSimon Glass { 4586494d708SSimon Glass struct uclass *uc; 4596494d708SSimon Glass int ret; 4606494d708SSimon Glass 4616494d708SSimon Glass uc = dev->uclass; 4626494d708SSimon Glass if (uc->uc_drv->pre_unbind) { 4636494d708SSimon Glass ret = uc->uc_drv->pre_unbind(dev); 4646494d708SSimon Glass if (ret) 4656494d708SSimon Glass return ret; 4666494d708SSimon Glass } 4676494d708SSimon Glass 4686494d708SSimon Glass list_del(&dev->uclass_node); 4696494d708SSimon Glass return 0; 4706494d708SSimon Glass } 4717f9875e7SSimon Glass #endif 4726494d708SSimon Glass 4735a66a8ffSSimon Glass int uclass_resolve_seq(struct udevice *dev) 4745a66a8ffSSimon Glass { 4755a66a8ffSSimon Glass struct udevice *dup; 4765a66a8ffSSimon Glass int seq; 4775a66a8ffSSimon Glass int ret; 4785a66a8ffSSimon Glass 4795a66a8ffSSimon Glass assert(dev->seq == -1); 4805a66a8ffSSimon Glass ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq, 4815a66a8ffSSimon Glass false, &dup); 4825a66a8ffSSimon Glass if (!ret) { 4835a66a8ffSSimon Glass dm_warn("Device '%s': seq %d is in use by '%s'\n", 4845a66a8ffSSimon Glass dev->name, dev->req_seq, dup->name); 4855a66a8ffSSimon Glass } else if (ret == -ENODEV) { 4865a66a8ffSSimon Glass /* Our requested sequence number is available */ 4875a66a8ffSSimon Glass if (dev->req_seq != -1) 4885a66a8ffSSimon Glass return dev->req_seq; 4895a66a8ffSSimon Glass } else { 4905a66a8ffSSimon Glass return ret; 4915a66a8ffSSimon Glass } 4925a66a8ffSSimon Glass 4935a66a8ffSSimon Glass for (seq = 0; seq < DM_MAX_SEQ; seq++) { 4945a66a8ffSSimon Glass ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq, 4955a66a8ffSSimon Glass false, &dup); 4965a66a8ffSSimon Glass if (ret == -ENODEV) 4975a66a8ffSSimon Glass break; 4985a66a8ffSSimon Glass if (ret) 4995a66a8ffSSimon Glass return ret; 5005a66a8ffSSimon Glass } 5015a66a8ffSSimon Glass return seq; 5025a66a8ffSSimon Glass } 5035a66a8ffSSimon Glass 50402c07b37SSimon Glass int uclass_pre_probe_device(struct udevice *dev) 50583c7e434SSimon Glass { 50683c7e434SSimon Glass struct uclass_driver *uc_drv; 50702c07b37SSimon Glass int ret; 50802c07b37SSimon Glass 50902c07b37SSimon Glass uc_drv = dev->uclass->uc_drv; 51002c07b37SSimon Glass if (uc_drv->pre_probe) { 51102c07b37SSimon Glass ret = uc_drv->pre_probe(dev); 51202c07b37SSimon Glass if (ret) 51302c07b37SSimon Glass return ret; 51402c07b37SSimon Glass } 51583c7e434SSimon Glass 51683c7e434SSimon Glass if (!dev->parent) 51783c7e434SSimon Glass return 0; 51883c7e434SSimon Glass uc_drv = dev->parent->uclass->uc_drv; 51983c7e434SSimon Glass if (uc_drv->child_pre_probe) 52083c7e434SSimon Glass return uc_drv->child_pre_probe(dev); 52183c7e434SSimon Glass 52283c7e434SSimon Glass return 0; 52383c7e434SSimon Glass } 52483c7e434SSimon Glass 52554c5d08aSHeiko Schocher int uclass_post_probe_device(struct udevice *dev) 5266494d708SSimon Glass { 5276494d708SSimon Glass struct uclass_driver *uc_drv = dev->uclass->uc_drv; 5286494d708SSimon Glass 5296494d708SSimon Glass if (uc_drv->post_probe) 5306494d708SSimon Glass return uc_drv->post_probe(dev); 5316494d708SSimon Glass 5326494d708SSimon Glass return 0; 5336494d708SSimon Glass } 5346494d708SSimon Glass 5350a5804b5SMasahiro Yamada #if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) 53654c5d08aSHeiko Schocher int uclass_pre_remove_device(struct udevice *dev) 5376494d708SSimon Glass { 5386494d708SSimon Glass struct uclass *uc; 5396494d708SSimon Glass int ret; 5406494d708SSimon Glass 5416494d708SSimon Glass uc = dev->uclass; 5426494d708SSimon Glass if (uc->uc_drv->pre_remove) { 5436494d708SSimon Glass ret = uc->uc_drv->pre_remove(dev); 5446494d708SSimon Glass if (ret) 5456494d708SSimon Glass return ret; 5466494d708SSimon Glass } 5476494d708SSimon Glass 5486494d708SSimon Glass return 0; 5496494d708SSimon Glass } 5507f9875e7SSimon Glass #endif 551