1 /* 2 * Copyright (c) 2013 Google, Inc 3 * 4 * (C) Copyright 2012 5 * Marek Vasut <marex@denx.de> 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <common.h> 11 #include <errno.h> 12 #include <dm/device.h> 13 #include <dm/device-internal.h> 14 #include <dm/platdata.h> 15 #include <dm/uclass.h> 16 #include <dm/util.h> 17 #include <fdtdec.h> 18 #include <linux/compiler.h> 19 20 struct driver *lists_driver_lookup_name(const char *name) 21 { 22 struct driver *drv = 23 ll_entry_start(struct driver, driver); 24 const int n_ents = ll_entry_count(struct driver, driver); 25 struct driver *entry; 26 int len; 27 28 if (!drv || !n_ents) 29 return NULL; 30 31 len = strlen(name); 32 33 for (entry = drv; entry != drv + n_ents; entry++) { 34 if (strncmp(name, entry->name, len)) 35 continue; 36 37 /* Full match */ 38 if (len == strlen(entry->name)) 39 return entry; 40 } 41 42 /* Not found */ 43 return NULL; 44 } 45 46 struct uclass_driver *lists_uclass_lookup(enum uclass_id id) 47 { 48 struct uclass_driver *uclass = 49 ll_entry_start(struct uclass_driver, uclass); 50 const int n_ents = ll_entry_count(struct uclass_driver, uclass); 51 struct uclass_driver *entry; 52 53 if ((id == UCLASS_INVALID) || !uclass) 54 return NULL; 55 56 for (entry = uclass; entry != uclass + n_ents; entry++) { 57 if (entry->id == id) 58 return entry; 59 } 60 61 return NULL; 62 } 63 64 int lists_bind_drivers(struct udevice *parent) 65 { 66 struct driver_info *info = 67 ll_entry_start(struct driver_info, driver_info); 68 const int n_ents = ll_entry_count(struct driver_info, driver_info); 69 struct driver_info *entry; 70 struct udevice *dev; 71 int result = 0; 72 int ret; 73 74 for (entry = info; entry != info + n_ents; entry++) { 75 ret = device_bind_by_name(parent, entry, &dev); 76 if (ret) { 77 dm_warn("No match for driver '%s'\n", entry->name); 78 if (!result || ret != -ENOENT) 79 result = ret; 80 } 81 } 82 83 return result; 84 } 85 86 #ifdef CONFIG_OF_CONTROL 87 /** 88 * driver_check_compatible() - Check if a driver is compatible with this node 89 * 90 * @param blob: Device tree pointer 91 * @param offset: Offset of node in device tree 92 * @param of_matchL List of compatible strings to match 93 * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node 94 * does not have a compatible string, other error <0 if there is a device 95 * tree error 96 */ 97 static int driver_check_compatible(const void *blob, int offset, 98 const struct udevice_id *of_match) 99 { 100 int ret; 101 102 if (!of_match) 103 return -ENOENT; 104 105 while (of_match->compatible) { 106 ret = fdt_node_check_compatible(blob, offset, 107 of_match->compatible); 108 if (!ret) 109 return 0; 110 else if (ret == -FDT_ERR_NOTFOUND) 111 return -ENODEV; 112 else if (ret < 0) 113 return -EINVAL; 114 of_match++; 115 } 116 117 return -ENOENT; 118 } 119 120 int lists_bind_fdt(struct udevice *parent, const void *blob, int offset) 121 { 122 struct driver *driver = ll_entry_start(struct driver, driver); 123 const int n_ents = ll_entry_count(struct driver, driver); 124 struct driver *entry; 125 struct udevice *dev; 126 const char *name; 127 int result = 0; 128 int ret; 129 130 dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL)); 131 for (entry = driver; entry != driver + n_ents; entry++) { 132 ret = driver_check_compatible(blob, offset, entry->of_match); 133 if (ret == -ENOENT) { 134 continue; 135 } else if (ret == -ENODEV) { 136 break; 137 } else if (ret) { 138 dm_warn("Device tree error at offset %d\n", offset); 139 if (!result || ret != -ENOENT) 140 result = ret; 141 break; 142 } 143 144 name = fdt_get_name(blob, offset, NULL); 145 dm_dbg(" - found match at '%s'\n", entry->name); 146 ret = device_bind(parent, entry, name, NULL, offset, &dev); 147 if (ret) { 148 dm_warn("No match for driver '%s'\n", entry->name); 149 if (!result || ret != -ENOENT) 150 result = ret; 151 } 152 } 153 154 return result; 155 } 156 #endif 157