]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/core/device.c
dm: core: Mark device as active before calling uclass probe() methods
[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 int device_bind(struct udevice *parent, const struct driver *drv,
28                 const char *name, void *platdata, int of_offset,
29                 struct udevice **devp)
30 {
31         struct udevice *dev;
32         struct uclass *uc;
33         int ret = 0;
34
35         *devp = NULL;
36         if (!name)
37                 return -EINVAL;
38
39         ret = uclass_get(drv->id, &uc);
40         if (ret)
41                 return ret;
42
43         dev = calloc(1, sizeof(struct udevice));
44         if (!dev)
45                 return -ENOMEM;
46
47         INIT_LIST_HEAD(&dev->sibling_node);
48         INIT_LIST_HEAD(&dev->child_head);
49         INIT_LIST_HEAD(&dev->uclass_node);
50         dev->platdata = platdata;
51         dev->name = name;
52         dev->of_offset = of_offset;
53         dev->parent = parent;
54         dev->driver = drv;
55         dev->uclass = uc;
56
57         dev->seq = -1;
58         dev->req_seq = -1;
59 #ifdef CONFIG_OF_CONTROL
60         /*
61          * Some devices, such as a SPI bus, I2C bus and serial ports are
62          * numbered using aliases.
63          *
64          * This is just a 'requested' sequence, and will be
65          * resolved (and ->seq updated) when the device is probed.
66          */
67         if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
68                 if (uc->uc_drv->name && of_offset != -1) {
69                         fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name,
70                                              of_offset, &dev->req_seq);
71                 }
72         }
73 #endif
74         if (!dev->platdata && drv->platdata_auto_alloc_size) {
75                 dev->flags |= DM_FLAG_ALLOC_PDATA;
76                 dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
77                 if (!dev->platdata) {
78                         ret = -ENOMEM;
79                         goto fail_alloc1;
80                 }
81         }
82         if (parent) {
83                 int size = parent->driver->per_child_platdata_auto_alloc_size;
84
85                 if (!size) {
86                         size = parent->uclass->uc_drv->
87                                         per_child_platdata_auto_alloc_size;
88                 }
89                 if (size) {
90                         dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
91                         dev->parent_platdata = calloc(1, size);
92                         if (!dev->parent_platdata) {
93                                 ret = -ENOMEM;
94                                 goto fail_alloc2;
95                         }
96                 }
97         }
98
99         /* put dev into parent's successor list */
100         if (parent)
101                 list_add_tail(&dev->sibling_node, &parent->child_head);
102
103         ret = uclass_bind_device(dev);
104         if (ret)
105                 goto fail_uclass_bind;
106
107         /* if we fail to bind we remove device from successors and free it */
108         if (drv->bind) {
109                 ret = drv->bind(dev);
110                 if (ret)
111                         goto fail_bind;
112         }
113         if (parent && parent->driver->child_post_bind) {
114                 ret = parent->driver->child_post_bind(dev);
115                 if (ret)
116                         goto fail_child_post_bind;
117         }
118
119         if (parent)
120                 dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
121         *devp = dev;
122
123         return 0;
124
125 fail_child_post_bind:
126         if (drv->unbind && drv->unbind(dev)) {
127                 dm_warn("unbind() method failed on dev '%s' on error path\n",
128                         dev->name);
129         }
130
131 fail_bind:
132         if (uclass_unbind_device(dev)) {
133                 dm_warn("Failed to unbind dev '%s' on error path\n",
134                         dev->name);
135         }
136 fail_uclass_bind:
137         list_del(&dev->sibling_node);
138         if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
139                 free(dev->parent_platdata);
140                 dev->parent_platdata = NULL;
141         }
142 fail_alloc2:
143         if (dev->flags & DM_FLAG_ALLOC_PDATA) {
144                 free(dev->platdata);
145                 dev->platdata = NULL;
146         }
147 fail_alloc1:
148         free(dev);
149
150         return ret;
151 }
152
153 int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
154                         const struct driver_info *info, struct udevice **devp)
155 {
156         struct driver *drv;
157
158         drv = lists_driver_lookup_name(info->name);
159         if (!drv)
160                 return -ENOENT;
161         if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
162                 return -EPERM;
163
164         return device_bind(parent, drv, info->name, (void *)info->platdata,
165                            -1, devp);
166 }
167
168 static void *alloc_priv(int size, uint flags)
169 {
170         void *priv;
171
172         if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
173                 priv = memalign(ARCH_DMA_MINALIGN, size);
174                 if (priv)
175                         memset(priv, '\0', size);
176         } else {
177                 priv = calloc(1, size);
178         }
179
180         return priv;
181 }
182
183 int device_probe_child(struct udevice *dev, void *parent_priv)
184 {
185         const struct driver *drv;
186         int size = 0;
187         int ret;
188         int seq;
189
190         if (!dev)
191                 return -EINVAL;
192
193         if (dev->flags & DM_FLAG_ACTIVATED)
194                 return 0;
195
196         drv = dev->driver;
197         assert(drv);
198
199         /* Allocate private data if requested */
200         if (drv->priv_auto_alloc_size) {
201                 dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
202                 if (!dev->priv) {
203                         ret = -ENOMEM;
204                         goto fail;
205                 }
206         }
207         /* Allocate private data if requested */
208         size = dev->uclass->uc_drv->per_device_auto_alloc_size;
209         if (size) {
210                 dev->uclass_priv = calloc(1, size);
211                 if (!dev->uclass_priv) {
212                         ret = -ENOMEM;
213                         goto fail;
214                 }
215         }
216
217         /* Ensure all parents are probed */
218         if (dev->parent) {
219                 size = dev->parent->driver->per_child_auto_alloc_size;
220                 if (!size) {
221                         size = dev->parent->uclass->uc_drv->
222                                         per_child_auto_alloc_size;
223                 }
224                 if (size) {
225                         dev->parent_priv = alloc_priv(size, drv->flags);
226                         if (!dev->parent_priv) {
227                                 ret = -ENOMEM;
228                                 goto fail;
229                         }
230                         if (parent_priv)
231                                 memcpy(dev->parent_priv, parent_priv, size);
232                 }
233
234                 ret = device_probe(dev->parent);
235                 if (ret)
236                         goto fail;
237         }
238
239         seq = uclass_resolve_seq(dev);
240         if (seq < 0) {
241                 ret = seq;
242                 goto fail;
243         }
244         dev->seq = seq;
245
246         dev->flags |= DM_FLAG_ACTIVATED;
247
248         ret = uclass_pre_probe_device(dev);
249         if (ret)
250                 goto fail;
251
252         if (dev->parent && dev->parent->driver->child_pre_probe) {
253                 ret = dev->parent->driver->child_pre_probe(dev);
254                 if (ret)
255                         goto fail;
256         }
257
258         if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
259                 ret = drv->ofdata_to_platdata(dev);
260                 if (ret)
261                         goto fail;
262         }
263
264         dev->flags |= DM_FLAG_ACTIVATED;
265         if (drv->probe) {
266                 ret = drv->probe(dev);
267                 if (ret) {
268                         dev->flags &= ~DM_FLAG_ACTIVATED;
269                         goto fail;
270                 }
271         }
272
273         ret = uclass_post_probe_device(dev);
274         if (ret)
275                 goto fail_uclass;
276
277         return 0;
278 fail_uclass:
279         if (device_remove(dev)) {
280                 dm_warn("%s: Device '%s' failed to remove on error path\n",
281                         __func__, dev->name);
282         }
283 fail:
284         dev->flags &= ~DM_FLAG_ACTIVATED;
285
286         dev->seq = -1;
287         device_free(dev);
288
289         return ret;
290 }
291
292 int device_probe(struct udevice *dev)
293 {
294         return device_probe_child(dev, NULL);
295 }
296
297 void *dev_get_platdata(struct udevice *dev)
298 {
299         if (!dev) {
300                 dm_warn("%s: null device\n", __func__);
301                 return NULL;
302         }
303
304         return dev->platdata;
305 }
306
307 void *dev_get_parent_platdata(struct udevice *dev)
308 {
309         if (!dev) {
310                 dm_warn("%s: null device", __func__);
311                 return NULL;
312         }
313
314         return dev->parent_platdata;
315 }
316
317 void *dev_get_priv(struct udevice *dev)
318 {
319         if (!dev) {
320                 dm_warn("%s: null device\n", __func__);
321                 return NULL;
322         }
323
324         return dev->priv;
325 }
326
327 void *dev_get_uclass_priv(struct udevice *dev)
328 {
329         if (!dev) {
330                 dm_warn("%s: null device\n", __func__);
331                 return NULL;
332         }
333
334         return dev->uclass_priv;
335 }
336
337 void *dev_get_parentdata(struct udevice *dev)
338 {
339         if (!dev) {
340                 dm_warn("%s: null device\n", __func__);
341                 return NULL;
342         }
343
344         return dev->parent_priv;
345 }
346
347 static int device_get_device_tail(struct udevice *dev, int ret,
348                                   struct udevice **devp)
349 {
350         if (ret)
351                 return ret;
352
353         ret = device_probe(dev);
354         if (ret)
355                 return ret;
356
357         *devp = dev;
358
359         return 0;
360 }
361
362 int device_get_child(struct udevice *parent, int index, struct udevice **devp)
363 {
364         struct udevice *dev;
365
366         list_for_each_entry(dev, &parent->child_head, sibling_node) {
367                 if (!index--)
368                         return device_get_device_tail(dev, 0, devp);
369         }
370
371         return -ENODEV;
372 }
373
374 int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
375                              bool find_req_seq, struct udevice **devp)
376 {
377         struct udevice *dev;
378
379         *devp = NULL;
380         if (seq_or_req_seq == -1)
381                 return -ENODEV;
382
383         list_for_each_entry(dev, &parent->child_head, sibling_node) {
384                 if ((find_req_seq ? dev->req_seq : dev->seq) ==
385                                 seq_or_req_seq) {
386                         *devp = dev;
387                         return 0;
388                 }
389         }
390
391         return -ENODEV;
392 }
393
394 int device_get_child_by_seq(struct udevice *parent, int seq,
395                             struct udevice **devp)
396 {
397         struct udevice *dev;
398         int ret;
399
400         *devp = NULL;
401         ret = device_find_child_by_seq(parent, seq, false, &dev);
402         if (ret == -ENODEV) {
403                 /*
404                  * We didn't find it in probed devices. See if there is one
405                  * that will request this seq if probed.
406                  */
407                 ret = device_find_child_by_seq(parent, seq, true, &dev);
408         }
409         return device_get_device_tail(dev, ret, devp);
410 }
411
412 int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
413                                    struct udevice **devp)
414 {
415         struct udevice *dev;
416
417         *devp = NULL;
418
419         list_for_each_entry(dev, &parent->child_head, sibling_node) {
420                 if (dev->of_offset == of_offset) {
421                         *devp = dev;
422                         return 0;
423                 }
424         }
425
426         return -ENODEV;
427 }
428
429 int device_get_child_by_of_offset(struct udevice *parent, int seq,
430                                   struct udevice **devp)
431 {
432         struct udevice *dev;
433         int ret;
434
435         *devp = NULL;
436         ret = device_find_child_by_of_offset(parent, seq, &dev);
437         return device_get_device_tail(dev, ret, devp);
438 }
439
440 int device_find_first_child(struct udevice *parent, struct udevice **devp)
441 {
442         if (list_empty(&parent->child_head)) {
443                 *devp = NULL;
444         } else {
445                 *devp = list_first_entry(&parent->child_head, struct udevice,
446                                          sibling_node);
447         }
448
449         return 0;
450 }
451
452 int device_find_next_child(struct udevice **devp)
453 {
454         struct udevice *dev = *devp;
455         struct udevice *parent = dev->parent;
456
457         if (list_is_last(&dev->sibling_node, &parent->child_head)) {
458                 *devp = NULL;
459         } else {
460                 *devp = list_entry(dev->sibling_node.next, struct udevice,
461                                    sibling_node);
462         }
463
464         return 0;
465 }
466
467 struct udevice *dev_get_parent(struct udevice *child)
468 {
469         return child->parent;
470 }
471
472 ulong dev_get_driver_data(struct udevice *dev)
473 {
474         return dev->driver_data;
475 }
476
477 enum uclass_id device_get_uclass_id(struct udevice *dev)
478 {
479         return dev->uclass->uc_drv->id;
480 }
481
482 #ifdef CONFIG_OF_CONTROL
483 fdt_addr_t dev_get_addr(struct udevice *dev)
484 {
485         return fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
486 }
487 #else
488 fdt_addr_t dev_get_addr(struct udevice *dev)
489 {
490         return FDT_ADDR_T_NONE;
491 }
492 #endif