blob: ef41a9be3edc3d9cb20247f5026bd720a265d5a7 [file] [log] [blame]
Simon Glass6494d702014-02-26 15:59:18 -07001/*
2 * Device manager
3 *
4 * Copyright (c) 2013 Google, Inc
5 *
6 * (C) Copyright 2012
7 * Pavel Herrmann <morpheus.ibis@gmail.com>
8 *
9 * SPDX-License-Identifier: GPL-2.0+
10 */
11
12#include <common.h>
Simon Glass5a66a8f2014-07-23 06:55:12 -060013#include <fdtdec.h>
Simon Glass6494d702014-02-26 15:59:18 -070014#include <malloc.h>
15#include <dm/device.h>
16#include <dm/device-internal.h>
17#include <dm/lists.h>
18#include <dm/platdata.h>
19#include <dm/uclass.h>
20#include <dm/uclass-internal.h>
21#include <dm/util.h>
22#include <linux/err.h>
23#include <linux/list.h>
24
Simon Glass5a66a8f2014-07-23 06:55:12 -060025DECLARE_GLOBAL_DATA_PTR;
26
Simon Glass6494d702014-02-26 15:59:18 -070027/**
28 * device_chld_unbind() - Unbind all device's children from the device
29 *
30 * On error, the function continues to unbind all children, and reports the
31 * first error.
32 *
33 * @dev: The device that is to be stripped of its children
34 * @return 0 on success, -ve on error
35 */
Heiko Schocher54c5d082014-05-22 12:43:05 +020036static int device_chld_unbind(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -070037{
Heiko Schocher54c5d082014-05-22 12:43:05 +020038 struct udevice *pos, *n;
Simon Glass6494d702014-02-26 15:59:18 -070039 int ret, saved_ret = 0;
40
41 assert(dev);
42
43 list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
44 ret = device_unbind(pos);
45 if (ret && !saved_ret)
46 saved_ret = ret;
47 }
48
49 return saved_ret;
50}
51
52/**
53 * device_chld_remove() - Stop all device's children
54 * @dev: The device whose children are to be removed
55 * @return 0 on success, -ve on error
56 */
Heiko Schocher54c5d082014-05-22 12:43:05 +020057static int device_chld_remove(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -070058{
Heiko Schocher54c5d082014-05-22 12:43:05 +020059 struct udevice *pos, *n;
Simon Glass6494d702014-02-26 15:59:18 -070060 int ret;
61
62 assert(dev);
63
64 list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
65 ret = device_remove(pos);
66 if (ret)
67 return ret;
68 }
69
70 return 0;
71}
72
Heiko Schocher54c5d082014-05-22 12:43:05 +020073int device_bind(struct udevice *parent, struct driver *drv, const char *name,
74 void *platdata, int of_offset, struct udevice **devp)
Simon Glass6494d702014-02-26 15:59:18 -070075{
Heiko Schocher54c5d082014-05-22 12:43:05 +020076 struct udevice *dev;
Simon Glass6494d702014-02-26 15:59:18 -070077 struct uclass *uc;
78 int ret = 0;
79
80 *devp = NULL;
81 if (!name)
82 return -EINVAL;
83
84 ret = uclass_get(drv->id, &uc);
85 if (ret)
86 return ret;
87
Heiko Schocher54c5d082014-05-22 12:43:05 +020088 dev = calloc(1, sizeof(struct udevice));
Simon Glass6494d702014-02-26 15:59:18 -070089 if (!dev)
90 return -ENOMEM;
91
92 INIT_LIST_HEAD(&dev->sibling_node);
93 INIT_LIST_HEAD(&dev->child_head);
94 INIT_LIST_HEAD(&dev->uclass_node);
95 dev->platdata = platdata;
96 dev->name = name;
97 dev->of_offset = of_offset;
98 dev->parent = parent;
99 dev->driver = drv;
100 dev->uclass = uc;
Simon Glass5a66a8f2014-07-23 06:55:12 -0600101
102 /*
103 * For some devices, such as a SPI or I2C bus, the 'reg' property
104 * is a reasonable indicator of the sequence number. But if there is
105 * an alias, we use that in preference. In any case, this is just
106 * a 'requested' sequence, and will be resolved (and ->seq updated)
107 * when the device is probed.
108 */
Simon Glass5a66a8f2014-07-23 06:55:12 -0600109 dev->seq = -1;
Simon Glass91cbd792014-09-17 09:02:38 -0600110#ifdef CONFIG_OF_CONTROL
111 dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
Simon Glass5a66a8f2014-07-23 06:55:12 -0600112 if (uc->uc_drv->name && of_offset != -1) {
113 fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
114 &dev->req_seq);
115 }
Simon Glass91cbd792014-09-17 09:02:38 -0600116#else
117 dev->req_seq = -1;
118#endif
Simon Glass6494d702014-02-26 15:59:18 -0700119 if (!dev->platdata && drv->platdata_auto_alloc_size)
120 dev->flags |= DM_FLAG_ALLOC_PDATA;
121
122 /* put dev into parent's successor list */
123 if (parent)
124 list_add_tail(&dev->sibling_node, &parent->child_head);
125
126 ret = uclass_bind_device(dev);
127 if (ret)
128 goto fail_bind;
129
130 /* if we fail to bind we remove device from successors and free it */
131 if (drv->bind) {
132 ret = drv->bind(dev);
133 if (ret) {
134 if (uclass_unbind_device(dev)) {
135 dm_warn("Failed to unbind dev '%s' on error path\n",
136 dev->name);
137 }
138 goto fail_bind;
139 }
140 }
141 if (parent)
142 dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
143 *devp = dev;
144
145 return 0;
146
147fail_bind:
148 list_del(&dev->sibling_node);
149 free(dev);
150 return ret;
151}
152
Simon Glass00606d72014-07-23 06:55:03 -0600153int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
154 const struct driver_info *info, struct udevice **devp)
Simon Glass6494d702014-02-26 15:59:18 -0700155{
156 struct driver *drv;
157
158 drv = lists_driver_lookup_name(info->name);
159 if (!drv)
160 return -ENOENT;
Simon Glass00606d72014-07-23 06:55:03 -0600161 if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
162 return -EPERM;
Simon Glass6494d702014-02-26 15:59:18 -0700163
164 return device_bind(parent, drv, info->name, (void *)info->platdata,
165 -1, devp);
166}
167
Heiko Schocher54c5d082014-05-22 12:43:05 +0200168int device_unbind(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700169{
170 struct driver *drv;
171 int ret;
172
173 if (!dev)
174 return -EINVAL;
175
176 if (dev->flags & DM_FLAG_ACTIVATED)
177 return -EINVAL;
178
179 drv = dev->driver;
180 assert(drv);
181
182 if (drv->unbind) {
183 ret = drv->unbind(dev);
184 if (ret)
185 return ret;
186 }
187
188 ret = device_chld_unbind(dev);
189 if (ret)
190 return ret;
191
192 ret = uclass_unbind_device(dev);
193 if (ret)
194 return ret;
195
196 if (dev->parent)
197 list_del(&dev->sibling_node);
198 free(dev);
199
200 return 0;
201}
202
203/**
204 * device_free() - Free memory buffers allocated by a device
205 * @dev: Device that is to be started
206 */
Heiko Schocher54c5d082014-05-22 12:43:05 +0200207static void device_free(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700208{
209 int size;
210
211 if (dev->driver->priv_auto_alloc_size) {
212 free(dev->priv);
213 dev->priv = NULL;
214 }
215 if (dev->flags & DM_FLAG_ALLOC_PDATA) {
216 free(dev->platdata);
217 dev->platdata = NULL;
218 }
219 size = dev->uclass->uc_drv->per_device_auto_alloc_size;
220 if (size) {
221 free(dev->uclass_priv);
222 dev->uclass_priv = NULL;
223 }
Simon Glasse59f4582014-07-23 06:55:20 -0600224 if (dev->parent) {
225 size = dev->parent->driver->per_child_auto_alloc_size;
226 if (size) {
227 free(dev->parent_priv);
228 dev->parent_priv = NULL;
229 }
230 }
Simon Glass6494d702014-02-26 15:59:18 -0700231}
232
Heiko Schocher54c5d082014-05-22 12:43:05 +0200233int device_probe(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700234{
235 struct driver *drv;
236 int size = 0;
237 int ret;
Simon Glass5a66a8f2014-07-23 06:55:12 -0600238 int seq;
Simon Glass6494d702014-02-26 15:59:18 -0700239
240 if (!dev)
241 return -EINVAL;
242
243 if (dev->flags & DM_FLAG_ACTIVATED)
244 return 0;
245
246 drv = dev->driver;
247 assert(drv);
248
249 /* Allocate private data and platdata if requested */
250 if (drv->priv_auto_alloc_size) {
251 dev->priv = calloc(1, drv->priv_auto_alloc_size);
252 if (!dev->priv) {
253 ret = -ENOMEM;
254 goto fail;
255 }
256 }
257 /* Allocate private data if requested */
258 if (dev->flags & DM_FLAG_ALLOC_PDATA) {
259 dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
260 if (!dev->platdata) {
261 ret = -ENOMEM;
262 goto fail;
263 }
264 }
265 size = dev->uclass->uc_drv->per_device_auto_alloc_size;
266 if (size) {
267 dev->uclass_priv = calloc(1, size);
268 if (!dev->uclass_priv) {
269 ret = -ENOMEM;
270 goto fail;
271 }
272 }
273
274 /* Ensure all parents are probed */
275 if (dev->parent) {
Simon Glasse59f4582014-07-23 06:55:20 -0600276 size = dev->parent->driver->per_child_auto_alloc_size;
277 if (size) {
278 dev->parent_priv = calloc(1, size);
279 if (!dev->parent_priv) {
280 ret = -ENOMEM;
281 goto fail;
282 }
283 }
284
Simon Glass6494d702014-02-26 15:59:18 -0700285 ret = device_probe(dev->parent);
286 if (ret)
287 goto fail;
288 }
289
Simon Glass5a66a8f2014-07-23 06:55:12 -0600290 seq = uclass_resolve_seq(dev);
291 if (seq < 0) {
292 ret = seq;
293 goto fail;
294 }
295 dev->seq = seq;
296
Simon Glassa327dee2014-07-23 06:55:21 -0600297 if (dev->parent && dev->parent->driver->child_pre_probe) {
298 ret = dev->parent->driver->child_pre_probe(dev);
299 if (ret)
300 goto fail;
301 }
302
Simon Glass6494d702014-02-26 15:59:18 -0700303 if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
304 ret = drv->ofdata_to_platdata(dev);
305 if (ret)
306 goto fail;
307 }
308
309 if (drv->probe) {
310 ret = drv->probe(dev);
311 if (ret)
312 goto fail;
313 }
314
315 dev->flags |= DM_FLAG_ACTIVATED;
316
317 ret = uclass_post_probe_device(dev);
318 if (ret) {
319 dev->flags &= ~DM_FLAG_ACTIVATED;
320 goto fail_uclass;
321 }
322
323 return 0;
324fail_uclass:
325 if (device_remove(dev)) {
326 dm_warn("%s: Device '%s' failed to remove on error path\n",
327 __func__, dev->name);
328 }
329fail:
Simon Glass5a66a8f2014-07-23 06:55:12 -0600330 dev->seq = -1;
Simon Glass6494d702014-02-26 15:59:18 -0700331 device_free(dev);
332
333 return ret;
334}
335
Heiko Schocher54c5d082014-05-22 12:43:05 +0200336int device_remove(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700337{
338 struct driver *drv;
339 int ret;
340
341 if (!dev)
342 return -EINVAL;
343
344 if (!(dev->flags & DM_FLAG_ACTIVATED))
345 return 0;
346
347 drv = dev->driver;
348 assert(drv);
349
350 ret = uclass_pre_remove_device(dev);
351 if (ret)
352 return ret;
353
354 ret = device_chld_remove(dev);
355 if (ret)
356 goto err;
357
358 if (drv->remove) {
359 ret = drv->remove(dev);
360 if (ret)
361 goto err_remove;
362 }
363
Simon Glassa327dee2014-07-23 06:55:21 -0600364 if (dev->parent && dev->parent->driver->child_post_remove) {
365 ret = dev->parent->driver->child_post_remove(dev);
366 if (ret) {
367 dm_warn("%s: Device '%s' failed child_post_remove()",
368 __func__, dev->name);
369 }
370 }
371
Simon Glass6494d702014-02-26 15:59:18 -0700372 device_free(dev);
373
Simon Glass5a66a8f2014-07-23 06:55:12 -0600374 dev->seq = -1;
Simon Glass6494d702014-02-26 15:59:18 -0700375 dev->flags &= ~DM_FLAG_ACTIVATED;
376
Simon Glassa327dee2014-07-23 06:55:21 -0600377 return ret;
Simon Glass6494d702014-02-26 15:59:18 -0700378
379err_remove:
380 /* We can't put the children back */
381 dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
382 __func__, dev->name);
383err:
384 ret = uclass_post_probe_device(dev);
385 if (ret) {
386 dm_warn("%s: Device '%s' failed to post_probe on error path\n",
387 __func__, dev->name);
388 }
389
390 return ret;
391}
392
Heiko Schocher54c5d082014-05-22 12:43:05 +0200393void *dev_get_platdata(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700394{
395 if (!dev) {
396 dm_warn("%s: null device", __func__);
397 return NULL;
398 }
399
400 return dev->platdata;
401}
402
Heiko Schocher54c5d082014-05-22 12:43:05 +0200403void *dev_get_priv(struct udevice *dev)
Simon Glass6494d702014-02-26 15:59:18 -0700404{
405 if (!dev) {
406 dm_warn("%s: null device", __func__);
407 return NULL;
408 }
409
410 return dev->priv;
411}
Simon Glass997c87b2014-07-23 06:55:19 -0600412
Simon Glasse59f4582014-07-23 06:55:20 -0600413void *dev_get_parentdata(struct udevice *dev)
414{
415 if (!dev) {
416 dm_warn("%s: null device", __func__);
417 return NULL;
418 }
419
420 return dev->parent_priv;
421}
422
Simon Glass997c87b2014-07-23 06:55:19 -0600423static int device_get_device_tail(struct udevice *dev, int ret,
424 struct udevice **devp)
425{
426 if (ret)
427 return ret;
428
429 ret = device_probe(dev);
430 if (ret)
431 return ret;
432
433 *devp = dev;
434
435 return 0;
436}
437
438int device_get_child(struct udevice *parent, int index, struct udevice **devp)
439{
440 struct udevice *dev;
441
442 list_for_each_entry(dev, &parent->child_head, sibling_node) {
443 if (!index--)
444 return device_get_device_tail(dev, 0, devp);
445 }
446
447 return -ENODEV;
448}
449
450int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
451 bool find_req_seq, struct udevice **devp)
452{
453 struct udevice *dev;
454
455 *devp = NULL;
456 if (seq_or_req_seq == -1)
457 return -ENODEV;
458
459 list_for_each_entry(dev, &parent->child_head, sibling_node) {
460 if ((find_req_seq ? dev->req_seq : dev->seq) ==
461 seq_or_req_seq) {
462 *devp = dev;
463 return 0;
464 }
465 }
466
467 return -ENODEV;
468}
469
470int device_get_child_by_seq(struct udevice *parent, int seq,
471 struct udevice **devp)
472{
473 struct udevice *dev;
474 int ret;
475
476 *devp = NULL;
477 ret = device_find_child_by_seq(parent, seq, false, &dev);
478 if (ret == -ENODEV) {
479 /*
480 * We didn't find it in probed devices. See if there is one
481 * that will request this seq if probed.
482 */
483 ret = device_find_child_by_seq(parent, seq, true, &dev);
484 }
485 return device_get_device_tail(dev, ret, devp);
486}
487
488int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
489 struct udevice **devp)
490{
491 struct udevice *dev;
492
493 *devp = NULL;
494
495 list_for_each_entry(dev, &parent->child_head, sibling_node) {
496 if (dev->of_offset == of_offset) {
497 *devp = dev;
498 return 0;
499 }
500 }
501
502 return -ENODEV;
503}
504
505int device_get_child_by_of_offset(struct udevice *parent, int seq,
506 struct udevice **devp)
507{
508 struct udevice *dev;
509 int ret;
510
511 *devp = NULL;
512 ret = device_find_child_by_of_offset(parent, seq, &dev);
513 return device_get_device_tail(dev, ret, devp);
514}