core: Add dev_{disable,enable}_by_path

We cannot use device structures to disable devices, since getting
them with the API functions would bind and activate the device, which
would fail if the underlying device does not exist.
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Mario Six 2018-06-26 08:46:50 +02:00 committed by Simon Glass
parent 2ea4d0db73
commit e4c98a59db
2 changed files with 94 additions and 0 deletions

View File

@ -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);
}

View File

@ -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
*