+ bool "Enable per-uclass fallback drivers"
+ depends on DM
+ help
+ If a driver requests a resource (like a clock) from a node which
+ isn't bound to a driver, the driver model will look for a fallback
+ driver to "stub" the resource. These stubs usually do nothing and
+ are therefore only suitable in instances where the resource is not
+ required.
+
endmenu
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index e46d5717aa62..91d3a48d77b8 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -378,8 +378,26 @@ int uclass_find_device_by_of_offset(enum uclass_id id, int
node,
return -ENODEV;
}
+static int uclass_bind_fallback(struct uclass *uc, ofnode node, struct udevice
**devp)
+{
+ struct driver *drv;
+
+ log(LOGC_DM, LOGL_ERR, " - binding fallback '%s' driver '%s'\n",
+ uc->uc_drv->name, uc->uc_drv->fallback_drv_name);
+
+ drv = lists_driver_lookup_name(uc->uc_drv->fallback_drv_name);
+ if (!drv) {
+ log(LOGC_DM, LOGL_DEBUG, " - Can't find stub driver '%s' for
uclass '%s'\n",
+ uc->uc_drv->fallback_drv_name, uc->uc_drv->name);
+ return -ENOENT;
+ }
+
+ return device_bind_with_driver_data(gd->dm_root, drv,
+ ofnode_get_name(node), 0, node, devp);
+}
+
int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
struct udevice **devp)
{
struct uclass *uc;
@@ -401,9 +419,13 @@ int uclass_find_device_by_ofnode(enum uclass_id id, ofnode
node,
*devp = dev;
goto done;
}
}
- ret = -ENODEV;
+
+ if (CONFIG_IS_ENABLED(FALLBACK_DRIVERS) &&
uc->uc_drv->fallback_drv_name)
+ ret = uclass_bind_fallback(uc, node, devp);
+ else
+ ret = -ENODEV;
done:
log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n",
ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret);
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 456eef7f2f31..b99e36485bc5 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -67,8 +67,10 @@ struct udevice;
* @child_pre_probe: Called before a child in this uclass is probed
* @child_post_probe: Called after a child in this uclass is probed
* @init: Called to set up the uclass
* @destroy: Called to destroy the uclass
+ * @stub_drv_name: Name of a stub driver to use for devices that are not
+ * supported by any other driver.
* @priv_auto: If non-zero this is the size of the private data
* to be allocated in the uclass's ->priv pointer. If zero, then the uclass
* driver is responsible for allocating any data required.
* @per_device_auto: Each device can hold private data owned
@@ -98,8 +100,9 @@ struct uclass_driver {
int (*child_pre_probe)(struct udevice *dev);
int (*child_post_probe)(struct udevice *dev);
int (*init)(struct uclass *class);
int (*destroy)(struct uclass *class);
+ const char *fallback_drv_name;
int priv_auto;
int per_device_auto;
int per_device_plat_auto;
int per_child_auto;