]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/core/device.c
166b0732ab9e2ece25c292e42dec8ffc63102500
[karo-tx-uboot.git] / drivers / core / device.c
1 /*
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>
13 #include <fdtdec.h>
14 #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
25 DECLARE_GLOBAL_DATA_PTR;
26
27 /**
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  */
36 static int device_chld_unbind(struct udevice *dev)
37 {
38         struct udevice *pos, *n;
39         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  */
57 static int device_chld_remove(struct udevice *dev)
58 {
59         struct udevice *pos, *n;
60         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
73 int device_bind(struct udevice *parent, struct driver *drv, const char *name,
74                 void *platdata, int of_offset, struct udevice **devp)
75 {
76         struct udevice *dev;
77         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
88         dev = calloc(1, sizeof(struct udevice));
89         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;
101
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          */
109         dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
110         dev->seq = -1;
111         if (uc->uc_drv->name && of_offset != -1) {
112                 fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
113                                      &dev->req_seq);
114         }
115
116         if (!dev->platdata && drv->platdata_auto_alloc_size)
117                 dev->flags |= DM_FLAG_ALLOC_PDATA;
118
119         /* put dev into parent's successor list */
120         if (parent)
121                 list_add_tail(&dev->sibling_node, &parent->child_head);
122
123         ret = uclass_bind_device(dev);
124         if (ret)
125                 goto fail_bind;
126
127         /* if we fail to bind we remove device from successors and free it */
128         if (drv->bind) {
129                 ret = drv->bind(dev);
130                 if (ret) {
131                         if (uclass_unbind_device(dev)) {
132                                 dm_warn("Failed to unbind dev '%s' on error path\n",
133                                         dev->name);
134                         }
135                         goto fail_bind;
136                 }
137         }
138         if (parent)
139                 dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
140         *devp = dev;
141
142         return 0;
143
144 fail_bind:
145         list_del(&dev->sibling_node);
146         free(dev);
147         return ret;
148 }
149
150 int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
151                         const struct driver_info *info, struct udevice **devp)
152 {
153         struct driver *drv;
154
155         drv = lists_driver_lookup_name(info->name);
156         if (!drv)
157                 return -ENOENT;
158         if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
159                 return -EPERM;
160
161         return device_bind(parent, drv, info->name, (void *)info->platdata,
162                            -1, devp);
163 }
164
165 int device_unbind(struct udevice *dev)
166 {
167         struct driver *drv;
168         int ret;
169
170         if (!dev)
171                 return -EINVAL;
172
173         if (dev->flags & DM_FLAG_ACTIVATED)
174                 return -EINVAL;
175
176         drv = dev->driver;
177         assert(drv);
178
179         if (drv->unbind) {
180                 ret = drv->unbind(dev);
181                 if (ret)
182                         return ret;
183         }
184
185         ret = device_chld_unbind(dev);
186         if (ret)
187                 return ret;
188
189         ret = uclass_unbind_device(dev);
190         if (ret)
191                 return ret;
192
193         if (dev->parent)
194                 list_del(&dev->sibling_node);
195         free(dev);
196
197         return 0;
198 }
199
200 /**
201  * device_free() - Free memory buffers allocated by a device
202  * @dev:        Device that is to be started
203  */
204 static void device_free(struct udevice *dev)
205 {
206         int size;
207
208         if (dev->driver->priv_auto_alloc_size) {
209                 free(dev->priv);
210                 dev->priv = NULL;
211         }
212         if (dev->flags & DM_FLAG_ALLOC_PDATA) {
213                 free(dev->platdata);
214                 dev->platdata = NULL;
215         }
216         size = dev->uclass->uc_drv->per_device_auto_alloc_size;
217         if (size) {
218                 free(dev->uclass_priv);
219                 dev->uclass_priv = NULL;
220         }
221         if (dev->parent) {
222                 size = dev->parent->driver->per_child_auto_alloc_size;
223                 if (size) {
224                         free(dev->parent_priv);
225                         dev->parent_priv = NULL;
226                 }
227         }
228 }
229
230 int device_probe(struct udevice *dev)
231 {
232         struct driver *drv;
233         int size = 0;
234         int ret;
235         int seq;
236
237         if (!dev)
238                 return -EINVAL;
239
240         if (dev->flags & DM_FLAG_ACTIVATED)
241                 return 0;
242
243         drv = dev->driver;
244         assert(drv);
245
246         /* Allocate private data and platdata if requested */
247         if (drv->priv_auto_alloc_size) {
248                 dev->priv = calloc(1, drv->priv_auto_alloc_size);
249                 if (!dev->priv) {
250                         ret = -ENOMEM;
251                         goto fail;
252                 }
253         }
254         /* Allocate private data if requested */
255         if (dev->flags & DM_FLAG_ALLOC_PDATA) {
256                 dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
257                 if (!dev->platdata) {
258                         ret = -ENOMEM;
259                         goto fail;
260                 }
261         }
262         size = dev->uclass->uc_drv->per_device_auto_alloc_size;
263         if (size) {
264                 dev->uclass_priv = calloc(1, size);
265                 if (!dev->uclass_priv) {
266                         ret = -ENOMEM;
267                         goto fail;
268                 }
269         }
270
271         /* Ensure all parents are probed */
272         if (dev->parent) {
273                 size = dev->parent->driver->per_child_auto_alloc_size;
274                 if (size) {
275                         dev->parent_priv = calloc(1, size);
276                         if (!dev->parent_priv) {
277                                 ret = -ENOMEM;
278                                 goto fail;
279                         }
280                 }
281
282                 ret = device_probe(dev->parent);
283                 if (ret)
284                         goto fail;
285         }
286
287         seq = uclass_resolve_seq(dev);
288         if (seq < 0) {
289                 ret = seq;
290                 goto fail;
291         }
292         dev->seq = seq;
293
294         if (dev->parent && dev->parent->driver->child_pre_probe) {
295                 ret = dev->parent->driver->child_pre_probe(dev);
296                 if (ret)
297                         goto fail;
298         }
299
300         if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
301                 ret = drv->ofdata_to_platdata(dev);
302                 if (ret)
303                         goto fail;
304         }
305
306         if (drv->probe) {
307                 ret = drv->probe(dev);
308                 if (ret)
309                         goto fail;
310         }
311
312         dev->flags |= DM_FLAG_ACTIVATED;
313
314         ret = uclass_post_probe_device(dev);
315         if (ret) {
316                 dev->flags &= ~DM_FLAG_ACTIVATED;
317                 goto fail_uclass;
318         }
319
320         return 0;
321 fail_uclass:
322         if (device_remove(dev)) {
323                 dm_warn("%s: Device '%s' failed to remove on error path\n",
324                         __func__, dev->name);
325         }
326 fail:
327         dev->seq = -1;
328         device_free(dev);
329
330         return ret;
331 }
332
333 int device_remove(struct udevice *dev)
334 {
335         struct driver *drv;
336         int ret;
337
338         if (!dev)
339                 return -EINVAL;
340
341         if (!(dev->flags & DM_FLAG_ACTIVATED))
342                 return 0;
343
344         drv = dev->driver;
345         assert(drv);
346
347         ret = uclass_pre_remove_device(dev);
348         if (ret)
349                 return ret;
350
351         ret = device_chld_remove(dev);
352         if (ret)
353                 goto err;
354
355         if (drv->remove) {
356                 ret = drv->remove(dev);
357                 if (ret)
358                         goto err_remove;
359         }
360
361         if (dev->parent && dev->parent->driver->child_post_remove) {
362                 ret = dev->parent->driver->child_post_remove(dev);
363                 if (ret) {
364                         dm_warn("%s: Device '%s' failed child_post_remove()",
365                                 __func__, dev->name);
366                 }
367         }
368
369         device_free(dev);
370
371         dev->seq = -1;
372         dev->flags &= ~DM_FLAG_ACTIVATED;
373
374         return ret;
375
376 err_remove:
377         /* We can't put the children back */
378         dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
379                 __func__, dev->name);
380 err:
381         ret = uclass_post_probe_device(dev);
382         if (ret) {
383                 dm_warn("%s: Device '%s' failed to post_probe on error path\n",
384                         __func__, dev->name);
385         }
386
387         return ret;
388 }
389
390 void *dev_get_platdata(struct udevice *dev)
391 {
392         if (!dev) {
393                 dm_warn("%s: null device", __func__);
394                 return NULL;
395         }
396
397         return dev->platdata;
398 }
399
400 void *dev_get_priv(struct udevice *dev)
401 {
402         if (!dev) {
403                 dm_warn("%s: null device", __func__);
404                 return NULL;
405         }
406
407         return dev->priv;
408 }
409
410 void *dev_get_parentdata(struct udevice *dev)
411 {
412         if (!dev) {
413                 dm_warn("%s: null device", __func__);
414                 return NULL;
415         }
416
417         return dev->parent_priv;
418 }
419
420 static int device_get_device_tail(struct udevice *dev, int ret,
421                                   struct udevice **devp)
422 {
423         if (ret)
424                 return ret;
425
426         ret = device_probe(dev);
427         if (ret)
428                 return ret;
429
430         *devp = dev;
431
432         return 0;
433 }
434
435 int device_get_child(struct udevice *parent, int index, struct udevice **devp)
436 {
437         struct udevice *dev;
438
439         list_for_each_entry(dev, &parent->child_head, sibling_node) {
440                 if (!index--)
441                         return device_get_device_tail(dev, 0, devp);
442         }
443
444         return -ENODEV;
445 }
446
447 int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
448                              bool find_req_seq, struct udevice **devp)
449 {
450         struct udevice *dev;
451
452         *devp = NULL;
453         if (seq_or_req_seq == -1)
454                 return -ENODEV;
455
456         list_for_each_entry(dev, &parent->child_head, sibling_node) {
457                 if ((find_req_seq ? dev->req_seq : dev->seq) ==
458                                 seq_or_req_seq) {
459                         *devp = dev;
460                         return 0;
461                 }
462         }
463
464         return -ENODEV;
465 }
466
467 int device_get_child_by_seq(struct udevice *parent, int seq,
468                             struct udevice **devp)
469 {
470         struct udevice *dev;
471         int ret;
472
473         *devp = NULL;
474         ret = device_find_child_by_seq(parent, seq, false, &dev);
475         if (ret == -ENODEV) {
476                 /*
477                  * We didn't find it in probed devices. See if there is one
478                  * that will request this seq if probed.
479                  */
480                 ret = device_find_child_by_seq(parent, seq, true, &dev);
481         }
482         return device_get_device_tail(dev, ret, devp);
483 }
484
485 int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
486                                    struct udevice **devp)
487 {
488         struct udevice *dev;
489
490         *devp = NULL;
491
492         list_for_each_entry(dev, &parent->child_head, sibling_node) {
493                 if (dev->of_offset == of_offset) {
494                         *devp = dev;
495                         return 0;
496                 }
497         }
498
499         return -ENODEV;
500 }
501
502 int device_get_child_by_of_offset(struct udevice *parent, int seq,
503                                   struct udevice **devp)
504 {
505         struct udevice *dev;
506         int ret;
507
508         *devp = NULL;
509         ret = device_find_child_by_of_offset(parent, seq, &dev);
510         return device_get_device_tail(dev, ret, devp);
511 }