Blame view
drivers/core/device.c
18.5 KB
83d290c56 SPDX: Convert all... |
1 |
// SPDX-License-Identifier: GPL-2.0+ |
6494d708b dm: Add base driv... |
2 3 4 5 6 7 8 |
/* * Device manager * * Copyright (c) 2013 Google, Inc * * (C) Copyright 2012 * Pavel Herrmann <morpheus.ibis@gmail.com> |
6494d708b dm: Add base driv... |
9 10 11 |
*/ #include <common.h> |
7c6168625 dm: core: impleme... |
12 |
#include <asm/io.h> |
f4fcba5c5 clk: implement cl... |
13 |
#include <clk.h> |
5a66a8ff8 dm: Introduce dev... |
14 |
#include <fdtdec.h> |
ef5cd3306 dm: core: Enable ... |
15 |
#include <fdt_support.h> |
6494d708b dm: Add base driv... |
16 17 18 19 |
#include <malloc.h> #include <dm/device.h> #include <dm/device-internal.h> #include <dm/lists.h> |
29d11b883 core: Make device... |
20 |
#include <dm/of_access.h> |
d90a5a30d pinctrl: add pin ... |
21 |
#include <dm/pinctrl.h> |
6494d708b dm: Add base driv... |
22 |
#include <dm/platdata.h> |
396e343b3 dm: core: Allow b... |
23 |
#include <dm/read.h> |
6494d708b dm: Add base driv... |
24 25 26 27 28 |
#include <dm/uclass.h> #include <dm/uclass-internal.h> #include <dm/util.h> #include <linux/err.h> #include <linux/list.h> |
3ad307784 dm: core: device:... |
29 |
#include <power-domain.h> |
6494d708b dm: Add base driv... |
30 |
|
5a66a8ff8 dm: Introduce dev... |
31 |
DECLARE_GLOBAL_DATA_PTR; |
daac3bfee dm: allow setting... |
32 33 |
static int device_bind_common(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, |
7a61b0b58 dm: core: Adjust ... |
34 |
ulong driver_data, ofnode node, |
9fa281900 dm: core: Expand ... |
35 |
uint of_platdata_size, struct udevice **devp) |
6494d708b dm: Add base driv... |
36 |
{ |
54c5d08a0 dm: rename device... |
37 |
struct udevice *dev; |
6494d708b dm: Add base driv... |
38 |
struct uclass *uc; |
5eaed8802 dm: core: Extend ... |
39 |
int size, ret = 0; |
6494d708b dm: Add base driv... |
40 |
|
e6cabe4a6 dm: core: allow d... |
41 42 |
if (devp) *devp = NULL; |
6494d708b dm: Add base driv... |
43 44 45 46 |
if (!name) return -EINVAL; ret = uclass_get(drv->id, &uc); |
3346c8762 dm: Improve handl... |
47 48 49 |
if (ret) { debug("Missing uclass for driver %s ", drv->name); |
6494d708b dm: Add base driv... |
50 |
return ret; |
3346c8762 dm: Improve handl... |
51 |
} |
6494d708b dm: Add base driv... |
52 |
|
54c5d08a0 dm: rename device... |
53 |
dev = calloc(1, sizeof(struct udevice)); |
6494d708b dm: Add base driv... |
54 55 56 57 58 59 |
if (!dev) return -ENOMEM; INIT_LIST_HEAD(&dev->sibling_node); INIT_LIST_HEAD(&dev->child_head); INIT_LIST_HEAD(&dev->uclass_node); |
e2282d707 devres: make Devr... |
60 |
#ifdef CONFIG_DEVRES |
608f26c51 devres: introduce... |
61 |
INIT_LIST_HEAD(&dev->devres_head); |
e2282d707 devres: make Devr... |
62 |
#endif |
6494d708b dm: Add base driv... |
63 |
dev->platdata = platdata; |
daac3bfee dm: allow setting... |
64 |
dev->driver_data = driver_data; |
6494d708b dm: Add base driv... |
65 |
dev->name = name; |
7a61b0b58 dm: core: Adjust ... |
66 |
dev->node = node; |
6494d708b dm: Add base driv... |
67 68 69 |
dev->parent = parent; dev->driver = drv; dev->uclass = uc; |
5a66a8ff8 dm: Introduce dev... |
70 |
|
5a66a8ff8 dm: Introduce dev... |
71 |
dev->seq = -1; |
9cc36a2b8 dm: core: Add a f... |
72 |
dev->req_seq = -1; |
3542ff29e dm: device: Allow... |
73 74 |
if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) && (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) { |
36fa61dc6 dm: core: Allow s... |
75 |
/* |
770eb30ed dm: device.c: Min... |
76 77 78 79 80 81 |
* Some devices, such as a SPI bus, I2C bus and serial ports * are numbered using aliases. * * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ |
3542ff29e dm: device: Allow... |
82 83 |
if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) |
396e343b3 dm: core: Allow b... |
84 |
dev_read_alias_seq(dev, &dev->req_seq); |
3542ff29e dm: device: Allow... |
85 86 |
} else { dev->req_seq = uclass_find_next_free_req_seq(drv->id); |
9cc36a2b8 dm: core: Add a f... |
87 |
} |
5a66a8ff8 dm: Introduce dev... |
88 |
} |
36fa61dc6 dm: core: Allow s... |
89 |
|
9fa281900 dm: core: Expand ... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
if (drv->platdata_auto_alloc_size) { bool alloc = !platdata; if (CONFIG_IS_ENABLED(OF_PLATDATA)) { if (of_platdata_size) { dev->flags |= DM_FLAG_OF_PLATDATA; if (of_platdata_size < drv->platdata_auto_alloc_size) alloc = true; } } if (alloc) { dev->flags |= DM_FLAG_ALLOC_PDATA; dev->platdata = calloc(1, drv->platdata_auto_alloc_size); if (!dev->platdata) { ret = -ENOMEM; goto fail_alloc1; } if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) { memcpy(dev->platdata, platdata, of_platdata_size); } |
f8a85449e dm: core: Allocat... |
113 114 |
} } |
cdc133bde dm: core: Allow p... |
115 |
|
5eaed8802 dm: core: Extend ... |
116 117 118 119 120 121 122 123 124 125 126 127 |
size = uc->uc_drv->per_device_platdata_auto_alloc_size; if (size) { dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA; dev->uclass_platdata = calloc(1, size); if (!dev->uclass_platdata) { ret = -ENOMEM; goto fail_alloc2; } } if (parent) { size = parent->driver->per_child_platdata_auto_alloc_size; |
ba8da9dc4 dm: core: Allow u... |
128 129 130 131 |
if (!size) { size = parent->uclass->uc_drv-> per_child_platdata_auto_alloc_size; } |
cdc133bde dm: core: Allow p... |
132 133 134 135 136 |
if (size) { dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA; dev->parent_platdata = calloc(1, size); if (!dev->parent_platdata) { ret = -ENOMEM; |
5eaed8802 dm: core: Extend ... |
137 |
goto fail_alloc3; |
cdc133bde dm: core: Allow p... |
138 139 140 |
} } } |
6494d708b dm: Add base driv... |
141 142 143 144 145 146 147 |
/* put dev into parent's successor list */ if (parent) list_add_tail(&dev->sibling_node, &parent->child_head); ret = uclass_bind_device(dev); if (ret) |
72ebfe86f dm: core: Tidy up... |
148 |
goto fail_uclass_bind; |
6494d708b dm: Add base driv... |
149 150 151 152 |
/* if we fail to bind we remove device from successors and free it */ if (drv->bind) { ret = drv->bind(dev); |
72ebfe86f dm: core: Tidy up... |
153 |
if (ret) |
6494d708b dm: Add base driv... |
154 |
goto fail_bind; |
6494d708b dm: Add base driv... |
155 |
} |
0118ce795 dm: core: Add a p... |
156 157 158 159 160 |
if (parent && parent->driver->child_post_bind) { ret = parent->driver->child_post_bind(dev); if (ret) goto fail_child_post_bind; } |
20af3c0a0 dm: core: Call uc... |
161 162 163 164 165 |
if (uc->uc_drv->post_bind) { ret = uc->uc_drv->post_bind(dev); if (ret) goto fail_uclass_post_bind; } |
0118ce795 dm: core: Add a p... |
166 |
|
6494d708b dm: Add base driv... |
167 |
if (parent) |
ceb919096 dm: replace dm_db... |
168 169 |
pr_debug("Bound device %s to %s ", dev->name, parent->name); |
e6cabe4a6 dm: core: allow d... |
170 171 |
if (devp) *devp = dev; |
6494d708b dm: Add base driv... |
172 |
|
aed1a4dd8 dm: add DM_FLAG_B... |
173 |
dev->flags |= DM_FLAG_BOUND; |
6494d708b dm: Add base driv... |
174 |
return 0; |
20af3c0a0 dm: core: Call uc... |
175 176 |
fail_uclass_post_bind: /* There is no child unbind() method, so no clean-up required */ |
0118ce795 dm: core: Add a p... |
177 |
fail_child_post_bind: |
0a5804b53 dm: drop CONFIG_D... |
178 |
if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) { |
5a87c4174 dm: core: Drop de... |
179 180 181 182 183 |
if (drv->unbind && drv->unbind(dev)) { dm_warn("unbind() method failed on dev '%s' on error path ", dev->name); } |
0118ce795 dm: core: Add a p... |
184 |
} |
6494d708b dm: Add base driv... |
185 |
fail_bind: |
0a5804b53 dm: drop CONFIG_D... |
186 |
if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) { |
5a87c4174 dm: core: Drop de... |
187 188 189 190 191 |
if (uclass_unbind_device(dev)) { dm_warn("Failed to unbind dev '%s' on error path ", dev->name); } |
72ebfe86f dm: core: Tidy up... |
192 193 |
} fail_uclass_bind: |
0a5804b53 dm: drop CONFIG_D... |
194 |
if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) { |
5a87c4174 dm: core: Drop de... |
195 196 197 198 199 |
list_del(&dev->sibling_node); if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) { free(dev->parent_platdata); dev->parent_platdata = NULL; } |
cdc133bde dm: core: Allow p... |
200 |
} |
5eaed8802 dm: core: Extend ... |
201 202 203 204 205 |
fail_alloc3: if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) { free(dev->uclass_platdata); dev->uclass_platdata = NULL; } |
cdc133bde dm: core: Allow p... |
206 |
fail_alloc2: |
f8a85449e dm: core: Allocat... |
207 208 209 210 211 |
if (dev->flags & DM_FLAG_ALLOC_PDATA) { free(dev->platdata); dev->platdata = NULL; } fail_alloc1: |
608f26c51 devres: introduce... |
212 |
devres_release_all(dev); |
6494d708b dm: Add base driv... |
213 |
free(dev); |
72ebfe86f dm: core: Tidy up... |
214 |
|
6494d708b dm: Add base driv... |
215 216 |
return ret; } |
daac3bfee dm: allow setting... |
217 218 |
int device_bind_with_driver_data(struct udevice *parent, const struct driver *drv, const char *name, |
396e343b3 dm: core: Allow b... |
219 |
ulong driver_data, ofnode node, |
daac3bfee dm: allow setting... |
220 221 |
struct udevice **devp) { |
396e343b3 dm: core: Allow b... |
222 223 |
return device_bind_common(parent, drv, name, NULL, driver_data, node, 0, devp); |
daac3bfee dm: allow setting... |
224 225 226 227 228 229 |
} int device_bind(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp) { |
7a61b0b58 dm: core: Adjust ... |
230 231 |
return device_bind_common(parent, drv, name, platdata, 0, offset_to_ofnode(of_offset), 0, devp); |
daac3bfee dm: allow setting... |
232 |
} |
d677b00cb dm: core: Add a w... |
233 234 235 236 237 238 239 |
int device_bind_ofnode(struct udevice *parent, const struct driver *drv, const char *name, void *platdata, ofnode node, struct udevice **devp) { return device_bind_common(parent, drv, name, platdata, 0, node, 0, devp); } |
00606d7e3 dm: Allow drivers... |
240 241 |
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, const struct driver_info *info, struct udevice **devp) |
6494d708b dm: Add base driv... |
242 243 |
{ struct driver *drv; |
9fa281900 dm: core: Expand ... |
244 |
uint platdata_size = 0; |
6494d708b dm: Add base driv... |
245 246 247 248 |
drv = lists_driver_lookup_name(info->name); if (!drv) return -ENOENT; |
00606d7e3 dm: Allow drivers... |
249 250 |
if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC)) return -EPERM; |
6494d708b dm: Add base driv... |
251 |
|
9fa281900 dm: core: Expand ... |
252 253 254 255 |
#if CONFIG_IS_ENABLED(OF_PLATDATA) platdata_size = info->platdata_size; #endif return device_bind_common(parent, drv, info->name, |
396e343b3 dm: core: Allow b... |
256 257 |
(void *)info->platdata, 0, ofnode_null(), platdata_size, devp); |
6494d708b dm: Add base driv... |
258 |
} |
2c03c4633 dm: core: Support... |
259 260 261 262 263 |
static void *alloc_priv(int size, uint flags) { void *priv; if (flags & DM_FLAG_ALLOC_PRIV_DMA) { |
5924da1df dm: core: Round u... |
264 |
size = ROUND(size, ARCH_DMA_MINALIGN); |
2c03c4633 dm: core: Support... |
265 |
priv = memalign(ARCH_DMA_MINALIGN, size); |
5a8a8045a dm: core: Ensure ... |
266 |
if (priv) { |
2c03c4633 dm: core: Support... |
267 |
memset(priv, '\0', size); |
5a8a8045a dm: core: Ensure ... |
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
/* * Ensure that the zero bytes are flushed to memory. * This prevents problems if the driver uses this as * both an input and an output buffer: * * 1. Zeroes written to buffer (here) and sit in the * cache * 2. Driver issues a read command to DMA * 3. CPU runs out of cache space and evicts some cache * data in the buffer, writing zeroes to RAM from * the memset() above * 4. DMA completes * 5. Buffer now has some DMA data and some zeroes * 6. Data being read is now incorrect * * To prevent this, ensure that the cache is clean * within this range at the start. The driver can then * use normal flush-after-write, invalidate-before-read * procedures. * * TODO(sjg@chromium.org): Drop this microblaze * exception. */ #ifndef CONFIG_MICROBLAZE flush_dcache_range((ulong)priv, (ulong)priv + size); #endif } |
2c03c4633 dm: core: Support... |
296 297 298 299 300 301 |
} else { priv = calloc(1, size); } return priv; } |
c6db965f6 dm: Remove device... |
302 |
int device_probe(struct udevice *dev) |
6494d708b dm: Add base driv... |
303 |
{ |
3ad307784 dm: core: device:... |
304 |
struct power_domain pd; |
3479253da dm: core: Convert... |
305 |
const struct driver *drv; |
6494d708b dm: Add base driv... |
306 307 |
int size = 0; int ret; |
5a66a8ff8 dm: Introduce dev... |
308 |
int seq; |
6494d708b dm: Add base driv... |
309 310 311 312 313 314 315 316 317 |
if (!dev) return -EINVAL; if (dev->flags & DM_FLAG_ACTIVATED) return 0; drv = dev->driver; assert(drv); |
cdeb2ba99 dm: core: Fix cod... |
318 319 |
/* Allocate private data if requested and not reentered */ if (drv->priv_auto_alloc_size && !dev->priv) { |
2c03c4633 dm: core: Support... |
320 |
dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags); |
6494d708b dm: Add base driv... |
321 322 323 324 325 |
if (!dev->priv) { ret = -ENOMEM; goto fail; } } |
cdeb2ba99 dm: core: Fix cod... |
326 |
/* Allocate private data if requested and not reentered */ |
6494d708b dm: Add base driv... |
327 |
size = dev->uclass->uc_drv->per_device_auto_alloc_size; |
cdeb2ba99 dm: core: Fix cod... |
328 |
if (size && !dev->uclass_priv) { |
c7a3accc3 dm: core: Alloc u... |
329 330 |
dev->uclass_priv = alloc_priv(size, dev->uclass->uc_drv->flags); |
6494d708b dm: Add base driv... |
331 332 333 334 335 336 337 338 |
if (!dev->uclass_priv) { ret = -ENOMEM; goto fail; } } /* Ensure all parents are probed */ if (dev->parent) { |
e59f458de dm: Introduce per... |
339 |
size = dev->parent->driver->per_child_auto_alloc_size; |
dac8db2ce dm: core: Allow u... |
340 341 342 343 |
if (!size) { size = dev->parent->uclass->uc_drv-> per_child_auto_alloc_size; } |
cdeb2ba99 dm: core: Fix cod... |
344 |
if (size && !dev->parent_priv) { |
2c03c4633 dm: core: Support... |
345 |
dev->parent_priv = alloc_priv(size, drv->flags); |
e59f458de dm: Introduce per... |
346 347 348 349 350 |
if (!dev->parent_priv) { ret = -ENOMEM; goto fail; } } |
6494d708b dm: Add base driv... |
351 352 353 |
ret = device_probe(dev->parent); if (ret) goto fail; |
cdeb2ba99 dm: core: Fix cod... |
354 355 356 357 358 359 360 361 362 |
/* * The device might have already been probed during * the call to device_probe() on its parent device * (e.g. PCI bridge devices). Test the flags again * so that we don't mess up the device. */ if (dev->flags & DM_FLAG_ACTIVATED) return 0; |
6494d708b dm: Add base driv... |
363 |
} |
5a66a8ff8 dm: Introduce dev... |
364 365 366 367 368 369 |
seq = uclass_resolve_seq(dev); if (seq < 0) { ret = seq; goto fail; } dev->seq = seq; |
206d4d2b4 dm: core: Mark de... |
370 |
dev->flags |= DM_FLAG_ACTIVATED; |
84d26e296 dm: core: Don't u... |
371 372 |
/* * Process pinctrl for everything except the root device, and |
0379597e5 dm: core: Don't s... |
373 374 375 |
* continue regardless of the result of pinctrl. Don't process pinctrl * settings for pinctrl devices since the device may not yet be * probed. |
84d26e296 dm: core: Don't u... |
376 |
*/ |
0379597e5 dm: core: Don't s... |
377 |
if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) |
84d26e296 dm: core: Don't u... |
378 |
pinctrl_select_state(dev, "default"); |
d90a5a30d pinctrl: add pin ... |
379 |
|
3ad307784 dm: core: device:... |
380 |
if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) { |
f958ee491 MLK-20945-2 dm: d... |
381 382 383 384 385 386 387 388 389 |
if (!power_domain_get(dev, &pd)) { if (!(dev->driver->flags & DM_FLAG_IGNORE_POWER_ON)) { ret = power_domain_on(&pd); if (ret) { power_domain_free(&pd); goto fail; } } } |
3ad307784 dm: core: device:... |
390 |
} |
02c07b374 dm: core: Add a u... |
391 |
ret = uclass_pre_probe_device(dev); |
83c7e434c dm: core: Allow u... |
392 393 |
if (ret) goto fail; |
a327dee0f dm: Add child_pre... |
394 395 396 397 398 |
if (dev->parent && dev->parent->driver->child_pre_probe) { ret = dev->parent->driver->child_pre_probe(dev); if (ret) goto fail; } |
396e343b3 dm: core: Allow b... |
399 |
if (drv->ofdata_to_platdata && dev_has_of_node(dev)) { |
6494d708b dm: Add base driv... |
400 401 402 403 |
ret = drv->ofdata_to_platdata(dev); if (ret) goto fail; } |
5dd4ff270 MLK-21850-1 dm: d... |
404 |
|
f4fcba5c5 clk: implement cl... |
405 |
/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ |
5dd4ff270 MLK-21850-1 dm: d... |
406 407 408 409 410 |
if (!(dev->driver->flags & DM_FLAG_IGNORE_DEFAULT_CLKS)) { ret = clk_set_defaults(dev); if (ret) goto fail; } |
f4fcba5c5 clk: implement cl... |
411 |
|
6494d708b dm: Add base driv... |
412 413 |
if (drv->probe) { ret = drv->probe(dev); |
02eeb1bbb dm: core: Mark de... |
414 415 |
if (ret) { dev->flags &= ~DM_FLAG_ACTIVATED; |
6494d708b dm: Add base driv... |
416 |
goto fail; |
02eeb1bbb dm: core: Mark de... |
417 |
} |
6494d708b dm: Add base driv... |
418 |
} |
6494d708b dm: Add base driv... |
419 |
ret = uclass_post_probe_device(dev); |
206d4d2b4 dm: core: Mark de... |
420 |
if (ret) |
6494d708b dm: Add base driv... |
421 |
goto fail_uclass; |
6494d708b dm: Add base driv... |
422 |
|
c3ab98536 dm: core: device:... |
423 424 |
if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL) pinctrl_select_state(dev, "default"); |
6494d708b dm: Add base driv... |
425 426 |
return 0; fail_uclass: |
706865afe dm: core: Add fla... |
427 |
if (device_remove(dev, DM_REMOVE_NORMAL)) { |
6494d708b dm: Add base driv... |
428 429 430 431 432 |
dm_warn("%s: Device '%s' failed to remove on error path ", __func__, dev->name); } fail: |
206d4d2b4 dm: core: Mark de... |
433 |
dev->flags &= ~DM_FLAG_ACTIVATED; |
5a66a8ff8 dm: Introduce dev... |
434 |
dev->seq = -1; |
6494d708b dm: Add base driv... |
435 436 437 438 |
device_free(dev); return ret; } |
9f15cc14b dm: core: Update ... |
439 |
void *dev_get_platdata(const struct udevice *dev) |
6494d708b dm: Add base driv... |
440 441 |
{ if (!dev) { |
964d153c0 dm: device: Add n... |
442 443 |
dm_warn("%s: null device ", __func__); |
6494d708b dm: Add base driv... |
444 445 446 447 448 |
return NULL; } return dev->platdata; } |
9f15cc14b dm: core: Update ... |
449 |
void *dev_get_parent_platdata(const struct udevice *dev) |
cdc133bde dm: core: Allow p... |
450 451 |
{ if (!dev) { |
36d7cc17b dm: core: Add \n ... |
452 453 |
dm_warn("%s: null device ", __func__); |
cdc133bde dm: core: Allow p... |
454 455 456 457 458 |
return NULL; } return dev->parent_platdata; } |
9f15cc14b dm: core: Update ... |
459 |
void *dev_get_uclass_platdata(const struct udevice *dev) |
5eaed8802 dm: core: Extend ... |
460 461 |
{ if (!dev) { |
36d7cc17b dm: core: Add \n ... |
462 463 |
dm_warn("%s: null device ", __func__); |
5eaed8802 dm: core: Extend ... |
464 465 466 467 468 |
return NULL; } return dev->uclass_platdata; } |
9f15cc14b dm: core: Update ... |
469 |
void *dev_get_priv(const struct udevice *dev) |
6494d708b dm: Add base driv... |
470 471 |
{ if (!dev) { |
964d153c0 dm: device: Add n... |
472 473 |
dm_warn("%s: null device ", __func__); |
6494d708b dm: Add base driv... |
474 475 476 477 478 |
return NULL; } return dev->priv; } |
997c87bb0 dm: Add functions... |
479 |
|
9f15cc14b dm: core: Update ... |
480 |
void *dev_get_uclass_priv(const struct udevice *dev) |
e564f054a dm: core: Add dev... |
481 482 483 484 485 486 487 488 489 |
{ if (!dev) { dm_warn("%s: null device ", __func__); return NULL; } return dev->uclass_priv; } |
9f15cc14b dm: core: Update ... |
490 |
void *dev_get_parent_priv(const struct udevice *dev) |
e59f458de dm: Introduce per... |
491 492 |
{ if (!dev) { |
964d153c0 dm: device: Add n... |
493 494 |
dm_warn("%s: null device ", __func__); |
e59f458de dm: Introduce per... |
495 496 497 498 499 |
return NULL; } return dev->parent_priv; } |
997c87bb0 dm: Add functions... |
500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
static int device_get_device_tail(struct udevice *dev, int ret, struct udevice **devp) { if (ret) return ret; ret = device_probe(dev); if (ret) return ret; *devp = dev; return 0; } |
e4c98a59d core: Add dev_{di... |
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
/** * device_find_by_ofnode() - Return device associated with given ofnode * * The returned device is *not* activated. * * @node: The ofnode for which a associated device should be looked up * @devp: Pointer to structure to hold the found device * Return: 0 if OK, -ve on error */ static int device_find_by_ofnode(ofnode node, struct udevice **devp) { struct uclass *uc; struct udevice *dev; int ret; list_for_each_entry(uc, &gd->uclass_root, sibling_node) { ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev); if (!ret || dev) { *devp = dev; return 0; } } return -ENODEV; } |
997c87bb0 dm: Add functions... |
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 |
int device_get_child(struct udevice *parent, int index, struct udevice **devp) { struct udevice *dev; list_for_each_entry(dev, &parent->child_head, sibling_node) { if (!index--) return device_get_device_tail(dev, 0, devp); } return -ENODEV; } int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq, bool find_req_seq, struct udevice **devp) { struct udevice *dev; *devp = NULL; if (seq_or_req_seq == -1) return -ENODEV; list_for_each_entry(dev, &parent->child_head, sibling_node) { if ((find_req_seq ? dev->req_seq : dev->seq) == seq_or_req_seq) { *devp = dev; return 0; } } return -ENODEV; } int device_get_child_by_seq(struct udevice *parent, int seq, struct udevice **devp) { struct udevice *dev; int ret; *devp = NULL; ret = device_find_child_by_seq(parent, seq, false, &dev); if (ret == -ENODEV) { /* * We didn't find it in probed devices. See if there is one * that will request this seq if probed. */ ret = device_find_child_by_seq(parent, seq, true, &dev); } return device_get_device_tail(dev, ret, devp); } int device_find_child_by_of_offset(struct udevice *parent, int of_offset, struct udevice **devp) { struct udevice *dev; *devp = NULL; list_for_each_entry(dev, &parent->child_head, sibling_node) { |
e160f7d43 dm: core: Replace... |
598 |
if (dev_of_offset(dev) == of_offset) { |
997c87bb0 dm: Add functions... |
599 600 601 602 603 604 605 |
*devp = dev; return 0; } } return -ENODEV; } |
132f9bfc9 dm: core: Correct... |
606 |
int device_get_child_by_of_offset(struct udevice *parent, int node, |
997c87bb0 dm: Add functions... |
607 608 609 610 611 612 |
struct udevice **devp) { struct udevice *dev; int ret; *devp = NULL; |
132f9bfc9 dm: core: Correct... |
613 |
ret = device_find_child_by_of_offset(parent, node, &dev); |
997c87bb0 dm: Add functions... |
614 615 |
return device_get_device_tail(dev, ret, devp); } |
a8981d4f8 dm: core: Add fun... |
616 |
|
7ec9181d6 dm: convert devic... |
617 618 |
static struct udevice *_device_find_global_by_ofnode(struct udevice *parent, ofnode ofnode) |
2693047ac dm: core: Add a f... |
619 620 |
{ struct udevice *dev, *found; |
7ec9181d6 dm: convert devic... |
621 |
if (ofnode_equal(dev_ofnode(parent), ofnode)) |
2693047ac dm: core: Add a f... |
622 623 624 |
return parent; list_for_each_entry(dev, &parent->child_head, sibling_node) { |
7ec9181d6 dm: convert devic... |
625 |
found = _device_find_global_by_ofnode(dev, ofnode); |
2693047ac dm: core: Add a f... |
626 627 628 629 630 631 |
if (found) return found; } return NULL; } |
7ec9181d6 dm: convert devic... |
632 633 634 635 636 637 638 639 |
int device_find_global_by_ofnode(ofnode ofnode, struct udevice **devp) { *devp = _device_find_global_by_ofnode(gd->dm_root, ofnode); return *devp ? 0 : -ENOENT; } int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp) |
2693047ac dm: core: Add a f... |
640 641 |
{ struct udevice *dev; |
7ec9181d6 dm: convert devic... |
642 |
dev = _device_find_global_by_ofnode(gd->dm_root, ofnode); |
2693047ac dm: core: Add a f... |
643 644 |
return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp); } |
a8981d4f8 dm: core: Add fun... |
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 |
int device_find_first_child(struct udevice *parent, struct udevice **devp) { if (list_empty(&parent->child_head)) { *devp = NULL; } else { *devp = list_first_entry(&parent->child_head, struct udevice, sibling_node); } return 0; } int device_find_next_child(struct udevice **devp) { struct udevice *dev = *devp; struct udevice *parent = dev->parent; if (list_is_last(&dev->sibling_node, &parent->child_head)) { *devp = NULL; } else { *devp = list_entry(dev->sibling_node.next, struct udevice, sibling_node); } return 0; } |
2ef249b44 dm: core: Allow a... |
671 |
|
cdb6aa0af dm: core: Add a f... |
672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 |
int device_find_first_inactive_child(struct udevice *parent, enum uclass_id uclass_id, struct udevice **devp) { struct udevice *dev; *devp = NULL; list_for_each_entry(dev, &parent->child_head, sibling_node) { if (!device_active(dev) && device_get_uclass_id(dev) == uclass_id) { *devp = dev; return 0; } } return -ENODEV; } |
3abe11153 dm: core: Add a f... |
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 |
int device_find_first_child_by_uclass(struct udevice *parent, enum uclass_id uclass_id, struct udevice **devp) { struct udevice *dev; *devp = NULL; list_for_each_entry(dev, &parent->child_head, sibling_node) { if (device_get_uclass_id(dev) == uclass_id) { *devp = dev; return 0; } } return -ENODEV; } int device_find_child_by_name(struct udevice *parent, const char *name, struct udevice **devp) { struct udevice *dev; *devp = NULL; list_for_each_entry(dev, &parent->child_head, sibling_node) { if (!strcmp(dev->name, name)) { *devp = dev; return 0; } } return -ENODEV; } |
9f15cc14b dm: core: Update ... |
722 |
struct udevice *dev_get_parent(const struct udevice *child) |
479728cb0 dm: core: Add fun... |
723 724 725 |
{ return child->parent; } |
9f15cc14b dm: core: Update ... |
726 |
ulong dev_get_driver_data(const struct udevice *dev) |
2ef249b44 dm: core: Allow a... |
727 |
{ |
39de84335 dm: core: Rename ... |
728 |
return dev->driver_data; |
2ef249b44 dm: core: Allow a... |
729 |
} |
b36705310 dm: core: Add a f... |
730 |
|
9f15cc14b dm: core: Update ... |
731 |
const void *dev_get_driver_ops(const struct udevice *dev) |
cc73d37b7 dm: core: device:... |
732 733 734 735 736 737 |
{ if (!dev || !dev->driver->ops) return NULL; return dev->driver->ops; } |
9f15cc14b dm: core: Update ... |
738 |
enum uclass_id device_get_uclass_id(const struct udevice *dev) |
b36705310 dm: core: Add a f... |
739 740 741 |
{ return dev->uclass->uc_drv->id; } |
c9cac3f84 dm: introduce dev... |
742 |
|
9f15cc14b dm: core: Update ... |
743 |
const char *dev_get_uclass_name(const struct udevice *dev) |
f9c370dcd dm: core: device:... |
744 745 746 747 748 749 |
{ if (!dev) return NULL; return dev->uclass->uc_drv->name; } |
9f15cc14b dm: core: Update ... |
750 |
bool device_has_children(const struct udevice *dev) |
c5785673b dm: core: Add dev... |
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 |
{ return !list_empty(&dev->child_head); } bool device_has_active_children(struct udevice *dev) { struct udevice *child; for (device_find_first_child(dev, &child); child; device_find_next_child(&child)) { if (device_active(child)) return true; } return false; } bool device_is_last_sibling(struct udevice *dev) { struct udevice *parent = dev->parent; if (!parent) return false; return list_is_last(&dev->sibling_node, &parent->child_head); } |
f5c67ea03 dm: core: Add a w... |
777 |
|
a2040facd dm: core: Allow d... |
778 779 |
void device_set_name_alloced(struct udevice *dev) { |
fd1c2d9b6 dm: core: Rename ... |
780 |
dev->flags |= DM_FLAG_NAME_ALLOCED; |
a2040facd dm: core: Allow d... |
781 |
} |
f5c67ea03 dm: core: Add a w... |
782 783 784 785 786 787 |
int device_set_name(struct udevice *dev, const char *name) { name = strdup(name); if (!name) return -ENOMEM; dev->name = name; |
a2040facd dm: core: Allow d... |
788 |
device_set_name_alloced(dev); |
f5c67ea03 dm: core: Add a w... |
789 790 791 |
return 0; } |
73443b9e4 drivers: core: de... |
792 |
|
911f3aef3 dm: core: Rename ... |
793 |
bool device_is_compatible(struct udevice *dev, const char *compat) |
73443b9e4 drivers: core: de... |
794 |
{ |
5ccc2c213 dm: ofnode: add o... |
795 |
return ofnode_device_is_compatible(dev_ofnode(dev), compat); |
73443b9e4 drivers: core: de... |
796 797 798 799 800 801 802 803 |
} bool of_machine_is_compatible(const char *compat) { const void *fdt = gd->fdt_blob; return !fdt_node_check_compatible(fdt, 0, compat); } |
e4c98a59d core: Add dev_{di... |
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 |
int dev_disable_by_path(const char *path) { struct uclass *uc; ofnode node = ofnode_path(path); struct udevice *dev; int ret = 1; if (!of_live_active()) return -ENOSYS; list_for_each_entry(uc, &gd->uclass_root, sibling_node) { ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev); if (!ret) break; } if (ret) return ret; ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; ret = device_unbind(dev); if (ret) return ret; return ofnode_set_enabled(node, false); } int dev_enable_by_path(const char *path) { ofnode node = ofnode_path(path); ofnode pnode = ofnode_get_parent(node); struct udevice *parent; int ret = 1; if (!of_live_active()) return -ENOSYS; ret = device_find_by_ofnode(pnode, &parent); if (ret) return ret; ret = ofnode_set_enabled(node, true); if (ret) return ret; |
8d773c4ab dm: core: Respect... |
852 |
return lists_bind_fdt(parent, node, NULL, false); |
e4c98a59d core: Add dev_{di... |
853 |
} |