16494d708SSimon Glass /* 26494d708SSimon Glass * Copyright (c) 2013 Google, Inc 36494d708SSimon Glass * 46494d708SSimon Glass * (C) Copyright 2012 56494d708SSimon Glass * Marek Vasut <marex@denx.de> 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 <dm/device.h> 136494d708SSimon Glass #include <dm/device-internal.h> 146494d708SSimon Glass #include <dm/platdata.h> 156494d708SSimon Glass #include <dm/uclass.h> 166494d708SSimon Glass #include <dm/util.h> 17*6a6d8fbeSSimon Glass #include <fdtdec.h> 186494d708SSimon Glass #include <linux/compiler.h> 196494d708SSimon Glass 206494d708SSimon Glass struct driver *lists_driver_lookup_name(const char *name) 216494d708SSimon Glass { 226494d708SSimon Glass struct driver *drv = 236494d708SSimon Glass ll_entry_start(struct driver, driver); 246494d708SSimon Glass const int n_ents = ll_entry_count(struct driver, driver); 256494d708SSimon Glass struct driver *entry; 266494d708SSimon Glass int len; 276494d708SSimon Glass 286494d708SSimon Glass if (!drv || !n_ents) 296494d708SSimon Glass return NULL; 306494d708SSimon Glass 316494d708SSimon Glass len = strlen(name); 326494d708SSimon Glass 336494d708SSimon Glass for (entry = drv; entry != drv + n_ents; entry++) { 346494d708SSimon Glass if (strncmp(name, entry->name, len)) 356494d708SSimon Glass continue; 366494d708SSimon Glass 376494d708SSimon Glass /* Full match */ 386494d708SSimon Glass if (len == strlen(entry->name)) 396494d708SSimon Glass return entry; 406494d708SSimon Glass } 416494d708SSimon Glass 426494d708SSimon Glass /* Not found */ 436494d708SSimon Glass return NULL; 446494d708SSimon Glass } 456494d708SSimon Glass 466494d708SSimon Glass struct uclass_driver *lists_uclass_lookup(enum uclass_id id) 476494d708SSimon Glass { 486494d708SSimon Glass struct uclass_driver *uclass = 496494d708SSimon Glass ll_entry_start(struct uclass_driver, uclass); 506494d708SSimon Glass const int n_ents = ll_entry_count(struct uclass_driver, uclass); 516494d708SSimon Glass struct uclass_driver *entry; 526494d708SSimon Glass 536494d708SSimon Glass if ((id == UCLASS_INVALID) || !uclass) 546494d708SSimon Glass return NULL; 556494d708SSimon Glass 566494d708SSimon Glass for (entry = uclass; entry != uclass + n_ents; entry++) { 576494d708SSimon Glass if (entry->id == id) 586494d708SSimon Glass return entry; 596494d708SSimon Glass } 606494d708SSimon Glass 616494d708SSimon Glass return NULL; 626494d708SSimon Glass } 636494d708SSimon Glass 6454c5d08aSHeiko Schocher int lists_bind_drivers(struct udevice *parent) 656494d708SSimon Glass { 666494d708SSimon Glass struct driver_info *info = 676494d708SSimon Glass ll_entry_start(struct driver_info, driver_info); 686494d708SSimon Glass const int n_ents = ll_entry_count(struct driver_info, driver_info); 696494d708SSimon Glass struct driver_info *entry; 7054c5d08aSHeiko Schocher struct udevice *dev; 716494d708SSimon Glass int result = 0; 726494d708SSimon Glass int ret; 736494d708SSimon Glass 746494d708SSimon Glass for (entry = info; entry != info + n_ents; entry++) { 756494d708SSimon Glass ret = device_bind_by_name(parent, entry, &dev); 766494d708SSimon Glass if (ret) { 776494d708SSimon Glass dm_warn("No match for driver '%s'\n", entry->name); 786494d708SSimon Glass if (!result || ret != -ENOENT) 796494d708SSimon Glass result = ret; 806494d708SSimon Glass } 816494d708SSimon Glass } 826494d708SSimon Glass 836494d708SSimon Glass return result; 846494d708SSimon Glass } 856494d708SSimon Glass 866494d708SSimon Glass #ifdef CONFIG_OF_CONTROL 876494d708SSimon Glass /** 886494d708SSimon Glass * driver_check_compatible() - Check if a driver is compatible with this node 896494d708SSimon Glass * 906494d708SSimon Glass * @param blob: Device tree pointer 916494d708SSimon Glass * @param offset: Offset of node in device tree 926494d708SSimon Glass * @param of_matchL List of compatible strings to match 936494d708SSimon Glass * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node 946494d708SSimon Glass * does not have a compatible string, other error <0 if there is a device 956494d708SSimon Glass * tree error 966494d708SSimon Glass */ 976494d708SSimon Glass static int driver_check_compatible(const void *blob, int offset, 98ae7f4513SSimon Glass const struct udevice_id *of_match) 996494d708SSimon Glass { 1006494d708SSimon Glass int ret; 1016494d708SSimon Glass 1026494d708SSimon Glass if (!of_match) 1036494d708SSimon Glass return -ENOENT; 1046494d708SSimon Glass 1056494d708SSimon Glass while (of_match->compatible) { 1066494d708SSimon Glass ret = fdt_node_check_compatible(blob, offset, 1076494d708SSimon Glass of_match->compatible); 1086494d708SSimon Glass if (!ret) 1096494d708SSimon Glass return 0; 1106494d708SSimon Glass else if (ret == -FDT_ERR_NOTFOUND) 1116494d708SSimon Glass return -ENODEV; 1126494d708SSimon Glass else if (ret < 0) 1136494d708SSimon Glass return -EINVAL; 1146494d708SSimon Glass of_match++; 1156494d708SSimon Glass } 1166494d708SSimon Glass 1176494d708SSimon Glass return -ENOENT; 1186494d708SSimon Glass } 1196494d708SSimon Glass 12054c5d08aSHeiko Schocher int lists_bind_fdt(struct udevice *parent, const void *blob, int offset) 1216494d708SSimon Glass { 1226494d708SSimon Glass struct driver *driver = ll_entry_start(struct driver, driver); 1236494d708SSimon Glass const int n_ents = ll_entry_count(struct driver, driver); 1246494d708SSimon Glass struct driver *entry; 12554c5d08aSHeiko Schocher struct udevice *dev; 1266494d708SSimon Glass const char *name; 1276494d708SSimon Glass int result = 0; 1286494d708SSimon Glass int ret; 1296494d708SSimon Glass 1306494d708SSimon Glass dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL)); 1316494d708SSimon Glass for (entry = driver; entry != driver + n_ents; entry++) { 1326494d708SSimon Glass ret = driver_check_compatible(blob, offset, entry->of_match); 1336494d708SSimon Glass if (ret == -ENOENT) { 1346494d708SSimon Glass continue; 1356494d708SSimon Glass } else if (ret == -ENODEV) { 1366494d708SSimon Glass break; 1376494d708SSimon Glass } else if (ret) { 1386494d708SSimon Glass dm_warn("Device tree error at offset %d\n", offset); 1396494d708SSimon Glass if (!result || ret != -ENOENT) 1406494d708SSimon Glass result = ret; 1416494d708SSimon Glass break; 1426494d708SSimon Glass } 1436494d708SSimon Glass 1446494d708SSimon Glass name = fdt_get_name(blob, offset, NULL); 1456494d708SSimon Glass dm_dbg(" - found match at '%s'\n", entry->name); 1466494d708SSimon Glass ret = device_bind(parent, entry, name, NULL, offset, &dev); 1476494d708SSimon Glass if (ret) { 1486494d708SSimon Glass dm_warn("No match for driver '%s'\n", entry->name); 1496494d708SSimon Glass if (!result || ret != -ENOENT) 1506494d708SSimon Glass result = ret; 1516494d708SSimon Glass } 1526494d708SSimon Glass } 1536494d708SSimon Glass 1546494d708SSimon Glass return result; 1556494d708SSimon Glass } 1566494d708SSimon Glass #endif 157