+// SPDX-License-Identifier: GPL-2.0+
/*
* Device manager
*
*
* (C) Copyright 2012
* Pavel Herrmann <morpheus.ibis@gmail.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm/uclass-internal.h>
#include <dm/util.h>
-int device_unbind_children(struct udevice *dev)
+int device_chld_unbind(struct udevice *dev, struct driver *drv)
{
struct udevice *pos, *n;
int ret, saved_ret = 0;
assert(dev);
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
+ if (drv && (pos->driver != drv))
+ continue;
+
ret = device_unbind(pos);
if (ret && !saved_ret)
saved_ret = ret;
return saved_ret;
}
-int device_remove_children(struct udevice *dev)
+int device_chld_remove(struct udevice *dev, struct driver *drv,
+ uint flags)
{
struct udevice *pos, *n;
int ret;
assert(dev);
list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
- ret = device_remove(pos);
+ if (drv && (pos->driver != drv))
+ continue;
+
+ ret = device_remove(pos, flags);
if (ret)
return ret;
}
return ret;
}
- ret = device_unbind_children(dev);
+ ret = device_chld_unbind(dev, NULL);
if (ret)
return ret;
devres_release_all(dev);
+ if (dev->flags & DM_FLAG_NAME_ALLOCED)
+ free((char *)dev->name);
free(dev);
return 0;
devres_release_probe(dev);
}
-int device_remove(struct udevice *dev)
+static bool flags_remove(uint flags, uint drv_flags)
+{
+ if ((flags & DM_REMOVE_NORMAL) ||
+ (flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE))))
+ return true;
+
+ return false;
+}
+
+int device_remove(struct udevice *dev, uint flags)
{
const struct driver *drv;
int ret;
if (ret)
return ret;
- ret = device_remove_children(dev);
+ ret = device_chld_remove(dev, NULL, flags);
if (ret)
goto err;
- if (drv->remove) {
+ /*
+ * Remove the device if called with the "normal" remove flag set,
+ * or if the remove flag matches any of the drivers remove flags
+ */
+ if (drv->remove && flags_remove(flags, drv->flags)) {
ret = drv->remove(dev);
if (ret)
goto err_remove;
}
}
- device_free(dev);
+ if (flags_remove(flags, drv->flags)) {
+ device_free(dev);
- dev->seq = -1;
- dev->flags &= ~DM_FLAG_ACTIVATED;
+ dev->seq = -1;
+ dev->flags &= ~DM_FLAG_ACTIVATED;
+ }
return ret;