diff --git a/drivers/core/device.c b/drivers/core/device.c index fd59fe1e0f..feed43c8c3 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -516,6 +516,33 @@ static int device_get_device_tail(struct udevice *dev, int ret, return 0; } +/** + * device_find_by_ofnode() - Return device associated with given ofnode + * + * The returned device is *not* activated. + * + * @node: The ofnode for which a associated device should be looked up + * @devp: Pointer to structure to hold the found device + * Return: 0 if OK, -ve on error + */ +static int device_find_by_ofnode(ofnode node, struct udevice **devp) +{ + struct uclass *uc; + struct udevice *dev; + int ret; + + list_for_each_entry(uc, &gd->uclass_root, sibling_node) { + ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, + &dev); + if (!ret || dev) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + int device_get_child(struct udevice *parent, int index, struct udevice **devp) { struct udevice *dev; @@ -739,3 +766,54 @@ bool of_machine_is_compatible(const char *compat) return !fdt_node_check_compatible(fdt, 0, compat); } + +int dev_disable_by_path(const char *path) +{ + struct uclass *uc; + ofnode node = ofnode_path(path); + struct udevice *dev; + int ret = 1; + + if (!of_live_active()) + return -ENOSYS; + + list_for_each_entry(uc, &gd->uclass_root, sibling_node) { + ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev); + if (!ret) + break; + } + + if (ret) + return ret; + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return ret; + + ret = device_unbind(dev); + if (ret) + return ret; + + return ofnode_set_enabled(node, false); +} + +int dev_enable_by_path(const char *path) +{ + ofnode node = ofnode_path(path); + ofnode pnode = ofnode_get_parent(node); + struct udevice *parent; + int ret = 1; + + if (!of_live_active()) + return -ENOSYS; + + ret = device_find_by_ofnode(pnode, &parent); + if (ret) + return ret; + + ret = ofnode_set_enabled(node, true); + if (ret) + return ret; + + return lists_bind_fdt(parent, node, NULL); +} diff --git a/include/dm/device.h b/include/dm/device.h index 3120b68fcc..9812d86f08 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -600,6 +600,22 @@ bool device_is_compatible(struct udevice *dev, const char *compat); */ bool of_machine_is_compatible(const char *compat); +/** + * dev_disable_by_path() - Disable a device given its device tree path + * + * @path: The device tree path identifying the device to be disabled + * @return 0 on success, -ve on error + */ +int dev_disable_by_path(const char *path); + +/** + * dev_enable_by_path() - Enable a device given its device tree path + * + * @path: The device tree path identifying the device to be enabled + * @return 0 on success, -ve on error + */ +int dev_enable_by_path(const char *path); + /** * device_is_on_pci_bus - Test if a device is on a PCI bus *