X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fcore%2Fuclass.c;h=9766aeabd192f69206f5fec8bb8274979aa14edb;hb=9450ab2ba8d720bd9f73bccc0af2e2b5a2c2aaf1;hp=04e939d6c13bc216ec31ae311a9ceb659d027a25;hpb=3f6dcdb9cd4dbda226a1474f1e9398413e906b41;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 04e939d..9766aea 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -1,13 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2013 Google, Inc * * (C) Copyright 2012 * Pavel Herrmann - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include #include #include #include @@ -56,9 +56,14 @@ static int uclass_add(enum uclass_id id, struct uclass **ucp) *ucp = NULL; uc_drv = lists_uclass_lookup(id); if (!uc_drv) { - dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n", - id); - return -ENOENT; + debug("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n", + id); + /* + * Use a strange error to make this case easier to find. When + * a uclass is not available it can prevent driver model from + * starting up and this failure is otherwise hard to debug. + */ + return -EPFNOSUPPORT; } uc = calloc(1, sizeof(*uc)); if (!uc) @@ -111,7 +116,7 @@ int uclass_destroy(struct uclass *uc) while (!list_empty(&uc->dev_head)) { dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node); - ret = device_remove(dev); + ret = device_remove(dev, DM_REMOVE_NORMAL); if (ret) return ret; ret = device_unbind(dev); @@ -143,6 +148,50 @@ int uclass_get(enum uclass_id id, struct uclass **ucp) return 0; } +const char *uclass_get_name(enum uclass_id id) +{ + struct uclass *uc; + + if (uclass_get(id, &uc)) + return NULL; + return uc->uc_drv->name; +} + +enum uclass_id uclass_get_by_name(const char *name) +{ + int i; + + for (i = 0; i < UCLASS_COUNT; i++) { + struct uclass_driver *uc_drv = lists_uclass_lookup(i); + + if (uc_drv && !strcmp(uc_drv->name, name)) + return i; + } + + return UCLASS_INVALID; +} + +int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp) +{ + struct udevice *iter; + struct uclass *uc = dev->uclass; + int i = 0; + + if (list_empty(&uc->dev_head)) + return -ENODEV; + + uclass_foreach_dev(iter, uc) { + if (iter == dev) { + if (ucp) + *ucp = uc; + return i; + } + i++; + } + + return -ENODEV; +} + int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) { struct uclass *uc; @@ -153,8 +202,10 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp) ret = uclass_get(id, &uc); if (ret) return ret; + if (list_empty(&uc->dev_head)) + return -ENODEV; - list_for_each_entry(dev, &uc->dev_head, uclass_node) { + uclass_foreach_dev(dev, uc) { if (!index--) { *devp = dev; return 0; @@ -208,7 +259,7 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, if (ret) return ret; - list_for_each_entry(dev, &uc->dev_head, uclass_node) { + uclass_foreach_dev(dev, uc) { if (!strncmp(dev->name, name, strlen(name))) { *devp = dev; return 0; @@ -233,8 +284,8 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, if (ret) return ret; - list_for_each_entry(dev, &uc->dev_head, uclass_node) { - debug(" - %d %d\n", dev->req_seq, dev->seq); + uclass_foreach_dev(dev, uc) { + debug(" - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name); if ((find_req_seq ? dev->req_seq : dev->seq) == seq_or_req_seq) { *devp = dev; @@ -247,8 +298,8 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq, return -ENODEV; } -static int uclass_find_device_by_of_offset(enum uclass_id id, int node, - struct udevice **devp) +int uclass_find_device_by_of_offset(enum uclass_id id, int node, + struct udevice **devp) { struct uclass *uc; struct udevice *dev; @@ -261,8 +312,70 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node, if (ret) return ret; - list_for_each_entry(dev, &uc->dev_head, uclass_node) { - if (dev->of_offset == node) { + uclass_foreach_dev(dev, uc) { + if (dev_of_offset(dev) == node) { + *devp = dev; + return 0; + } + } + + return -ENODEV; +} + +int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node, + struct udevice **devp) +{ + struct uclass *uc; + struct udevice *dev; + int ret; + + log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node)); + *devp = NULL; + if (!ofnode_valid(node)) + return -ENODEV; + ret = uclass_get(id, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n", + dev->name); + if (ofnode_equal(dev_ofnode(dev), node)) { + *devp = dev; + goto done; + } + } + ret = -ENODEV; + +done: + log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n", + ofnode_get_name(node), *devp ? (*devp)->name : "(none)", ret); + return ret; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent, + const char *name, struct udevice **devp) +{ + struct udevice *dev; + struct uclass *uc; + int find_phandle; + int ret; + + *devp = NULL; + find_phandle = dev_read_u32_default(parent, name, -1); + if (find_phandle <= 0) + return -ENOENT; + ret = uclass_get(id, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + uint phandle; + + phandle = dev_read_phandle(dev); + + if (phandle == find_phandle) { *devp = dev; return 0; } @@ -270,13 +383,34 @@ static int uclass_find_device_by_of_offset(enum uclass_id id, int node, return -ENODEV; } +#endif + +int uclass_get_device_by_driver(enum uclass_id id, + const struct driver *find_drv, + struct udevice **devp) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + ret = uclass_get(id, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + if (dev->driver == find_drv) + return uclass_get_device_tail(dev, 0, devp); + } + + return -ENODEV; +} -int uclass_get_device_tail(struct udevice *dev, int ret, - struct udevice **devp) +int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp) { if (ret) return ret; + assert(dev); ret = device_probe(dev); if (ret) return ret; @@ -335,6 +469,60 @@ int uclass_get_device_by_of_offset(enum uclass_id id, int node, return uclass_get_device_tail(dev, ret, devp); } +int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + log(LOGC_DM, LOGL_DEBUG, "Looking for %s\n", ofnode_get_name(node)); + *devp = NULL; + ret = uclass_find_device_by_ofnode(id, node, &dev); + log(LOGC_DM, LOGL_DEBUG, " - result for %s: %s (ret=%d)\n", + ofnode_get_name(node), dev ? dev->name : "(none)", ret); + + return uclass_get_device_tail(dev, ret, devp); +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id, + struct udevice **devp) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + *devp = NULL; + ret = uclass_get(id, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + uint phandle; + + phandle = dev_read_phandle(dev); + + if (phandle == phandle_id) { + *devp = dev; + return uclass_get_device_tail(dev, ret, devp); + } + } + + return -ENODEV; +} + +int uclass_get_device_by_phandle(enum uclass_id id, struct udevice *parent, + const char *name, struct udevice **devp) +{ + struct udevice *dev; + int ret; + + *devp = NULL; + ret = uclass_find_device_by_phandle(id, parent, name, &dev); + return uclass_get_device_tail(dev, ret, devp); +} +#endif + int uclass_first_device(enum uclass_id id, struct udevice **devp) { struct udevice *dev; @@ -342,9 +530,24 @@ int uclass_first_device(enum uclass_id id, struct udevice **devp) *devp = NULL; ret = uclass_find_first_device(id, &dev); + if (!dev) + return 0; return uclass_get_device_tail(dev, ret, devp); } +int uclass_first_device_err(enum uclass_id id, struct udevice **devp) +{ + int ret; + + ret = uclass_first_device(id, devp); + if (ret) + return ret; + else if (!*devp) + return -ENODEV; + + return 0; +} + int uclass_next_device(struct udevice **devp) { struct udevice *dev = *devp; @@ -352,9 +555,51 @@ int uclass_next_device(struct udevice **devp) *devp = NULL; ret = uclass_find_next_device(&dev); + if (!dev) + return 0; return uclass_get_device_tail(dev, ret, devp); } +int uclass_next_device_err(struct udevice **devp) +{ + int ret; + + ret = uclass_next_device(devp); + if (ret) + return ret; + else if (!*devp) + return -ENODEV; + + return 0; +} + +int uclass_first_device_check(enum uclass_id id, struct udevice **devp) +{ + int ret; + + *devp = NULL; + ret = uclass_find_first_device(id, devp); + if (ret) + return ret; + if (!*devp) + return 0; + + return device_probe(*devp); +} + +int uclass_next_device_check(struct udevice **devp) +{ + int ret; + + ret = uclass_find_next_device(devp); + if (ret) + return ret; + if (!*devp) + return 0; + + return device_probe(*devp); +} + int uclass_bind_device(struct udevice *dev) { struct uclass *uc; @@ -372,11 +617,6 @@ int uclass_bind_device(struct udevice *dev) goto err; } } - if (uc->uc_drv->post_bind) { - ret = uc->uc_drv->post_bind(dev); - if (ret) - goto err; - } return 0; err: @@ -386,7 +626,7 @@ err: return ret; } -#ifdef CONFIG_DM_DEVICE_REMOVE +#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) int uclass_unbind_device(struct udevice *dev) { struct uclass *uc; @@ -458,33 +698,37 @@ int uclass_pre_probe_device(struct udevice *dev) int uclass_post_probe_device(struct udevice *dev) { - struct uclass_driver *uc_drv = dev->uclass->uc_drv; + struct uclass_driver *uc_drv; + int ret; + + if (dev->parent) { + uc_drv = dev->parent->uclass->uc_drv; + if (uc_drv->child_post_probe) { + ret = uc_drv->child_post_probe(dev); + if (ret) + return ret; + } + } + uc_drv = dev->uclass->uc_drv; if (uc_drv->post_probe) return uc_drv->post_probe(dev); return 0; } -#ifdef CONFIG_DM_DEVICE_REMOVE +#if CONFIG_IS_ENABLED(DM_DEVICE_REMOVE) int uclass_pre_remove_device(struct udevice *dev) { - struct uclass_driver *uc_drv; struct uclass *uc; int ret; uc = dev->uclass; - uc_drv = uc->uc_drv; if (uc->uc_drv->pre_remove) { ret = uc->uc_drv->pre_remove(dev); if (ret) return ret; } - if (uc_drv->per_device_auto_alloc_size) { - free(dev->uclass_priv); - dev->uclass_priv = NULL; - } - dev->seq = -1; return 0; }