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