183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
26494d708SSimon Glass /*
36494d708SSimon Glass * Device manager
46494d708SSimon Glass *
56494d708SSimon Glass * Copyright (c) 2013 Google, Inc
66494d708SSimon Glass *
76494d708SSimon Glass * (C) Copyright 2012
86494d708SSimon Glass * Pavel Herrmann <morpheus.ibis@gmail.com>
96494d708SSimon Glass */
106494d708SSimon Glass
116494d708SSimon Glass #include <common.h>
127c616862SVignesh R #include <asm/io.h>
13f4fcba5cSPhilipp Tomsich #include <clk.h>
145a66a8ffSSimon Glass #include <fdtdec.h>
15ef5cd330SStefan Roese #include <fdt_support.h>
166494d708SSimon Glass #include <malloc.h>
176494d708SSimon Glass #include <dm/device.h>
186494d708SSimon Glass #include <dm/device-internal.h>
196494d708SSimon Glass #include <dm/lists.h>
2029d11b88SMario Six #include <dm/of_access.h>
21d90a5a30SMasahiro Yamada #include <dm/pinctrl.h>
226494d708SSimon Glass #include <dm/platdata.h>
23396e343bSSimon Glass #include <dm/read.h>
246494d708SSimon Glass #include <dm/uclass.h>
256494d708SSimon Glass #include <dm/uclass-internal.h>
266494d708SSimon Glass #include <dm/util.h>
276494d708SSimon Glass #include <linux/err.h>
286494d708SSimon Glass #include <linux/list.h>
293ad30778SPeng Fan #include <power-domain.h>
306494d708SSimon Glass
315a66a8ffSSimon Glass DECLARE_GLOBAL_DATA_PTR;
325a66a8ffSSimon Glass
device_bind_common(struct udevice * parent,const struct driver * drv,const char * name,void * platdata,ulong driver_data,ofnode node,uint of_platdata_size,struct udevice ** devp)33daac3bfeSStephen Warren static int device_bind_common(struct udevice *parent, const struct driver *drv,
34daac3bfeSStephen Warren const char *name, void *platdata,
357a61b0b5SSimon Glass ulong driver_data, ofnode node,
369fa28190SSimon Glass uint of_platdata_size, struct udevice **devp)
376494d708SSimon Glass {
3854c5d08aSHeiko Schocher struct udevice *dev;
396494d708SSimon Glass struct uclass *uc;
405eaed880SPrzemyslaw Marczak int size, ret = 0;
416494d708SSimon Glass
42e6cabe4aSMasahiro Yamada if (devp)
436494d708SSimon Glass *devp = NULL;
446494d708SSimon Glass if (!name)
456494d708SSimon Glass return -EINVAL;
466494d708SSimon Glass
476494d708SSimon Glass ret = uclass_get(drv->id, &uc);
483346c876SSimon Glass if (ret) {
493346c876SSimon Glass debug("Missing uclass for driver %s\n", drv->name);
506494d708SSimon Glass return ret;
513346c876SSimon Glass }
526494d708SSimon Glass
5354c5d08aSHeiko Schocher dev = calloc(1, sizeof(struct udevice));
546494d708SSimon Glass if (!dev)
556494d708SSimon Glass return -ENOMEM;
566494d708SSimon Glass
576494d708SSimon Glass INIT_LIST_HEAD(&dev->sibling_node);
586494d708SSimon Glass INIT_LIST_HEAD(&dev->child_head);
596494d708SSimon Glass INIT_LIST_HEAD(&dev->uclass_node);
60e2282d70SMasahiro Yamada #ifdef CONFIG_DEVRES
61608f26c5SMasahiro Yamada INIT_LIST_HEAD(&dev->devres_head);
62e2282d70SMasahiro Yamada #endif
636494d708SSimon Glass dev->platdata = platdata;
64daac3bfeSStephen Warren dev->driver_data = driver_data;
656494d708SSimon Glass dev->name = name;
667a61b0b5SSimon Glass dev->node = node;
676494d708SSimon Glass dev->parent = parent;
686494d708SSimon Glass dev->driver = drv;
696494d708SSimon Glass dev->uclass = uc;
705a66a8ffSSimon Glass
715a66a8ffSSimon Glass dev->seq = -1;
7291cbd792SSimon Glass dev->req_seq = -1;
73*3542ff29SJean-Jacques Hiblot if (CONFIG_IS_ENABLED(DM_SEQ_ALIAS) &&
74*3542ff29SJean-Jacques Hiblot (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS)) {
759cc36a2bSSimon Glass /*
7636fa61dcSSimon Glass * Some devices, such as a SPI bus, I2C bus and serial ports
7736fa61dcSSimon Glass * are numbered using aliases.
789cc36a2bSSimon Glass *
799cc36a2bSSimon Glass * This is just a 'requested' sequence, and will be
809cc36a2bSSimon Glass * resolved (and ->seq updated) when the device is probed.
819cc36a2bSSimon Glass */
82*3542ff29SJean-Jacques Hiblot if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
83*3542ff29SJean-Jacques Hiblot if (uc->uc_drv->name && ofnode_valid(node))
84396e343bSSimon Glass dev_read_alias_seq(dev, &dev->req_seq);
85*3542ff29SJean-Jacques Hiblot } else {
86*3542ff29SJean-Jacques Hiblot dev->req_seq = uclass_find_next_free_req_seq(drv->id);
879cc36a2bSSimon Glass }
8836fa61dcSSimon Glass }
8936fa61dcSSimon Glass
909fa28190SSimon Glass if (drv->platdata_auto_alloc_size) {
919fa28190SSimon Glass bool alloc = !platdata;
929fa28190SSimon Glass
939fa28190SSimon Glass if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
949fa28190SSimon Glass if (of_platdata_size) {
959fa28190SSimon Glass dev->flags |= DM_FLAG_OF_PLATDATA;
969fa28190SSimon Glass if (of_platdata_size <
979fa28190SSimon Glass drv->platdata_auto_alloc_size)
989fa28190SSimon Glass alloc = true;
999fa28190SSimon Glass }
1009fa28190SSimon Glass }
1019fa28190SSimon Glass if (alloc) {
1026494d708SSimon Glass dev->flags |= DM_FLAG_ALLOC_PDATA;
1039fa28190SSimon Glass dev->platdata = calloc(1,
1049fa28190SSimon Glass drv->platdata_auto_alloc_size);
105f8a85449SSimon Glass if (!dev->platdata) {
106f8a85449SSimon Glass ret = -ENOMEM;
107f8a85449SSimon Glass goto fail_alloc1;
108f8a85449SSimon Glass }
1099fa28190SSimon Glass if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
1109fa28190SSimon Glass memcpy(dev->platdata, platdata,
1119fa28190SSimon Glass of_platdata_size);
1129fa28190SSimon Glass }
1139fa28190SSimon Glass }
114f8a85449SSimon Glass }
115cdc133bdSSimon Glass
1165eaed880SPrzemyslaw Marczak size = uc->uc_drv->per_device_platdata_auto_alloc_size;
1175eaed880SPrzemyslaw Marczak if (size) {
1185eaed880SPrzemyslaw Marczak dev->flags |= DM_FLAG_ALLOC_UCLASS_PDATA;
1195eaed880SPrzemyslaw Marczak dev->uclass_platdata = calloc(1, size);
1205eaed880SPrzemyslaw Marczak if (!dev->uclass_platdata) {
1215eaed880SPrzemyslaw Marczak ret = -ENOMEM;
1225eaed880SPrzemyslaw Marczak goto fail_alloc2;
1235eaed880SPrzemyslaw Marczak }
1245eaed880SPrzemyslaw Marczak }
1255eaed880SPrzemyslaw Marczak
1265eaed880SPrzemyslaw Marczak if (parent) {
1275eaed880SPrzemyslaw Marczak size = parent->driver->per_child_platdata_auto_alloc_size;
128ba8da9dcSSimon Glass if (!size) {
129ba8da9dcSSimon Glass size = parent->uclass->uc_drv->
130ba8da9dcSSimon Glass per_child_platdata_auto_alloc_size;
131ba8da9dcSSimon Glass }
132cdc133bdSSimon Glass if (size) {
133cdc133bdSSimon Glass dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
134cdc133bdSSimon Glass dev->parent_platdata = calloc(1, size);
135cdc133bdSSimon Glass if (!dev->parent_platdata) {
136cdc133bdSSimon Glass ret = -ENOMEM;
1375eaed880SPrzemyslaw Marczak goto fail_alloc3;
138cdc133bdSSimon Glass }
139cdc133bdSSimon Glass }
140cdc133bdSSimon Glass }
1416494d708SSimon Glass
1426494d708SSimon Glass /* put dev into parent's successor list */
1436494d708SSimon Glass if (parent)
1446494d708SSimon Glass list_add_tail(&dev->sibling_node, &parent->child_head);
1456494d708SSimon Glass
1466494d708SSimon Glass ret = uclass_bind_device(dev);
1476494d708SSimon Glass if (ret)
14872ebfe86SSimon Glass goto fail_uclass_bind;
1496494d708SSimon Glass
1506494d708SSimon Glass /* if we fail to bind we remove device from successors and free it */
1516494d708SSimon Glass if (drv->bind) {
1526494d708SSimon Glass ret = drv->bind(dev);
15372ebfe86SSimon Glass if (ret)
1546494d708SSimon Glass goto fail_bind;
1556494d708SSimon Glass }
1560118ce79SSimon Glass if (parent && parent->driver->child_post_bind) {
1570118ce79SSimon Glass ret = parent->driver->child_post_bind(dev);
1580118ce79SSimon Glass if (ret)
1590118ce79SSimon Glass goto fail_child_post_bind;
1600118ce79SSimon Glass }
16120af3c0aSSimon Glass if (uc->uc_drv->post_bind) {
16220af3c0aSSimon Glass ret = uc->uc_drv->post_bind(dev);
16320af3c0aSSimon Glass if (ret)
16420af3c0aSSimon Glass goto fail_uclass_post_bind;
16520af3c0aSSimon Glass }
1660118ce79SSimon Glass
1676494d708SSimon Glass if (parent)
168ceb91909SMasahiro Yamada pr_debug("Bound device %s to %s\n", dev->name, parent->name);
169e6cabe4aSMasahiro Yamada if (devp)
1706494d708SSimon Glass *devp = dev;
1716494d708SSimon Glass
172aed1a4ddSMasahiro Yamada dev->flags |= DM_FLAG_BOUND;
173aed1a4ddSMasahiro Yamada
1746494d708SSimon Glass return 0;
1756494d708SSimon Glass
17620af3c0aSSimon Glass fail_uclass_post_bind:
17720af3c0aSSimon Glass /* There is no child unbind() method, so no clean-up required */
1780118ce79SSimon Glass fail_child_post_bind:
1790a5804b5SMasahiro Yamada if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
1800118ce79SSimon Glass if (drv->unbind && drv->unbind(dev)) {
1810118ce79SSimon Glass dm_warn("unbind() method failed on dev '%s' on error path\n",
1820118ce79SSimon Glass dev->name);
1830118ce79SSimon Glass }
1845a87c417SSimon Glass }
1850118ce79SSimon Glass
1866494d708SSimon Glass fail_bind:
1870a5804b5SMasahiro Yamada if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
18872ebfe86SSimon Glass if (uclass_unbind_device(dev)) {
18972ebfe86SSimon Glass dm_warn("Failed to unbind dev '%s' on error path\n",
19072ebfe86SSimon Glass dev->name);
19172ebfe86SSimon Glass }
1925a87c417SSimon Glass }
19372ebfe86SSimon Glass fail_uclass_bind:
1940a5804b5SMasahiro Yamada if (CONFIG_IS_ENABLED(DM_DEVICE_REMOVE)) {
1956494d708SSimon Glass list_del(&dev->sibling_node);
196cdc133bdSSimon Glass if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
197cdc133bdSSimon Glass free(dev->parent_platdata);
198cdc133bdSSimon Glass dev->parent_platdata = NULL;
199cdc133bdSSimon Glass }
2005a87c417SSimon Glass }
2015eaed880SPrzemyslaw Marczak fail_alloc3:
2025eaed880SPrzemyslaw Marczak if (dev->flags & DM_FLAG_ALLOC_UCLASS_PDATA) {
2035eaed880SPrzemyslaw Marczak free(dev->uclass_platdata);
2045eaed880SPrzemyslaw Marczak dev->uclass_platdata = NULL;
2055eaed880SPrzemyslaw Marczak }
206cdc133bdSSimon Glass fail_alloc2:
207f8a85449SSimon Glass if (dev->flags & DM_FLAG_ALLOC_PDATA) {
208f8a85449SSimon Glass free(dev->platdata);
209f8a85449SSimon Glass dev->platdata = NULL;
210f8a85449SSimon Glass }
211f8a85449SSimon Glass fail_alloc1:
212608f26c5SMasahiro Yamada devres_release_all(dev);
213608f26c5SMasahiro Yamada
2146494d708SSimon Glass free(dev);
21572ebfe86SSimon Glass
2166494d708SSimon Glass return ret;
2176494d708SSimon Glass }
2186494d708SSimon Glass
device_bind_with_driver_data(struct udevice * parent,const struct driver * drv,const char * name,ulong driver_data,ofnode node,struct udevice ** devp)219daac3bfeSStephen Warren int device_bind_with_driver_data(struct udevice *parent,
220daac3bfeSStephen Warren const struct driver *drv, const char *name,
221396e343bSSimon Glass ulong driver_data, ofnode node,
222daac3bfeSStephen Warren struct udevice **devp)
223daac3bfeSStephen Warren {
224396e343bSSimon Glass return device_bind_common(parent, drv, name, NULL, driver_data, node,
225396e343bSSimon Glass 0, devp);
226daac3bfeSStephen Warren }
227daac3bfeSStephen Warren
device_bind(struct udevice * parent,const struct driver * drv,const char * name,void * platdata,int of_offset,struct udevice ** devp)228daac3bfeSStephen Warren int device_bind(struct udevice *parent, const struct driver *drv,
229daac3bfeSStephen Warren const char *name, void *platdata, int of_offset,
230daac3bfeSStephen Warren struct udevice **devp)
231daac3bfeSStephen Warren {
2327a61b0b5SSimon Glass return device_bind_common(parent, drv, name, platdata, 0,
2337a61b0b5SSimon Glass offset_to_ofnode(of_offset), 0, devp);
234daac3bfeSStephen Warren }
235daac3bfeSStephen Warren
device_bind_ofnode(struct udevice * parent,const struct driver * drv,const char * name,void * platdata,ofnode node,struct udevice ** devp)236d677b00cSSimon Glass int device_bind_ofnode(struct udevice *parent, const struct driver *drv,
237d677b00cSSimon Glass const char *name, void *platdata, ofnode node,
238d677b00cSSimon Glass struct udevice **devp)
239d677b00cSSimon Glass {
240d677b00cSSimon Glass return device_bind_common(parent, drv, name, platdata, 0, node, 0,
241d677b00cSSimon Glass devp);
242d677b00cSSimon Glass }
243d677b00cSSimon Glass
device_bind_by_name(struct udevice * parent,bool pre_reloc_only,const struct driver_info * info,struct udevice ** devp)24400606d7eSSimon Glass int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
24500606d7eSSimon Glass const struct driver_info *info, struct udevice **devp)
2466494d708SSimon Glass {
2476494d708SSimon Glass struct driver *drv;
2489fa28190SSimon Glass uint platdata_size = 0;
2496494d708SSimon Glass
2506494d708SSimon Glass drv = lists_driver_lookup_name(info->name);
2516494d708SSimon Glass if (!drv)
2526494d708SSimon Glass return -ENOENT;
25300606d7eSSimon Glass if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
25400606d7eSSimon Glass return -EPERM;
2556494d708SSimon Glass
2569fa28190SSimon Glass #if CONFIG_IS_ENABLED(OF_PLATDATA)
2579fa28190SSimon Glass platdata_size = info->platdata_size;
2589fa28190SSimon Glass #endif
2599fa28190SSimon Glass return device_bind_common(parent, drv, info->name,
260396e343bSSimon Glass (void *)info->platdata, 0, ofnode_null(), platdata_size,
261396e343bSSimon Glass devp);
2626494d708SSimon Glass }
2636494d708SSimon Glass
alloc_priv(int size,uint flags)2642c03c463SSimon Glass static void *alloc_priv(int size, uint flags)
2652c03c463SSimon Glass {
2662c03c463SSimon Glass void *priv;
2672c03c463SSimon Glass
2682c03c463SSimon Glass if (flags & DM_FLAG_ALLOC_PRIV_DMA) {
2695924da1dSFaiz Abbas size = ROUND(size, ARCH_DMA_MINALIGN);
2702c03c463SSimon Glass priv = memalign(ARCH_DMA_MINALIGN, size);
2715a8a8045SSimon Glass if (priv) {
2722c03c463SSimon Glass memset(priv, '\0', size);
2735a8a8045SSimon Glass
2745a8a8045SSimon Glass /*
2755a8a8045SSimon Glass * Ensure that the zero bytes are flushed to memory.
2765a8a8045SSimon Glass * This prevents problems if the driver uses this as
2775a8a8045SSimon Glass * both an input and an output buffer:
2785a8a8045SSimon Glass *
2795a8a8045SSimon Glass * 1. Zeroes written to buffer (here) and sit in the
2805a8a8045SSimon Glass * cache
2815a8a8045SSimon Glass * 2. Driver issues a read command to DMA
2825a8a8045SSimon Glass * 3. CPU runs out of cache space and evicts some cache
2835a8a8045SSimon Glass * data in the buffer, writing zeroes to RAM from
2845a8a8045SSimon Glass * the memset() above
2855a8a8045SSimon Glass * 4. DMA completes
2865a8a8045SSimon Glass * 5. Buffer now has some DMA data and some zeroes
2875a8a8045SSimon Glass * 6. Data being read is now incorrect
2885a8a8045SSimon Glass *
2895a8a8045SSimon Glass * To prevent this, ensure that the cache is clean
2905a8a8045SSimon Glass * within this range at the start. The driver can then
2915a8a8045SSimon Glass * use normal flush-after-write, invalidate-before-read
2925a8a8045SSimon Glass * procedures.
2935a8a8045SSimon Glass *
2945a8a8045SSimon Glass * TODO(sjg@chromium.org): Drop this microblaze
2955a8a8045SSimon Glass * exception.
2965a8a8045SSimon Glass */
2975a8a8045SSimon Glass #ifndef CONFIG_MICROBLAZE
2985a8a8045SSimon Glass flush_dcache_range((ulong)priv, (ulong)priv + size);
2995a8a8045SSimon Glass #endif
3005a8a8045SSimon Glass }
3012c03c463SSimon Glass } else {
3022c03c463SSimon Glass priv = calloc(1, size);
3032c03c463SSimon Glass }
3042c03c463SSimon Glass
3052c03c463SSimon Glass return priv;
3062c03c463SSimon Glass }
3072c03c463SSimon Glass
device_probe(struct udevice * dev)308c6db965fSSimon Glass int device_probe(struct udevice *dev)
3096494d708SSimon Glass {
3103ad30778SPeng Fan struct power_domain pd;
3113479253dSSimon Glass const struct driver *drv;
3126494d708SSimon Glass int size = 0;
3136494d708SSimon Glass int ret;
3145a66a8ffSSimon Glass int seq;
3156494d708SSimon Glass
3166494d708SSimon Glass if (!dev)
3176494d708SSimon Glass return -EINVAL;
3186494d708SSimon Glass
3196494d708SSimon Glass if (dev->flags & DM_FLAG_ACTIVATED)
3206494d708SSimon Glass return 0;
3216494d708SSimon Glass
3226494d708SSimon Glass drv = dev->driver;
3236494d708SSimon Glass assert(drv);
3246494d708SSimon Glass
325cdeb2ba9SBin Meng /* Allocate private data if requested and not reentered */
326cdeb2ba9SBin Meng if (drv->priv_auto_alloc_size && !dev->priv) {
3272c03c463SSimon Glass dev->priv = alloc_priv(drv->priv_auto_alloc_size, drv->flags);
3286494d708SSimon Glass if (!dev->priv) {
3296494d708SSimon Glass ret = -ENOMEM;
3306494d708SSimon Glass goto fail;
3316494d708SSimon Glass }
3326494d708SSimon Glass }
333cdeb2ba9SBin Meng /* Allocate private data if requested and not reentered */
3346494d708SSimon Glass size = dev->uclass->uc_drv->per_device_auto_alloc_size;
335cdeb2ba9SBin Meng if (size && !dev->uclass_priv) {
336c7a3acccSSimon Glass dev->uclass_priv = alloc_priv(size,
337c7a3acccSSimon Glass dev->uclass->uc_drv->flags);
3386494d708SSimon Glass if (!dev->uclass_priv) {
3396494d708SSimon Glass ret = -ENOMEM;
3406494d708SSimon Glass goto fail;
3416494d708SSimon Glass }
3426494d708SSimon Glass }
3436494d708SSimon Glass
3446494d708SSimon Glass /* Ensure all parents are probed */
3456494d708SSimon Glass if (dev->parent) {
346e59f458dSSimon Glass size = dev->parent->driver->per_child_auto_alloc_size;
347dac8db2cSSimon Glass if (!size) {
348dac8db2cSSimon Glass size = dev->parent->uclass->uc_drv->
349dac8db2cSSimon Glass per_child_auto_alloc_size;
350dac8db2cSSimon Glass }
351cdeb2ba9SBin Meng if (size && !dev->parent_priv) {
3522c03c463SSimon Glass dev->parent_priv = alloc_priv(size, drv->flags);
353e59f458dSSimon Glass if (!dev->parent_priv) {
354e59f458dSSimon Glass ret = -ENOMEM;
355e59f458dSSimon Glass goto fail;
356e59f458dSSimon Glass }
357e59f458dSSimon Glass }
358e59f458dSSimon Glass
3596494d708SSimon Glass ret = device_probe(dev->parent);
3606494d708SSimon Glass if (ret)
3616494d708SSimon Glass goto fail;
362cdeb2ba9SBin Meng
363cdeb2ba9SBin Meng /*
364cdeb2ba9SBin Meng * The device might have already been probed during
365cdeb2ba9SBin Meng * the call to device_probe() on its parent device
366cdeb2ba9SBin Meng * (e.g. PCI bridge devices). Test the flags again
367cdeb2ba9SBin Meng * so that we don't mess up the device.
368cdeb2ba9SBin Meng */
369cdeb2ba9SBin Meng if (dev->flags & DM_FLAG_ACTIVATED)
370cdeb2ba9SBin Meng return 0;
3716494d708SSimon Glass }
3726494d708SSimon Glass
3735a66a8ffSSimon Glass seq = uclass_resolve_seq(dev);
3745a66a8ffSSimon Glass if (seq < 0) {
3755a66a8ffSSimon Glass ret = seq;
3765a66a8ffSSimon Glass goto fail;
3775a66a8ffSSimon Glass }
3785a66a8ffSSimon Glass dev->seq = seq;
3795a66a8ffSSimon Glass
380206d4d2bSSimon Glass dev->flags |= DM_FLAG_ACTIVATED;
381206d4d2bSSimon Glass
38284d26e29SSimon Glass /*
38384d26e29SSimon Glass * Process pinctrl for everything except the root device, and
3840379597eSSimon Glass * continue regardless of the result of pinctrl. Don't process pinctrl
3850379597eSSimon Glass * settings for pinctrl devices since the device may not yet be
3860379597eSSimon Glass * probed.
38784d26e29SSimon Glass */
3880379597eSSimon Glass if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL)
389d90a5a30SMasahiro Yamada pinctrl_select_state(dev, "default");
390d90a5a30SMasahiro Yamada
3913ad30778SPeng Fan if (dev->parent && device_get_uclass_id(dev) != UCLASS_POWER_DOMAIN) {
3923ad30778SPeng Fan if (!power_domain_get(dev, &pd))
3933ad30778SPeng Fan power_domain_on(&pd);
3943ad30778SPeng Fan }
3953ad30778SPeng Fan
39602c07b37SSimon Glass ret = uclass_pre_probe_device(dev);
39783c7e434SSimon Glass if (ret)
39883c7e434SSimon Glass goto fail;
39983c7e434SSimon Glass
400a327dee0SSimon Glass if (dev->parent && dev->parent->driver->child_pre_probe) {
401a327dee0SSimon Glass ret = dev->parent->driver->child_pre_probe(dev);
402a327dee0SSimon Glass if (ret)
403a327dee0SSimon Glass goto fail;
404a327dee0SSimon Glass }
405a327dee0SSimon Glass
406396e343bSSimon Glass if (drv->ofdata_to_platdata && dev_has_of_node(dev)) {
4076494d708SSimon Glass ret = drv->ofdata_to_platdata(dev);
4086494d708SSimon Glass if (ret)
4096494d708SSimon Glass goto fail;
4106494d708SSimon Glass }
4116494d708SSimon Glass
412f4fcba5cSPhilipp Tomsich /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
413f4fcba5cSPhilipp Tomsich ret = clk_set_defaults(dev);
414f4fcba5cSPhilipp Tomsich if (ret)
415f4fcba5cSPhilipp Tomsich goto fail;
416f4fcba5cSPhilipp Tomsich
4176494d708SSimon Glass if (drv->probe) {
4186494d708SSimon Glass ret = drv->probe(dev);
41902eeb1bbSSimon Glass if (ret) {
42002eeb1bbSSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED;
4216494d708SSimon Glass goto fail;
4226494d708SSimon Glass }
42302eeb1bbSSimon Glass }
4246494d708SSimon Glass
4256494d708SSimon Glass ret = uclass_post_probe_device(dev);
426206d4d2bSSimon Glass if (ret)
4276494d708SSimon Glass goto fail_uclass;
4286494d708SSimon Glass
429c3ab9853SPeng Fan if (dev->parent && device_get_uclass_id(dev) == UCLASS_PINCTRL)
430c3ab9853SPeng Fan pinctrl_select_state(dev, "default");
431c3ab9853SPeng Fan
4326494d708SSimon Glass return 0;
4336494d708SSimon Glass fail_uclass:
434706865afSStefan Roese if (device_remove(dev, DM_REMOVE_NORMAL)) {
4356494d708SSimon Glass dm_warn("%s: Device '%s' failed to remove on error path\n",
4366494d708SSimon Glass __func__, dev->name);
4376494d708SSimon Glass }
4386494d708SSimon Glass fail:
439206d4d2bSSimon Glass dev->flags &= ~DM_FLAG_ACTIVATED;
440206d4d2bSSimon Glass
4415a66a8ffSSimon Glass dev->seq = -1;
4426494d708SSimon Glass device_free(dev);
4436494d708SSimon Glass
4446494d708SSimon Glass return ret;
4456494d708SSimon Glass }
4466494d708SSimon Glass
dev_get_platdata(const struct udevice * dev)4479f15cc14SSimon Glass void *dev_get_platdata(const struct udevice *dev)
4486494d708SSimon Glass {
4496494d708SSimon Glass if (!dev) {
450964d153cSSimon Glass dm_warn("%s: null device\n", __func__);
4516494d708SSimon Glass return NULL;
4526494d708SSimon Glass }
4536494d708SSimon Glass
4546494d708SSimon Glass return dev->platdata;
4556494d708SSimon Glass }
4566494d708SSimon Glass
dev_get_parent_platdata(const struct udevice * dev)4579f15cc14SSimon Glass void *dev_get_parent_platdata(const struct udevice *dev)
458cdc133bdSSimon Glass {
459cdc133bdSSimon Glass if (!dev) {
46036d7cc17SSimon Glass dm_warn("%s: null device\n", __func__);
461cdc133bdSSimon Glass return NULL;
462cdc133bdSSimon Glass }
463cdc133bdSSimon Glass
464cdc133bdSSimon Glass return dev->parent_platdata;
465cdc133bdSSimon Glass }
466cdc133bdSSimon Glass
dev_get_uclass_platdata(const struct udevice * dev)4679f15cc14SSimon Glass void *dev_get_uclass_platdata(const struct udevice *dev)
4685eaed880SPrzemyslaw Marczak {
4695eaed880SPrzemyslaw Marczak if (!dev) {
47036d7cc17SSimon Glass dm_warn("%s: null device\n", __func__);
4715eaed880SPrzemyslaw Marczak return NULL;
4725eaed880SPrzemyslaw Marczak }
4735eaed880SPrzemyslaw Marczak
4745eaed880SPrzemyslaw Marczak return dev->uclass_platdata;
4755eaed880SPrzemyslaw Marczak }
4765eaed880SPrzemyslaw Marczak
dev_get_priv(const struct udevice * dev)4779f15cc14SSimon Glass void *dev_get_priv(const struct udevice *dev)
4786494d708SSimon Glass {
4796494d708SSimon Glass if (!dev) {
480964d153cSSimon Glass dm_warn("%s: null device\n", __func__);
4816494d708SSimon Glass return NULL;
4826494d708SSimon Glass }
4836494d708SSimon Glass
4846494d708SSimon Glass return dev->priv;
4856494d708SSimon Glass }
486997c87bbSSimon Glass
dev_get_uclass_priv(const struct udevice * dev)4879f15cc14SSimon Glass void *dev_get_uclass_priv(const struct udevice *dev)
488e564f054SSimon Glass {
489e564f054SSimon Glass if (!dev) {
490e564f054SSimon Glass dm_warn("%s: null device\n", __func__);
491e564f054SSimon Glass return NULL;
492e564f054SSimon Glass }
493e564f054SSimon Glass
494e564f054SSimon Glass return dev->uclass_priv;
495e564f054SSimon Glass }
496e564f054SSimon Glass
dev_get_parent_priv(const struct udevice * dev)4979f15cc14SSimon Glass void *dev_get_parent_priv(const struct udevice *dev)
498e59f458dSSimon Glass {
499e59f458dSSimon Glass if (!dev) {
500964d153cSSimon Glass dm_warn("%s: null device\n", __func__);
501e59f458dSSimon Glass return NULL;
502e59f458dSSimon Glass }
503e59f458dSSimon Glass
504e59f458dSSimon Glass return dev->parent_priv;
505e59f458dSSimon Glass }
506e59f458dSSimon Glass
device_get_device_tail(struct udevice * dev,int ret,struct udevice ** devp)507997c87bbSSimon Glass static int device_get_device_tail(struct udevice *dev, int ret,
508997c87bbSSimon Glass struct udevice **devp)
509997c87bbSSimon Glass {
510997c87bbSSimon Glass if (ret)
511997c87bbSSimon Glass return ret;
512997c87bbSSimon Glass
513997c87bbSSimon Glass ret = device_probe(dev);
514997c87bbSSimon Glass if (ret)
515997c87bbSSimon Glass return ret;
516997c87bbSSimon Glass
517997c87bbSSimon Glass *devp = dev;
518997c87bbSSimon Glass
519997c87bbSSimon Glass return 0;
520997c87bbSSimon Glass }
521997c87bbSSimon Glass
522e4c98a59SMario Six /**
523e4c98a59SMario Six * device_find_by_ofnode() - Return device associated with given ofnode
524e4c98a59SMario Six *
525e4c98a59SMario Six * The returned device is *not* activated.
526e4c98a59SMario Six *
527e4c98a59SMario Six * @node: The ofnode for which a associated device should be looked up
528e4c98a59SMario Six * @devp: Pointer to structure to hold the found device
529e4c98a59SMario Six * Return: 0 if OK, -ve on error
530e4c98a59SMario Six */
device_find_by_ofnode(ofnode node,struct udevice ** devp)531e4c98a59SMario Six static int device_find_by_ofnode(ofnode node, struct udevice **devp)
532e4c98a59SMario Six {
533e4c98a59SMario Six struct uclass *uc;
534e4c98a59SMario Six struct udevice *dev;
535e4c98a59SMario Six int ret;
536e4c98a59SMario Six
537e4c98a59SMario Six list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
538e4c98a59SMario Six ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node,
539e4c98a59SMario Six &dev);
540e4c98a59SMario Six if (!ret || dev) {
541e4c98a59SMario Six *devp = dev;
542e4c98a59SMario Six return 0;
543e4c98a59SMario Six }
544e4c98a59SMario Six }
545e4c98a59SMario Six
546e4c98a59SMario Six return -ENODEV;
547e4c98a59SMario Six }
548e4c98a59SMario Six
device_get_child(struct udevice * parent,int index,struct udevice ** devp)549997c87bbSSimon Glass int device_get_child(struct udevice *parent, int index, struct udevice **devp)
550997c87bbSSimon Glass {
551997c87bbSSimon Glass struct udevice *dev;
552997c87bbSSimon Glass
553997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
554997c87bbSSimon Glass if (!index--)
555997c87bbSSimon Glass return device_get_device_tail(dev, 0, devp);
556997c87bbSSimon Glass }
557997c87bbSSimon Glass
558997c87bbSSimon Glass return -ENODEV;
559997c87bbSSimon Glass }
560997c87bbSSimon Glass
device_find_child_by_seq(struct udevice * parent,int seq_or_req_seq,bool find_req_seq,struct udevice ** devp)561997c87bbSSimon Glass int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
562997c87bbSSimon Glass bool find_req_seq, struct udevice **devp)
563997c87bbSSimon Glass {
564997c87bbSSimon Glass struct udevice *dev;
565997c87bbSSimon Glass
566997c87bbSSimon Glass *devp = NULL;
567997c87bbSSimon Glass if (seq_or_req_seq == -1)
568997c87bbSSimon Glass return -ENODEV;
569997c87bbSSimon Glass
570997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
571997c87bbSSimon Glass if ((find_req_seq ? dev->req_seq : dev->seq) ==
572997c87bbSSimon Glass seq_or_req_seq) {
573997c87bbSSimon Glass *devp = dev;
574997c87bbSSimon Glass return 0;
575997c87bbSSimon Glass }
576997c87bbSSimon Glass }
577997c87bbSSimon Glass
578997c87bbSSimon Glass return -ENODEV;
579997c87bbSSimon Glass }
580997c87bbSSimon Glass
device_get_child_by_seq(struct udevice * parent,int seq,struct udevice ** devp)581997c87bbSSimon Glass int device_get_child_by_seq(struct udevice *parent, int seq,
582997c87bbSSimon Glass struct udevice **devp)
583997c87bbSSimon Glass {
584997c87bbSSimon Glass struct udevice *dev;
585997c87bbSSimon Glass int ret;
586997c87bbSSimon Glass
587997c87bbSSimon Glass *devp = NULL;
588997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, false, &dev);
589997c87bbSSimon Glass if (ret == -ENODEV) {
590997c87bbSSimon Glass /*
591997c87bbSSimon Glass * We didn't find it in probed devices. See if there is one
592997c87bbSSimon Glass * that will request this seq if probed.
593997c87bbSSimon Glass */
594997c87bbSSimon Glass ret = device_find_child_by_seq(parent, seq, true, &dev);
595997c87bbSSimon Glass }
596997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp);
597997c87bbSSimon Glass }
598997c87bbSSimon Glass
device_find_child_by_of_offset(struct udevice * parent,int of_offset,struct udevice ** devp)599997c87bbSSimon Glass int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
600997c87bbSSimon Glass struct udevice **devp)
601997c87bbSSimon Glass {
602997c87bbSSimon Glass struct udevice *dev;
603997c87bbSSimon Glass
604997c87bbSSimon Glass *devp = NULL;
605997c87bbSSimon Glass
606997c87bbSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
607e160f7d4SSimon Glass if (dev_of_offset(dev) == of_offset) {
608997c87bbSSimon Glass *devp = dev;
609997c87bbSSimon Glass return 0;
610997c87bbSSimon Glass }
611997c87bbSSimon Glass }
612997c87bbSSimon Glass
613997c87bbSSimon Glass return -ENODEV;
614997c87bbSSimon Glass }
615997c87bbSSimon Glass
device_get_child_by_of_offset(struct udevice * parent,int node,struct udevice ** devp)616132f9bfcSSimon Glass int device_get_child_by_of_offset(struct udevice *parent, int node,
617997c87bbSSimon Glass struct udevice **devp)
618997c87bbSSimon Glass {
619997c87bbSSimon Glass struct udevice *dev;
620997c87bbSSimon Glass int ret;
621997c87bbSSimon Glass
622997c87bbSSimon Glass *devp = NULL;
623132f9bfcSSimon Glass ret = device_find_child_by_of_offset(parent, node, &dev);
624997c87bbSSimon Glass return device_get_device_tail(dev, ret, devp);
625997c87bbSSimon Glass }
626a8981d4fSSimon Glass
_device_find_global_by_ofnode(struct udevice * parent,ofnode ofnode)6277ec9181dSJean-Jacques Hiblot static struct udevice *_device_find_global_by_ofnode(struct udevice *parent,
6287ec9181dSJean-Jacques Hiblot ofnode ofnode)
6292693047aSSimon Glass {
6302693047aSSimon Glass struct udevice *dev, *found;
6312693047aSSimon Glass
6327ec9181dSJean-Jacques Hiblot if (ofnode_equal(dev_ofnode(parent), ofnode))
6332693047aSSimon Glass return parent;
6342693047aSSimon Glass
6352693047aSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
6367ec9181dSJean-Jacques Hiblot found = _device_find_global_by_ofnode(dev, ofnode);
6372693047aSSimon Glass if (found)
6382693047aSSimon Glass return found;
6392693047aSSimon Glass }
6402693047aSSimon Glass
6412693047aSSimon Glass return NULL;
6422693047aSSimon Glass }
6432693047aSSimon Glass
device_find_global_by_ofnode(ofnode ofnode,struct udevice ** devp)6447ec9181dSJean-Jacques Hiblot int device_find_global_by_ofnode(ofnode ofnode, struct udevice **devp)
6457ec9181dSJean-Jacques Hiblot {
6467ec9181dSJean-Jacques Hiblot *devp = _device_find_global_by_ofnode(gd->dm_root, ofnode);
6477ec9181dSJean-Jacques Hiblot
6487ec9181dSJean-Jacques Hiblot return *devp ? 0 : -ENOENT;
6497ec9181dSJean-Jacques Hiblot }
6507ec9181dSJean-Jacques Hiblot
device_get_global_by_ofnode(ofnode ofnode,struct udevice ** devp)6517ec9181dSJean-Jacques Hiblot int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
6522693047aSSimon Glass {
6532693047aSSimon Glass struct udevice *dev;
6542693047aSSimon Glass
6557ec9181dSJean-Jacques Hiblot dev = _device_find_global_by_ofnode(gd->dm_root, ofnode);
6562693047aSSimon Glass return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
6572693047aSSimon Glass }
6582693047aSSimon Glass
device_find_first_child(struct udevice * parent,struct udevice ** devp)659a8981d4fSSimon Glass int device_find_first_child(struct udevice *parent, struct udevice **devp)
660a8981d4fSSimon Glass {
661a8981d4fSSimon Glass if (list_empty(&parent->child_head)) {
662a8981d4fSSimon Glass *devp = NULL;
663a8981d4fSSimon Glass } else {
664a8981d4fSSimon Glass *devp = list_first_entry(&parent->child_head, struct udevice,
665a8981d4fSSimon Glass sibling_node);
666a8981d4fSSimon Glass }
667a8981d4fSSimon Glass
668a8981d4fSSimon Glass return 0;
669a8981d4fSSimon Glass }
670a8981d4fSSimon Glass
device_find_next_child(struct udevice ** devp)671a8981d4fSSimon Glass int device_find_next_child(struct udevice **devp)
672a8981d4fSSimon Glass {
673a8981d4fSSimon Glass struct udevice *dev = *devp;
674a8981d4fSSimon Glass struct udevice *parent = dev->parent;
675a8981d4fSSimon Glass
676a8981d4fSSimon Glass if (list_is_last(&dev->sibling_node, &parent->child_head)) {
677a8981d4fSSimon Glass *devp = NULL;
678a8981d4fSSimon Glass } else {
679a8981d4fSSimon Glass *devp = list_entry(dev->sibling_node.next, struct udevice,
680a8981d4fSSimon Glass sibling_node);
681a8981d4fSSimon Glass }
682a8981d4fSSimon Glass
683a8981d4fSSimon Glass return 0;
684a8981d4fSSimon Glass }
6852ef249b4SSimon Glass
device_find_first_inactive_child(struct udevice * parent,enum uclass_id uclass_id,struct udevice ** devp)686cdb6aa0aSSimon Glass int device_find_first_inactive_child(struct udevice *parent,
687cdb6aa0aSSimon Glass enum uclass_id uclass_id,
688cdb6aa0aSSimon Glass struct udevice **devp)
689cdb6aa0aSSimon Glass {
690cdb6aa0aSSimon Glass struct udevice *dev;
691cdb6aa0aSSimon Glass
692cdb6aa0aSSimon Glass *devp = NULL;
693cdb6aa0aSSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
694cdb6aa0aSSimon Glass if (!device_active(dev) &&
695cdb6aa0aSSimon Glass device_get_uclass_id(dev) == uclass_id) {
696cdb6aa0aSSimon Glass *devp = dev;
697cdb6aa0aSSimon Glass return 0;
698cdb6aa0aSSimon Glass }
699cdb6aa0aSSimon Glass }
700cdb6aa0aSSimon Glass
701cdb6aa0aSSimon Glass return -ENODEV;
702cdb6aa0aSSimon Glass }
703cdb6aa0aSSimon Glass
device_find_first_child_by_uclass(struct udevice * parent,enum uclass_id uclass_id,struct udevice ** devp)7043abe1115SSimon Glass int device_find_first_child_by_uclass(struct udevice *parent,
7053abe1115SSimon Glass enum uclass_id uclass_id,
7063abe1115SSimon Glass struct udevice **devp)
7073abe1115SSimon Glass {
7083abe1115SSimon Glass struct udevice *dev;
7093abe1115SSimon Glass
7103abe1115SSimon Glass *devp = NULL;
7113abe1115SSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
7123abe1115SSimon Glass if (device_get_uclass_id(dev) == uclass_id) {
7133abe1115SSimon Glass *devp = dev;
7143abe1115SSimon Glass return 0;
7153abe1115SSimon Glass }
7163abe1115SSimon Glass }
7173abe1115SSimon Glass
7183abe1115SSimon Glass return -ENODEV;
7193abe1115SSimon Glass }
7203abe1115SSimon Glass
device_find_child_by_name(struct udevice * parent,const char * name,struct udevice ** devp)7213abe1115SSimon Glass int device_find_child_by_name(struct udevice *parent, const char *name,
7223abe1115SSimon Glass struct udevice **devp)
7233abe1115SSimon Glass {
7243abe1115SSimon Glass struct udevice *dev;
7253abe1115SSimon Glass
7263abe1115SSimon Glass *devp = NULL;
7273abe1115SSimon Glass
7283abe1115SSimon Glass list_for_each_entry(dev, &parent->child_head, sibling_node) {
7293abe1115SSimon Glass if (!strcmp(dev->name, name)) {
7303abe1115SSimon Glass *devp = dev;
7313abe1115SSimon Glass return 0;
7323abe1115SSimon Glass }
7333abe1115SSimon Glass }
7343abe1115SSimon Glass
7353abe1115SSimon Glass return -ENODEV;
7363abe1115SSimon Glass }
7373abe1115SSimon Glass
dev_get_parent(const struct udevice * child)7389f15cc14SSimon Glass struct udevice *dev_get_parent(const struct udevice *child)
739479728cbSSimon Glass {
740479728cbSSimon Glass return child->parent;
741479728cbSSimon Glass }
742479728cbSSimon Glass
dev_get_driver_data(const struct udevice * dev)7439f15cc14SSimon Glass ulong dev_get_driver_data(const struct udevice *dev)
7442ef249b4SSimon Glass {
74539de8433SSimon Glass return dev->driver_data;
7462ef249b4SSimon Glass }
747b3670531SSimon Glass
dev_get_driver_ops(const struct udevice * dev)7489f15cc14SSimon Glass const void *dev_get_driver_ops(const struct udevice *dev)
749cc73d37bSPrzemyslaw Marczak {
750cc73d37bSPrzemyslaw Marczak if (!dev || !dev->driver->ops)
751cc73d37bSPrzemyslaw Marczak return NULL;
752cc73d37bSPrzemyslaw Marczak
753cc73d37bSPrzemyslaw Marczak return dev->driver->ops;
754cc73d37bSPrzemyslaw Marczak }
755cc73d37bSPrzemyslaw Marczak
device_get_uclass_id(const struct udevice * dev)7569f15cc14SSimon Glass enum uclass_id device_get_uclass_id(const struct udevice *dev)
757b3670531SSimon Glass {
758b3670531SSimon Glass return dev->uclass->uc_drv->id;
759b3670531SSimon Glass }
760c9cac3f8SPeng Fan
dev_get_uclass_name(const struct udevice * dev)7619f15cc14SSimon Glass const char *dev_get_uclass_name(const struct udevice *dev)
762f9c370dcSPrzemyslaw Marczak {
763f9c370dcSPrzemyslaw Marczak if (!dev)
764f9c370dcSPrzemyslaw Marczak return NULL;
765f9c370dcSPrzemyslaw Marczak
766f9c370dcSPrzemyslaw Marczak return dev->uclass->uc_drv->name;
767f9c370dcSPrzemyslaw Marczak }
768f9c370dcSPrzemyslaw Marczak
device_has_children(const struct udevice * dev)7699f15cc14SSimon Glass bool device_has_children(const struct udevice *dev)
770c5785673SSimon Glass {
771c5785673SSimon Glass return !list_empty(&dev->child_head);
772c5785673SSimon Glass }
773c5785673SSimon Glass
device_has_active_children(struct udevice * dev)774c5785673SSimon Glass bool device_has_active_children(struct udevice *dev)
775c5785673SSimon Glass {
776c5785673SSimon Glass struct udevice *child;
777c5785673SSimon Glass
778c5785673SSimon Glass for (device_find_first_child(dev, &child);
779c5785673SSimon Glass child;
780c5785673SSimon Glass device_find_next_child(&child)) {
781c5785673SSimon Glass if (device_active(child))
782c5785673SSimon Glass return true;
783c5785673SSimon Glass }
784c5785673SSimon Glass
785c5785673SSimon Glass return false;
786c5785673SSimon Glass }
787c5785673SSimon Glass
device_is_last_sibling(struct udevice * dev)788c5785673SSimon Glass bool device_is_last_sibling(struct udevice *dev)
789c5785673SSimon Glass {
790c5785673SSimon Glass struct udevice *parent = dev->parent;
791c5785673SSimon Glass
792c5785673SSimon Glass if (!parent)
793c5785673SSimon Glass return false;
794c5785673SSimon Glass return list_is_last(&dev->sibling_node, &parent->child_head);
795c5785673SSimon Glass }
796f5c67ea0SSimon Glass
device_set_name_alloced(struct udevice * dev)797a2040facSSimon Glass void device_set_name_alloced(struct udevice *dev)
798a2040facSSimon Glass {
799fd1c2d9bSSimon Glass dev->flags |= DM_FLAG_NAME_ALLOCED;
800a2040facSSimon Glass }
801a2040facSSimon Glass
device_set_name(struct udevice * dev,const char * name)802f5c67ea0SSimon Glass int device_set_name(struct udevice *dev, const char *name)
803f5c67ea0SSimon Glass {
804f5c67ea0SSimon Glass name = strdup(name);
805f5c67ea0SSimon Glass if (!name)
806f5c67ea0SSimon Glass return -ENOMEM;
807f5c67ea0SSimon Glass dev->name = name;
808a2040facSSimon Glass device_set_name_alloced(dev);
809f5c67ea0SSimon Glass
810f5c67ea0SSimon Glass return 0;
811f5c67ea0SSimon Glass }
81273443b9eSMugunthan V N
device_is_compatible(struct udevice * dev,const char * compat)813911f3aefSSimon Glass bool device_is_compatible(struct udevice *dev, const char *compat)
81473443b9eSMugunthan V N {
8155ccc2c21SMasahiro Yamada return ofnode_device_is_compatible(dev_ofnode(dev), compat);
81673443b9eSMugunthan V N }
81773443b9eSMugunthan V N
of_machine_is_compatible(const char * compat)81873443b9eSMugunthan V N bool of_machine_is_compatible(const char *compat)
81973443b9eSMugunthan V N {
82073443b9eSMugunthan V N const void *fdt = gd->fdt_blob;
82173443b9eSMugunthan V N
82273443b9eSMugunthan V N return !fdt_node_check_compatible(fdt, 0, compat);
82373443b9eSMugunthan V N }
824e4c98a59SMario Six
dev_disable_by_path(const char * path)825e4c98a59SMario Six int dev_disable_by_path(const char *path)
826e4c98a59SMario Six {
827e4c98a59SMario Six struct uclass *uc;
828e4c98a59SMario Six ofnode node = ofnode_path(path);
829e4c98a59SMario Six struct udevice *dev;
830e4c98a59SMario Six int ret = 1;
831e4c98a59SMario Six
832e4c98a59SMario Six if (!of_live_active())
833e4c98a59SMario Six return -ENOSYS;
834e4c98a59SMario Six
835e4c98a59SMario Six list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
836e4c98a59SMario Six ret = uclass_find_device_by_ofnode(uc->uc_drv->id, node, &dev);
837e4c98a59SMario Six if (!ret)
838e4c98a59SMario Six break;
839e4c98a59SMario Six }
840e4c98a59SMario Six
841e4c98a59SMario Six if (ret)
842e4c98a59SMario Six return ret;
843e4c98a59SMario Six
844e4c98a59SMario Six ret = device_remove(dev, DM_REMOVE_NORMAL);
845e4c98a59SMario Six if (ret)
846e4c98a59SMario Six return ret;
847e4c98a59SMario Six
848e4c98a59SMario Six ret = device_unbind(dev);
849e4c98a59SMario Six if (ret)
850e4c98a59SMario Six return ret;
851e4c98a59SMario Six
852e4c98a59SMario Six return ofnode_set_enabled(node, false);
853e4c98a59SMario Six }
854e4c98a59SMario Six
dev_enable_by_path(const char * path)855e4c98a59SMario Six int dev_enable_by_path(const char *path)
856e4c98a59SMario Six {
857e4c98a59SMario Six ofnode node = ofnode_path(path);
858e4c98a59SMario Six ofnode pnode = ofnode_get_parent(node);
859e4c98a59SMario Six struct udevice *parent;
860e4c98a59SMario Six int ret = 1;
861e4c98a59SMario Six
862e4c98a59SMario Six if (!of_live_active())
863e4c98a59SMario Six return -ENOSYS;
864e4c98a59SMario Six
865e4c98a59SMario Six ret = device_find_by_ofnode(pnode, &parent);
866e4c98a59SMario Six if (ret)
867e4c98a59SMario Six return ret;
868e4c98a59SMario Six
869e4c98a59SMario Six ret = ofnode_set_enabled(node, true);
870e4c98a59SMario Six if (ret)
871e4c98a59SMario Six return ret;
872e4c98a59SMario Six
8738d773c4aSBin Meng return lists_bind_fdt(parent, node, NULL, false);
874e4c98a59SMario Six }
875