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
);
104 * device_free() - Free memory buffers allocated by a device
105 * @dev: Device that is to be started
107 void device_free(struct udevice
*dev
)
111 if (dev
->driver
->priv_auto_alloc_size
) {
115 size
= dev
->uclass
->uc_drv
->per_device_auto_alloc_size
;
117 free(dev
->uclass_priv
);
118 dev
->uclass_priv
= NULL
;
121 size
= dev
->parent
->driver
->per_child_auto_alloc_size
;
123 size
= dev
->parent
->uclass
->uc_drv
->
124 per_child_auto_alloc_size
;
127 free(dev
->parent_priv
);
128 dev
->parent_priv
= NULL
;
133 int device_remove(struct udevice
*dev
)
135 const struct driver
*drv
;
141 if (!(dev
->flags
& DM_FLAG_ACTIVATED
))
147 ret
= uclass_pre_remove_device(dev
);
151 ret
= device_remove_children(dev
);
156 ret
= drv
->remove(dev
);
161 if (dev
->parent
&& dev
->parent
->driver
->child_post_remove
) {
162 ret
= dev
->parent
->driver
->child_post_remove(dev
);
164 dm_warn("%s: Device '%s' failed child_post_remove()",
165 __func__
, dev
->name
);
172 dev
->flags
&= ~DM_FLAG_ACTIVATED
;
177 /* We can't put the children back */
178 dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
179 __func__
, dev
->name
);
181 ret
= uclass_post_probe_device(dev
);
183 dm_warn("%s: Device '%s' failed to post_probe on error path\n",
184 __func__
, dev
->name
);