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)
64 if (!(dev->flags & DM_FLAG_BOUND))
71 ret = drv->unbind(dev);
76 ret = device_unbind_children(dev);
80 if (dev->flags & DM_FLAG_ALLOC_PDATA) {
84 if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
85 free(dev->uclass_platdata);
86 dev->uclass_platdata = NULL;
88 if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
89 free(dev->parent_platdata);
90 dev->parent_platdata = NULL;
92 ret = uclass_unbind_device(dev);
97 list_del(&dev->sibling_node);
99 devres_release_all(dev);
107 * device_free() - Free memory buffers allocated by a device
108 * @dev: Device that is to be started
110 void device_free(struct udevice *dev)
114 if (dev->driver->priv_auto_alloc_size) {
118 size = dev->uclass->uc_drv->per_device_auto_alloc_size;
120 free(dev->uclass_priv);
121 dev->uclass_priv = NULL;
124 size = dev->parent->driver->per_child_auto_alloc_size;
126 size = dev->parent->uclass->uc_drv->
127 per_child_auto_alloc_size;
130 free(dev->parent_priv);
131 dev->parent_priv = NULL;
135 devres_release_probe(dev);
138 int device_remove(struct udevice *dev)
140 const struct driver *drv;
146 if (!(dev->flags & DM_FLAG_ACTIVATED))
152 ret = uclass_pre_remove_device(dev);
156 ret = device_remove_children(dev);
161 ret = drv->remove(dev);
166 if (dev->parent && dev->parent->driver->child_post_remove) {
167 ret = dev->parent->driver->child_post_remove(dev);
169 dm_warn("%s: Device '%s' failed child_post_remove()",
170 __func__, dev->name);
177 dev->flags &= ~DM_FLAG_ACTIVATED;
182 /* We can't put the children back */
183 dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
184 __func__, dev->name);
186 ret = uclass_post_probe_device(dev);
188 dm_warn("%s: Device '%s' failed to post_probe on error path\n",
189 __func__, dev->name);