blob: 366cffed89dc83693c3e3a07939fde4d5d318199 [file] [log] [blame]
Simon Glassdd6ab882014-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 Glassdb6f0202014-07-23 06:55:12 -060013#include <fdtdec.h>
Simon Glassdd6ab882014-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 Glassdb6f0202014-07-23 06:55:12 -060025DECLARE_GLOBAL_DATA_PTR;
26
Heiko Schocherb74fcb42014-05-22 12:43:05 +020027int device_bind(struct udevice *parent, struct driver *drv, const char *name,
28 void *platdata, int of_offset, struct udevice **devp)
Simon Glassdd6ab882014-02-26 15:59:18 -070029{
Heiko Schocherb74fcb42014-05-22 12:43:05 +020030 struct udevice *dev;
Simon Glassdd6ab882014-02-26 15:59:18 -070031 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
Heiko Schocherb74fcb42014-05-22 12:43:05 +020042 dev = calloc(1, sizeof(struct udevice));
Simon Glassdd6ab882014-02-26 15:59:18 -070043 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;
Simon Glassdb6f0202014-07-23 06:55:12 -060055
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 */
Simon Glassdb6f0202014-07-23 06:55:12 -060063 dev->seq = -1;
Simon Glassc2ac1412014-09-17 09:02:38 -060064#ifdef CONFIG_OF_CONTROL
65 dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
Robert Baldyga2e9edbf2014-09-18 17:13:07 +020066 if (!IS_ERR_VALUE(dev->req_seq))
67 dev->req_seq &= INT_MAX;
Simon Glassdb6f0202014-07-23 06:55:12 -060068 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 }
Simon Glassc2ac1412014-09-17 09:02:38 -060072#else
73 dev->req_seq = -1;
74#endif
Simon Glassba750492015-01-25 08:27:00 -070075 if (!dev->platdata && drv->platdata_auto_alloc_size) {
Simon Glassdd6ab882014-02-26 15:59:18 -070076 dev->flags |= DM_FLAG_ALLOC_PDATA;
Simon Glassba750492015-01-25 08:27:00 -070077 dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
78 if (!dev->platdata) {
79 ret = -ENOMEM;
80 goto fail_alloc1;
81 }
82 }
Simon Glassdd6ab882014-02-26 15:59:18 -070083
84 /* put dev into parent's successor list */
85 if (parent)
86 list_add_tail(&dev->sibling_node, &parent->child_head);
87
88 ret = uclass_bind_device(dev);
89 if (ret)
Simon Glass4ebe01b2015-01-25 08:26:59 -070090 goto fail_uclass_bind;
Simon Glassdd6ab882014-02-26 15:59:18 -070091
92 /* if we fail to bind we remove device from successors and free it */
93 if (drv->bind) {
94 ret = drv->bind(dev);
Simon Glass4ebe01b2015-01-25 08:26:59 -070095 if (ret)
Simon Glassdd6ab882014-02-26 15:59:18 -070096 goto fail_bind;
Simon Glassdd6ab882014-02-26 15:59:18 -070097 }
98 if (parent)
99 dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
100 *devp = dev;
101
102 return 0;
103
104fail_bind:
Simon Glass4ebe01b2015-01-25 08:26:59 -0700105 if (uclass_unbind_device(dev)) {
106 dm_warn("Failed to unbind dev '%s' on error path\n",
107 dev->name);
108 }
109fail_uclass_bind:
110 if (parent)
111 list_del(&dev->sibling_node);
Simon Glassba750492015-01-25 08:27:00 -0700112 if (dev->flags & DM_FLAG_ALLOC_PDATA) {
113 free(dev->platdata);
114 dev->platdata = NULL;
115 }
116fail_alloc1:
Simon Glassdd6ab882014-02-26 15:59:18 -0700117 free(dev);
Simon Glass4ebe01b2015-01-25 08:26:59 -0700118
Simon Glassdd6ab882014-02-26 15:59:18 -0700119 return ret;
120}
121
Simon Glassfef72b72014-07-23 06:55:03 -0600122int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
123 const struct driver_info *info, struct udevice **devp)
Simon Glassdd6ab882014-02-26 15:59:18 -0700124{
125 struct driver *drv;
126
127 drv = lists_driver_lookup_name(info->name);
128 if (!drv)
129 return -ENOENT;
Simon Glassfef72b72014-07-23 06:55:03 -0600130 if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
131 return -EPERM;
Simon Glassdd6ab882014-02-26 15:59:18 -0700132
133 return device_bind(parent, drv, info->name, (void *)info->platdata,
134 -1, devp);
135}
136
Simon Glass1586a842014-10-13 23:41:50 -0600137int device_probe_child(struct udevice *dev, void *parent_priv)
Simon Glassdd6ab882014-02-26 15:59:18 -0700138{
139 struct driver *drv;
140 int size = 0;
141 int ret;
Simon Glassdb6f0202014-07-23 06:55:12 -0600142 int seq;
Simon Glassdd6ab882014-02-26 15:59:18 -0700143
144 if (!dev)
145 return -EINVAL;
146
147 if (dev->flags & DM_FLAG_ACTIVATED)
148 return 0;
149
150 drv = dev->driver;
151 assert(drv);
152
Simon Glassba750492015-01-25 08:27:00 -0700153 /* Allocate private data if requested */
Simon Glassdd6ab882014-02-26 15:59:18 -0700154 if (drv->priv_auto_alloc_size) {
155 dev->priv = calloc(1, drv->priv_auto_alloc_size);
156 if (!dev->priv) {
157 ret = -ENOMEM;
158 goto fail;
159 }
160 }
161 /* Allocate private data if requested */
Simon Glassdd6ab882014-02-26 15:59:18 -0700162 size = dev->uclass->uc_drv->per_device_auto_alloc_size;
163 if (size) {
164 dev->uclass_priv = calloc(1, size);
165 if (!dev->uclass_priv) {
166 ret = -ENOMEM;
167 goto fail;
168 }
169 }
170
171 /* Ensure all parents are probed */
172 if (dev->parent) {
Simon Glass60d971b2014-07-23 06:55:20 -0600173 size = dev->parent->driver->per_child_auto_alloc_size;
174 if (size) {
175 dev->parent_priv = calloc(1, size);
176 if (!dev->parent_priv) {
177 ret = -ENOMEM;
178 goto fail;
179 }
Simon Glass1586a842014-10-13 23:41:50 -0600180 if (parent_priv)
181 memcpy(dev->parent_priv, parent_priv, size);
Simon Glass60d971b2014-07-23 06:55:20 -0600182 }
183
Simon Glassdd6ab882014-02-26 15:59:18 -0700184 ret = device_probe(dev->parent);
185 if (ret)
186 goto fail;
187 }
Simon Glassdb6f0202014-07-23 06:55:12 -0600188
189 seq = uclass_resolve_seq(dev);
190 if (seq < 0) {
191 ret = seq;
192 goto fail;
193 }
194 dev->seq = seq;
Simon Glassdd6ab882014-02-26 15:59:18 -0700195
Simon Glassd45560d2014-07-23 06:55:21 -0600196 if (dev->parent && dev->parent->driver->child_pre_probe) {
197 ret = dev->parent->driver->child_pre_probe(dev);
198 if (ret)
199 goto fail;
200 }
201
Simon Glassdd6ab882014-02-26 15:59:18 -0700202 if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
203 ret = drv->ofdata_to_platdata(dev);
204 if (ret)
205 goto fail;
206 }
207
208 if (drv->probe) {
209 ret = drv->probe(dev);
210 if (ret)
211 goto fail;
212 }
213
214 dev->flags |= DM_FLAG_ACTIVATED;
215
216 ret = uclass_post_probe_device(dev);
217 if (ret) {
218 dev->flags &= ~DM_FLAG_ACTIVATED;
219 goto fail_uclass;
220 }
221
222 return 0;
223fail_uclass:
224 if (device_remove(dev)) {
225 dm_warn("%s: Device '%s' failed to remove on error path\n",
226 __func__, dev->name);
227 }
228fail:
Simon Glassdb6f0202014-07-23 06:55:12 -0600229 dev->seq = -1;
Simon Glassdd6ab882014-02-26 15:59:18 -0700230 device_free(dev);
231
232 return ret;
233}
234
Simon Glass1586a842014-10-13 23:41:50 -0600235int device_probe(struct udevice *dev)
236{
237 return device_probe_child(dev, NULL);
238}
239
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200240void *dev_get_platdata(struct udevice *dev)
Simon Glassdd6ab882014-02-26 15:59:18 -0700241{
242 if (!dev) {
Simon Glassdf1e0722014-12-10 08:55:56 -0700243 dm_warn("%s: null device\n", __func__);
Simon Glassdd6ab882014-02-26 15:59:18 -0700244 return NULL;
245 }
246
247 return dev->platdata;
248}
249
Heiko Schocherb74fcb42014-05-22 12:43:05 +0200250void *dev_get_priv(struct udevice *dev)
Simon Glassdd6ab882014-02-26 15:59:18 -0700251{
252 if (!dev) {
Simon Glassdf1e0722014-12-10 08:55:56 -0700253 dm_warn("%s: null device\n", __func__);
Simon Glassdd6ab882014-02-26 15:59:18 -0700254 return NULL;
255 }
256
257 return dev->priv;
258}
Simon Glass48d4e292014-07-23 06:55:19 -0600259
Simon Glass60d971b2014-07-23 06:55:20 -0600260void *dev_get_parentdata(struct udevice *dev)
261{
262 if (!dev) {
Simon Glassdf1e0722014-12-10 08:55:56 -0700263 dm_warn("%s: null device\n", __func__);
Simon Glass60d971b2014-07-23 06:55:20 -0600264 return NULL;
265 }
266
267 return dev->parent_priv;
268}
269
Simon Glass48d4e292014-07-23 06:55:19 -0600270static int device_get_device_tail(struct udevice *dev, int ret,
271 struct udevice **devp)
272{
273 if (ret)
274 return ret;
275
276 ret = device_probe(dev);
277 if (ret)
278 return ret;
279
280 *devp = dev;
281
282 return 0;
283}
284
285int device_get_child(struct udevice *parent, int index, struct udevice **devp)
286{
287 struct udevice *dev;
288
289 list_for_each_entry(dev, &parent->child_head, sibling_node) {
290 if (!index--)
291 return device_get_device_tail(dev, 0, devp);
292 }
293
294 return -ENODEV;
295}
296
297int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
298 bool find_req_seq, struct udevice **devp)
299{
300 struct udevice *dev;
301
302 *devp = NULL;
303 if (seq_or_req_seq == -1)
304 return -ENODEV;
305
306 list_for_each_entry(dev, &parent->child_head, sibling_node) {
307 if ((find_req_seq ? dev->req_seq : dev->seq) ==
308 seq_or_req_seq) {
309 *devp = dev;
310 return 0;
311 }
312 }
313
314 return -ENODEV;
315}
316
317int device_get_child_by_seq(struct udevice *parent, int seq,
318 struct udevice **devp)
319{
320 struct udevice *dev;
321 int ret;
322
323 *devp = NULL;
324 ret = device_find_child_by_seq(parent, seq, false, &dev);
325 if (ret == -ENODEV) {
326 /*
327 * We didn't find it in probed devices. See if there is one
328 * that will request this seq if probed.
329 */
330 ret = device_find_child_by_seq(parent, seq, true, &dev);
331 }
332 return device_get_device_tail(dev, ret, devp);
333}
334
335int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
336 struct udevice **devp)
337{
338 struct udevice *dev;
339
340 *devp = NULL;
341
342 list_for_each_entry(dev, &parent->child_head, sibling_node) {
343 if (dev->of_offset == of_offset) {
344 *devp = dev;
345 return 0;
346 }
347 }
348
349 return -ENODEV;
350}
351
352int device_get_child_by_of_offset(struct udevice *parent, int seq,
353 struct udevice **devp)
354{
355 struct udevice *dev;
356 int ret;
357
358 *devp = NULL;
359 ret = device_find_child_by_of_offset(parent, seq, &dev);
360 return device_get_device_tail(dev, ret, devp);
361}
Simon Glass44da7352014-10-13 23:41:49 -0600362
363int device_find_first_child(struct udevice *parent, struct udevice **devp)
364{
365 if (list_empty(&parent->child_head)) {
366 *devp = NULL;
367 } else {
368 *devp = list_first_entry(&parent->child_head, struct udevice,
369 sibling_node);
370 }
371
372 return 0;
373}
374
375int device_find_next_child(struct udevice **devp)
376{
377 struct udevice *dev = *devp;
378 struct udevice *parent = dev->parent;
379
380 if (list_is_last(&dev->sibling_node, &parent->child_head)) {
381 *devp = NULL;
382 } else {
383 *devp = list_entry(dev->sibling_node.next, struct udevice,
384 sibling_node);
385 }
386
387 return 0;
388}
Simon Glass70c3a0e2014-11-11 10:46:18 -0700389
Simon Glass43f488a2014-11-11 10:46:19 -0700390struct udevice *dev_get_parent(struct udevice *child)
391{
392 return child->parent;
393}
394
Simon Glass70c3a0e2014-11-11 10:46:18 -0700395ulong dev_get_of_data(struct udevice *dev)
396{
397 return dev->of_id->data;
398}