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>
22 * device_chld_unbind() - Unbind all device's children from the device
24 * On error, the function continues to unbind all children, and reports the
27 * @dev: The device that is to be stripped of its children
28 * @return 0 on success, -ve on error
30 static int device_chld_unbind(struct udevice
*dev
)
32 struct udevice
*pos
, *n
;
33 int ret
, saved_ret
= 0;
37 list_for_each_entry_safe(pos
, n
, &dev
->child_head
, sibling_node
) {
38 ret
= device_unbind(pos
);
39 if (ret
&& !saved_ret
)
47 * device_chld_remove() - Stop all device's children
48 * @dev: The device whose children are to be removed
49 * @pre_os_remove: Flag, if this functions is called in the pre-OS stage
50 * @return 0 on success, -ve on error
52 static int device_chld_remove(struct udevice
*dev
, uint flags
)
54 struct udevice
*pos
, *n
;
59 list_for_each_entry_safe(pos
, n
, &dev
->child_head
, sibling_node
) {
60 ret
= device_remove(pos
, flags
);
68 int device_unbind(struct udevice
*dev
)
70 const struct driver
*drv
;
76 if (dev
->flags
& DM_FLAG_ACTIVATED
)
79 if (!(dev
->flags
& DM_FLAG_BOUND
))
86 ret
= drv
->unbind(dev
);
91 ret
= device_chld_unbind(dev
);
95 if (dev
->flags
& DM_FLAG_ALLOC_PDATA
) {
99 if (dev
->flags
& DM_FLAG_ALLOC_UCLASS_PDATA
) {
100 free(dev
->uclass_platdata
);
101 dev
->uclass_platdata
= NULL
;
103 if (dev
->flags
& DM_FLAG_ALLOC_PARENT_PDATA
) {
104 free(dev
->parent_platdata
);
105 dev
->parent_platdata
= NULL
;
107 ret
= uclass_unbind_device(dev
);
112 list_del(&dev
->sibling_node
);
114 devres_release_all(dev
);
116 if (dev
->flags
& DM_FLAG_NAME_ALLOCED
)
117 free((char *)dev
->name
);
124 * device_free() - Free memory buffers allocated by a device
125 * @dev: Device that is to be started
127 void device_free(struct udevice
*dev
)
131 if (dev
->driver
->priv_auto_alloc_size
) {
135 size
= dev
->uclass
->uc_drv
->per_device_auto_alloc_size
;
137 free(dev
->uclass_priv
);
138 dev
->uclass_priv
= NULL
;
141 size
= dev
->parent
->driver
->per_child_auto_alloc_size
;
143 size
= dev
->parent
->uclass
->uc_drv
->
144 per_child_auto_alloc_size
;
147 free(dev
->parent_priv
);
148 dev
->parent_priv
= NULL
;
152 devres_release_probe(dev
);
155 static bool flags_remove(uint flags
, uint drv_flags
)
157 if ((flags
& DM_REMOVE_NORMAL
) ||
158 (flags
& (drv_flags
& (DM_FLAG_ACTIVE_DMA
| DM_FLAG_OS_PREPARE
))))
164 int device_remove(struct udevice
*dev
, uint flags
)
166 const struct driver
*drv
;
172 if (!(dev
->flags
& DM_FLAG_ACTIVATED
))
178 ret
= uclass_pre_remove_device(dev
);
182 ret
= device_chld_remove(dev
, flags
);
187 * Remove the device if called with the "normal" remove flag set,
188 * or if the remove flag matches any of the drivers remove flags
190 if (drv
->remove
&& flags_remove(flags
, drv
->flags
)) {
191 ret
= drv
->remove(dev
);
196 if (dev
->parent
&& dev
->parent
->driver
->child_post_remove
) {
197 ret
= dev
->parent
->driver
->child_post_remove(dev
);
199 dm_warn("%s: Device '%s' failed child_post_remove()",
200 __func__
, dev
->name
);
204 if (flags_remove(flags
, drv
->flags
)) {
208 dev
->flags
&= ~DM_FLAG_ACTIVATED
;
214 /* We can't put the children back */
215 dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
216 __func__
, dev
->name
);
218 ret
= uclass_post_probe_device(dev
);
220 dm_warn("%s: Device '%s' failed to post_probe on error path\n",
221 __func__
, dev
->name
);