4 * Copyright (c) 2014 Google, Inc
7 * Pavel Herrmann <morpheus.ibis@gmail.com>
9 * SPDX-License-Identifier: GPL-2.0+
15 #include <dm/device.h>
16 #include <dm/device-internal.h>
17 #include <dm/uclass.h>
18 #include <dm/uclass-internal.h>
21 int device_unbind_children(struct udevice *dev)
23 struct udevice *pos, *n;
24 int ret, saved_ret = 0;
28 list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
29 ret = device_unbind(pos);
30 if (ret && !saved_ret)
37 int device_remove_children(struct udevice *dev)
39 struct udevice *pos, *n;
44 list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
45 ret = device_remove(pos);
53 int device_unbind(struct udevice *dev)
55 const struct driver *drv;
61 if (dev->flags & DM_FLAG_ACTIVATED)
68 ret = drv->unbind(dev);
73 ret = device_unbind_children(dev);
77 if (dev->flags & DM_FLAG_ALLOC_PDATA) {
81 if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
82 free(dev->uclass_platdata);
83 dev->uclass_platdata = NULL;
85 if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
86 free(dev->parent_platdata);
87 dev->parent_platdata = NULL;
89 ret = uclass_unbind_device(dev);
94 list_del(&dev->sibling_node);
101 * device_free() - Free memory buffers allocated by a device
102 * @dev: Device that is to be started
104 void device_free(struct udevice *dev)
108 if (dev->driver->priv_auto_alloc_size) {
112 size = dev->uclass->uc_drv->per_device_auto_alloc_size;
114 free(dev->uclass_priv);
115 dev->uclass_priv = NULL;
118 size = dev->parent->driver->per_child_auto_alloc_size;
120 size = dev->parent->uclass->uc_drv->
121 per_child_auto_alloc_size;
124 free(dev->parent_priv);
125 dev->parent_priv = NULL;
130 int device_remove(struct udevice *dev)
132 const struct driver *drv;
138 if (!(dev->flags & DM_FLAG_ACTIVATED))
144 ret = uclass_pre_remove_device(dev);
148 ret = device_remove_children(dev);
153 ret = drv->remove(dev);
158 if (dev->parent && dev->parent->driver->child_post_remove) {
159 ret = dev->parent->driver->child_post_remove(dev);
161 dm_warn("%s: Device '%s' failed child_post_remove()",
162 __func__, dev->name);
169 dev->flags &= ~DM_FLAG_ACTIVATED;
174 /* We can't put the children back */
175 dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
176 __func__, dev->name);
178 ret = uclass_post_probe_device(dev);
180 dm_warn("%s: Device '%s' failed to post_probe on error path\n",
181 __func__, dev->name);