]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/core/device.c
Merge branch 'master' of git://git.denx.de/u-boot-usb
[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, struct driver *drv, const char *name,
28                 void *platdata, int of_offset, struct udevice **devp)
29 {
30         struct udevice *dev;
31         struct uclass *uc;
32         int ret = 0;
33
34         *devp = NULL;
35         if (!name)
36                 return -EINVAL;
37
38         ret = uclass_get(drv->id, &uc);
39         if (ret)
40                 return ret;
41
42         dev = calloc(1, sizeof(struct udevice));
43         if (!dev)
44                 return -ENOMEM;
45
46         INIT_LIST_HEAD(&dev->sibling_node);
47         INIT_LIST_HEAD(&dev->child_head);
48         INIT_LIST_HEAD(&dev->uclass_node);
49         dev->platdata = platdata;
50         dev->name = name;
51         dev->of_offset = of_offset;
52         dev->parent = parent;
53         dev->driver = drv;
54         dev->uclass = uc;
55
56         /*
57          * For some devices, such as a SPI or I2C bus, the 'reg' property
58          * is a reasonable indicator of the sequence number. But if there is
59          * an alias, we use that in preference. In any case, this is just
60          * a 'requested' sequence, and will be resolved (and ->seq updated)
61          * when the device is probed.
62          */
63         dev->seq = -1;
64 #ifdef CONFIG_OF_CONTROL
65         dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
66         if (!IS_ERR_VALUE(dev->req_seq))
67                 dev->req_seq &= INT_MAX;
68         if (uc->uc_drv->name && of_offset != -1) {
69                 fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
70                                      &dev->req_seq);
71         }
72 #else
73         dev->req_seq = -1;
74 #endif
75         if (!dev->platdata && drv->platdata_auto_alloc_size)
76                 dev->flags |= DM_FLAG_ALLOC_PDATA;
77
78         /* put dev into parent's successor list */
79         if (parent)
80                 list_add_tail(&dev->sibling_node, &parent->child_head);
81
82         ret = uclass_bind_device(dev);
83         if (ret)
84                 goto fail_bind;
85
86         /* if we fail to bind we remove device from successors and free it */
87         if (drv->bind) {
88                 ret = drv->bind(dev);
89                 if (ret) {
90                         if (uclass_unbind_device(dev)) {
91                                 dm_warn("Failed to unbind dev '%s' on error path\n",
92                                         dev->name);
93                         }
94                         goto fail_bind;
95                 }
96         }
97         if (parent)
98                 dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
99         *devp = dev;
100
101         return 0;
102
103 fail_bind:
104         list_del(&dev->sibling_node);
105         free(dev);
106         return ret;
107 }
108
109 int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
110                         const struct driver_info *info, struct udevice **devp)
111 {
112         struct driver *drv;
113
114         drv = lists_driver_lookup_name(info->name);
115         if (!drv)
116                 return -ENOENT;
117         if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
118                 return -EPERM;
119
120         return device_bind(parent, drv, info->name, (void *)info->platdata,
121                            -1, devp);
122 }
123
124 int device_probe_child(struct udevice *dev, void *parent_priv)
125 {
126         struct driver *drv;
127         int size = 0;
128         int ret;
129         int seq;
130
131         if (!dev)
132                 return -EINVAL;
133
134         if (dev->flags & DM_FLAG_ACTIVATED)
135                 return 0;
136
137         drv = dev->driver;
138         assert(drv);
139
140         /* Allocate private data and platdata if requested */
141         if (drv->priv_auto_alloc_size) {
142                 dev->priv = calloc(1, drv->priv_auto_alloc_size);
143                 if (!dev->priv) {
144                         ret = -ENOMEM;
145                         goto fail;
146                 }
147         }
148         /* Allocate private data if requested */
149         if (dev->flags & DM_FLAG_ALLOC_PDATA) {
150                 dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
151                 if (!dev->platdata) {
152                         ret = -ENOMEM;
153                         goto fail;
154                 }
155         }
156         size = dev->uclass->uc_drv->per_device_auto_alloc_size;
157         if (size) {
158                 dev->uclass_priv = calloc(1, size);
159                 if (!dev->uclass_priv) {
160                         ret = -ENOMEM;
161                         goto fail;
162                 }
163         }
164
165         /* Ensure all parents are probed */
166         if (dev->parent) {
167                 size = dev->parent->driver->per_child_auto_alloc_size;
168                 if (size) {
169                         dev->parent_priv = calloc(1, size);
170                         if (!dev->parent_priv) {
171                                 ret = -ENOMEM;
172                                 goto fail;
173                         }
174                         if (parent_priv)
175                                 memcpy(dev->parent_priv, parent_priv, size);
176                 }
177
178                 ret = device_probe(dev->parent);
179                 if (ret)
180                         goto fail;
181         }
182
183         seq = uclass_resolve_seq(dev);
184         if (seq < 0) {
185                 ret = seq;
186                 goto fail;
187         }
188         dev->seq = seq;
189
190         if (dev->parent && dev->parent->driver->child_pre_probe) {
191                 ret = dev->parent->driver->child_pre_probe(dev);
192                 if (ret)
193                         goto fail;
194         }
195
196         if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
197                 ret = drv->ofdata_to_platdata(dev);
198                 if (ret)
199                         goto fail;
200         }
201
202         if (drv->probe) {
203                 ret = drv->probe(dev);
204                 if (ret)
205                         goto fail;
206         }
207
208         dev->flags |= DM_FLAG_ACTIVATED;
209
210         ret = uclass_post_probe_device(dev);
211         if (ret) {
212                 dev->flags &= ~DM_FLAG_ACTIVATED;
213                 goto fail_uclass;
214         }
215
216         return 0;
217 fail_uclass:
218         if (device_remove(dev)) {
219                 dm_warn("%s: Device '%s' failed to remove on error path\n",
220                         __func__, dev->name);
221         }
222 fail:
223         dev->seq = -1;
224         device_free(dev);
225
226         return ret;
227 }
228
229 int device_probe(struct udevice *dev)
230 {
231         return device_probe_child(dev, NULL);
232 }
233
234 void *dev_get_platdata(struct udevice *dev)
235 {
236         if (!dev) {
237                 dm_warn("%s: null device", __func__);
238                 return NULL;
239         }
240
241         return dev->platdata;
242 }
243
244 void *dev_get_priv(struct udevice *dev)
245 {
246         if (!dev) {
247                 dm_warn("%s: null device", __func__);
248                 return NULL;
249         }
250
251         return dev->priv;
252 }
253
254 void *dev_get_parentdata(struct udevice *dev)
255 {
256         if (!dev) {
257                 dm_warn("%s: null device", __func__);
258                 return NULL;
259         }
260
261         return dev->parent_priv;
262 }
263
264 static int device_get_device_tail(struct udevice *dev, int ret,
265                                   struct udevice **devp)
266 {
267         if (ret)
268                 return ret;
269
270         ret = device_probe(dev);
271         if (ret)
272                 return ret;
273
274         *devp = dev;
275
276         return 0;
277 }
278
279 int device_get_child(struct udevice *parent, int index, struct udevice **devp)
280 {
281         struct udevice *dev;
282
283         list_for_each_entry(dev, &parent->child_head, sibling_node) {
284                 if (!index--)
285                         return device_get_device_tail(dev, 0, devp);
286         }
287
288         return -ENODEV;
289 }
290
291 int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
292                              bool find_req_seq, struct udevice **devp)
293 {
294         struct udevice *dev;
295
296         *devp = NULL;
297         if (seq_or_req_seq == -1)
298                 return -ENODEV;
299
300         list_for_each_entry(dev, &parent->child_head, sibling_node) {
301                 if ((find_req_seq ? dev->req_seq : dev->seq) ==
302                                 seq_or_req_seq) {
303                         *devp = dev;
304                         return 0;
305                 }
306         }
307
308         return -ENODEV;
309 }
310
311 int device_get_child_by_seq(struct udevice *parent, int seq,
312                             struct udevice **devp)
313 {
314         struct udevice *dev;
315         int ret;
316
317         *devp = NULL;
318         ret = device_find_child_by_seq(parent, seq, false, &dev);
319         if (ret == -ENODEV) {
320                 /*
321                  * We didn't find it in probed devices. See if there is one
322                  * that will request this seq if probed.
323                  */
324                 ret = device_find_child_by_seq(parent, seq, true, &dev);
325         }
326         return device_get_device_tail(dev, ret, devp);
327 }
328
329 int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
330                                    struct udevice **devp)
331 {
332         struct udevice *dev;
333
334         *devp = NULL;
335
336         list_for_each_entry(dev, &parent->child_head, sibling_node) {
337                 if (dev->of_offset == of_offset) {
338                         *devp = dev;
339                         return 0;
340                 }
341         }
342
343         return -ENODEV;
344 }
345
346 int device_get_child_by_of_offset(struct udevice *parent, int seq,
347                                   struct udevice **devp)
348 {
349         struct udevice *dev;
350         int ret;
351
352         *devp = NULL;
353         ret = device_find_child_by_of_offset(parent, seq, &dev);
354         return device_get_device_tail(dev, ret, devp);
355 }
356
357 int device_find_first_child(struct udevice *parent, struct udevice **devp)
358 {
359         if (list_empty(&parent->child_head)) {
360                 *devp = NULL;
361         } else {
362                 *devp = list_first_entry(&parent->child_head, struct udevice,
363                                          sibling_node);
364         }
365
366         return 0;
367 }
368
369 int device_find_next_child(struct udevice **devp)
370 {
371         struct udevice *dev = *devp;
372         struct udevice *parent = dev->parent;
373
374         if (list_is_last(&dev->sibling_node, &parent->child_head)) {
375                 *devp = NULL;
376         } else {
377                 *devp = list_entry(dev->sibling_node.next, struct udevice,
378                                    sibling_node);
379         }
380
381         return 0;
382 }
383
384 struct udevice *dev_get_parent(struct udevice *child)
385 {
386         return child->parent;
387 }
388
389 ulong dev_get_of_data(struct udevice *dev)
390 {
391         return dev->of_id->data;
392 }