Commit 6494d708bfc630ac0585d5a81707442ebf578eac

Authored by Simon Glass
Committed by Tom Rini
1 parent 65c70539e5

dm: Add base driver model support

Add driver model functionality for generic board.

This includes data structures and base code for registering devices and
uclasses (groups of devices with the same purpose, e.g. all I2C ports will
be in the same uclass).

The feature is enabled with CONFIG_DM.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Marek Vasut <marex@denx.de>
Signed-off-by: Pavel Herrmann <morpheus.ibis@gmail.com>
Signed-off-by: Viktor Křivák <viktor.krivak@gmail.com>
Signed-off-by: Tomas Hlavacek <tmshlvck@gmail.com>

Showing 18 changed files with 1601 additions and 0 deletions Side-by-side Diff

... ... @@ -591,6 +591,7 @@
591 591 libs-y += net/
592 592 libs-y += disk/
593 593 libs-y += drivers/
  594 +libs-$(CONFIG_DM) += drivers/core/
594 595 libs-y += drivers/dma/
595 596 libs-y += drivers/gpio/
596 597 libs-y += drivers/i2c/
drivers/core/Makefile
  1 +#
  2 +# Copyright (c) 2013 Google, Inc
  3 +#
  4 +# SPDX-License-Identifier: GPL-2.0+
  5 +#
  6 +
  7 +obj-$(CONFIG_DM) := device.o lists.o root.o uclass.o util.o
drivers/core/device.c
  1 +/*
  2 + * Device manager
  3 + *
  4 + * Copyright (c) 2013 Google, Inc
  5 + *
  6 + * (C) Copyright 2012
  7 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  8 + *
  9 + * SPDX-License-Identifier: GPL-2.0+
  10 + */
  11 +
  12 +#include <common.h>
  13 +#include <malloc.h>
  14 +#include <dm/device.h>
  15 +#include <dm/device-internal.h>
  16 +#include <dm/lists.h>
  17 +#include <dm/platdata.h>
  18 +#include <dm/uclass.h>
  19 +#include <dm/uclass-internal.h>
  20 +#include <dm/util.h>
  21 +#include <linux/err.h>
  22 +#include <linux/list.h>
  23 +
  24 +/**
  25 + * device_chld_unbind() - Unbind all device's children from the device
  26 + *
  27 + * On error, the function continues to unbind all children, and reports the
  28 + * first error.
  29 + *
  30 + * @dev: The device that is to be stripped of its children
  31 + * @return 0 on success, -ve on error
  32 + */
  33 +static int device_chld_unbind(struct device *dev)
  34 +{
  35 + struct device *pos, *n;
  36 + int ret, saved_ret = 0;
  37 +
  38 + assert(dev);
  39 +
  40 + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  41 + ret = device_unbind(pos);
  42 + if (ret && !saved_ret)
  43 + saved_ret = ret;
  44 + }
  45 +
  46 + return saved_ret;
  47 +}
  48 +
  49 +/**
  50 + * device_chld_remove() - Stop all device's children
  51 + * @dev: The device whose children are to be removed
  52 + * @return 0 on success, -ve on error
  53 + */
  54 +static int device_chld_remove(struct device *dev)
  55 +{
  56 + struct device *pos, *n;
  57 + int ret;
  58 +
  59 + assert(dev);
  60 +
  61 + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) {
  62 + ret = device_remove(pos);
  63 + if (ret)
  64 + return ret;
  65 + }
  66 +
  67 + return 0;
  68 +}
  69 +
  70 +int device_bind(struct device *parent, struct driver *drv, const char *name,
  71 + void *platdata, int of_offset, struct device **devp)
  72 +{
  73 + struct device *dev;
  74 + struct uclass *uc;
  75 + int ret = 0;
  76 +
  77 + *devp = NULL;
  78 + if (!name)
  79 + return -EINVAL;
  80 +
  81 + ret = uclass_get(drv->id, &uc);
  82 + if (ret)
  83 + return ret;
  84 +
  85 + dev = calloc(1, sizeof(struct device));
  86 + if (!dev)
  87 + return -ENOMEM;
  88 +
  89 + INIT_LIST_HEAD(&dev->sibling_node);
  90 + INIT_LIST_HEAD(&dev->child_head);
  91 + INIT_LIST_HEAD(&dev->uclass_node);
  92 + dev->platdata = platdata;
  93 + dev->name = name;
  94 + dev->of_offset = of_offset;
  95 + dev->parent = parent;
  96 + dev->driver = drv;
  97 + dev->uclass = uc;
  98 + if (!dev->platdata && drv->platdata_auto_alloc_size)
  99 + dev->flags |= DM_FLAG_ALLOC_PDATA;
  100 +
  101 + /* put dev into parent's successor list */
  102 + if (parent)
  103 + list_add_tail(&dev->sibling_node, &parent->child_head);
  104 +
  105 + ret = uclass_bind_device(dev);
  106 + if (ret)
  107 + goto fail_bind;
  108 +
  109 + /* if we fail to bind we remove device from successors and free it */
  110 + if (drv->bind) {
  111 + ret = drv->bind(dev);
  112 + if (ret) {
  113 + if (uclass_unbind_device(dev)) {
  114 + dm_warn("Failed to unbind dev '%s' on error path\n",
  115 + dev->name);
  116 + }
  117 + goto fail_bind;
  118 + }
  119 + }
  120 + if (parent)
  121 + dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
  122 + *devp = dev;
  123 +
  124 + return 0;
  125 +
  126 +fail_bind:
  127 + list_del(&dev->sibling_node);
  128 + free(dev);
  129 + return ret;
  130 +}
  131 +
  132 +int device_bind_by_name(struct device *parent, const struct driver_info *info,
  133 + struct device **devp)
  134 +{
  135 + struct driver *drv;
  136 +
  137 + drv = lists_driver_lookup_name(info->name);
  138 + if (!drv)
  139 + return -ENOENT;
  140 +
  141 + return device_bind(parent, drv, info->name, (void *)info->platdata,
  142 + -1, devp);
  143 +}
  144 +
  145 +int device_unbind(struct device *dev)
  146 +{
  147 + struct driver *drv;
  148 + int ret;
  149 +
  150 + if (!dev)
  151 + return -EINVAL;
  152 +
  153 + if (dev->flags & DM_FLAG_ACTIVATED)
  154 + return -EINVAL;
  155 +
  156 + drv = dev->driver;
  157 + assert(drv);
  158 +
  159 + if (drv->unbind) {
  160 + ret = drv->unbind(dev);
  161 + if (ret)
  162 + return ret;
  163 + }
  164 +
  165 + ret = device_chld_unbind(dev);
  166 + if (ret)
  167 + return ret;
  168 +
  169 + ret = uclass_unbind_device(dev);
  170 + if (ret)
  171 + return ret;
  172 +
  173 + if (dev->parent)
  174 + list_del(&dev->sibling_node);
  175 + free(dev);
  176 +
  177 + return 0;
  178 +}
  179 +
  180 +/**
  181 + * device_free() - Free memory buffers allocated by a device
  182 + * @dev: Device that is to be started
  183 + */
  184 +static void device_free(struct device *dev)
  185 +{
  186 + int size;
  187 +
  188 + if (dev->driver->priv_auto_alloc_size) {
  189 + free(dev->priv);
  190 + dev->priv = NULL;
  191 + }
  192 + if (dev->flags & DM_FLAG_ALLOC_PDATA) {
  193 + free(dev->platdata);
  194 + dev->platdata = NULL;
  195 + }
  196 + size = dev->uclass->uc_drv->per_device_auto_alloc_size;
  197 + if (size) {
  198 + free(dev->uclass_priv);
  199 + dev->uclass_priv = NULL;
  200 + }
  201 +}
  202 +
  203 +int device_probe(struct device *dev)
  204 +{
  205 + struct driver *drv;
  206 + int size = 0;
  207 + int ret;
  208 +
  209 + if (!dev)
  210 + return -EINVAL;
  211 +
  212 + if (dev->flags & DM_FLAG_ACTIVATED)
  213 + return 0;
  214 +
  215 + drv = dev->driver;
  216 + assert(drv);
  217 +
  218 + /* Allocate private data and platdata if requested */
  219 + if (drv->priv_auto_alloc_size) {
  220 + dev->priv = calloc(1, drv->priv_auto_alloc_size);
  221 + if (!dev->priv) {
  222 + ret = -ENOMEM;
  223 + goto fail;
  224 + }
  225 + }
  226 + /* Allocate private data if requested */
  227 + if (dev->flags & DM_FLAG_ALLOC_PDATA) {
  228 + dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
  229 + if (!dev->platdata) {
  230 + ret = -ENOMEM;
  231 + goto fail;
  232 + }
  233 + }
  234 + size = dev->uclass->uc_drv->per_device_auto_alloc_size;
  235 + if (size) {
  236 + dev->uclass_priv = calloc(1, size);
  237 + if (!dev->uclass_priv) {
  238 + ret = -ENOMEM;
  239 + goto fail;
  240 + }
  241 + }
  242 +
  243 + /* Ensure all parents are probed */
  244 + if (dev->parent) {
  245 + ret = device_probe(dev->parent);
  246 + if (ret)
  247 + goto fail;
  248 + }
  249 +
  250 + if (drv->ofdata_to_platdata && dev->of_offset >= 0) {
  251 + ret = drv->ofdata_to_platdata(dev);
  252 + if (ret)
  253 + goto fail;
  254 + }
  255 +
  256 + if (drv->probe) {
  257 + ret = drv->probe(dev);
  258 + if (ret)
  259 + goto fail;
  260 + }
  261 +
  262 + dev->flags |= DM_FLAG_ACTIVATED;
  263 +
  264 + ret = uclass_post_probe_device(dev);
  265 + if (ret) {
  266 + dev->flags &= ~DM_FLAG_ACTIVATED;
  267 + goto fail_uclass;
  268 + }
  269 +
  270 + return 0;
  271 +fail_uclass:
  272 + if (device_remove(dev)) {
  273 + dm_warn("%s: Device '%s' failed to remove on error path\n",
  274 + __func__, dev->name);
  275 + }
  276 +fail:
  277 + device_free(dev);
  278 +
  279 + return ret;
  280 +}
  281 +
  282 +int device_remove(struct device *dev)
  283 +{
  284 + struct driver *drv;
  285 + int ret;
  286 +
  287 + if (!dev)
  288 + return -EINVAL;
  289 +
  290 + if (!(dev->flags & DM_FLAG_ACTIVATED))
  291 + return 0;
  292 +
  293 + drv = dev->driver;
  294 + assert(drv);
  295 +
  296 + ret = uclass_pre_remove_device(dev);
  297 + if (ret)
  298 + return ret;
  299 +
  300 + ret = device_chld_remove(dev);
  301 + if (ret)
  302 + goto err;
  303 +
  304 + if (drv->remove) {
  305 + ret = drv->remove(dev);
  306 + if (ret)
  307 + goto err_remove;
  308 + }
  309 +
  310 + device_free(dev);
  311 +
  312 + dev->flags &= ~DM_FLAG_ACTIVATED;
  313 +
  314 + return 0;
  315 +
  316 +err_remove:
  317 + /* We can't put the children back */
  318 + dm_warn("%s: Device '%s' failed to remove, but children are gone\n",
  319 + __func__, dev->name);
  320 +err:
  321 + ret = uclass_post_probe_device(dev);
  322 + if (ret) {
  323 + dm_warn("%s: Device '%s' failed to post_probe on error path\n",
  324 + __func__, dev->name);
  325 + }
  326 +
  327 + return ret;
  328 +}
  329 +
  330 +void *dev_get_platdata(struct device *dev)
  331 +{
  332 + if (!dev) {
  333 + dm_warn("%s: null device", __func__);
  334 + return NULL;
  335 + }
  336 +
  337 + return dev->platdata;
  338 +}
  339 +
  340 +void *dev_get_priv(struct device *dev)
  341 +{
  342 + if (!dev) {
  343 + dm_warn("%s: null device", __func__);
  344 + return NULL;
  345 + }
  346 +
  347 + return dev->priv;
  348 +}
drivers/core/lists.c
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Marek Vasut <marex@denx.de>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#include <common.h>
  11 +#include <errno.h>
  12 +#include <dm/device.h>
  13 +#include <dm/device-internal.h>
  14 +#include <dm/platdata.h>
  15 +#include <dm/uclass.h>
  16 +#include <dm/util.h>
  17 +#include <linux/compiler.h>
  18 +
  19 +struct driver *lists_driver_lookup_name(const char *name)
  20 +{
  21 + struct driver *drv =
  22 + ll_entry_start(struct driver, driver);
  23 + const int n_ents = ll_entry_count(struct driver, driver);
  24 + struct driver *entry;
  25 + int len;
  26 +
  27 + if (!drv || !n_ents)
  28 + return NULL;
  29 +
  30 + len = strlen(name);
  31 +
  32 + for (entry = drv; entry != drv + n_ents; entry++) {
  33 + if (strncmp(name, entry->name, len))
  34 + continue;
  35 +
  36 + /* Full match */
  37 + if (len == strlen(entry->name))
  38 + return entry;
  39 + }
  40 +
  41 + /* Not found */
  42 + return NULL;
  43 +}
  44 +
  45 +struct uclass_driver *lists_uclass_lookup(enum uclass_id id)
  46 +{
  47 + struct uclass_driver *uclass =
  48 + ll_entry_start(struct uclass_driver, uclass);
  49 + const int n_ents = ll_entry_count(struct uclass_driver, uclass);
  50 + struct uclass_driver *entry;
  51 +
  52 + if ((id == UCLASS_INVALID) || !uclass)
  53 + return NULL;
  54 +
  55 + for (entry = uclass; entry != uclass + n_ents; entry++) {
  56 + if (entry->id == id)
  57 + return entry;
  58 + }
  59 +
  60 + return NULL;
  61 +}
  62 +
  63 +int lists_bind_drivers(struct device *parent)
  64 +{
  65 + struct driver_info *info =
  66 + ll_entry_start(struct driver_info, driver_info);
  67 + const int n_ents = ll_entry_count(struct driver_info, driver_info);
  68 + struct driver_info *entry;
  69 + struct device *dev;
  70 + int result = 0;
  71 + int ret;
  72 +
  73 + for (entry = info; entry != info + n_ents; entry++) {
  74 + ret = device_bind_by_name(parent, entry, &dev);
  75 + if (ret) {
  76 + dm_warn("No match for driver '%s'\n", entry->name);
  77 + if (!result || ret != -ENOENT)
  78 + result = ret;
  79 + }
  80 + }
  81 +
  82 + return result;
  83 +}
  84 +
  85 +#ifdef CONFIG_OF_CONTROL
  86 +/**
  87 + * driver_check_compatible() - Check if a driver is compatible with this node
  88 + *
  89 + * @param blob: Device tree pointer
  90 + * @param offset: Offset of node in device tree
  91 + * @param of_matchL List of compatible strings to match
  92 + * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node
  93 + * does not have a compatible string, other error <0 if there is a device
  94 + * tree error
  95 + */
  96 +static int driver_check_compatible(const void *blob, int offset,
  97 + const struct device_id *of_match)
  98 +{
  99 + int ret;
  100 +
  101 + if (!of_match)
  102 + return -ENOENT;
  103 +
  104 + while (of_match->compatible) {
  105 + ret = fdt_node_check_compatible(blob, offset,
  106 + of_match->compatible);
  107 + if (!ret)
  108 + return 0;
  109 + else if (ret == -FDT_ERR_NOTFOUND)
  110 + return -ENODEV;
  111 + else if (ret < 0)
  112 + return -EINVAL;
  113 + of_match++;
  114 + }
  115 +
  116 + return -ENOENT;
  117 +}
  118 +
  119 +int lists_bind_fdt(struct device *parent, const void *blob, int offset)
  120 +{
  121 + struct driver *driver = ll_entry_start(struct driver, driver);
  122 + const int n_ents = ll_entry_count(struct driver, driver);
  123 + struct driver *entry;
  124 + struct device *dev;
  125 + const char *name;
  126 + int result = 0;
  127 + int ret;
  128 +
  129 + dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
  130 + for (entry = driver; entry != driver + n_ents; entry++) {
  131 + ret = driver_check_compatible(blob, offset, entry->of_match);
  132 + if (ret == -ENOENT) {
  133 + continue;
  134 + } else if (ret == -ENODEV) {
  135 + break;
  136 + } else if (ret) {
  137 + dm_warn("Device tree error at offset %d\n", offset);
  138 + if (!result || ret != -ENOENT)
  139 + result = ret;
  140 + break;
  141 + }
  142 +
  143 + name = fdt_get_name(blob, offset, NULL);
  144 + dm_dbg(" - found match at '%s'\n", entry->name);
  145 + ret = device_bind(parent, entry, name, NULL, offset, &dev);
  146 + if (ret) {
  147 + dm_warn("No match for driver '%s'\n", entry->name);
  148 + if (!result || ret != -ENOENT)
  149 + result = ret;
  150 + }
  151 + }
  152 +
  153 + return result;
  154 +}
  155 +#endif
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#include <common.h>
  11 +#include <errno.h>
  12 +#include <malloc.h>
  13 +#include <dm/device.h>
  14 +#include <dm/device-internal.h>
  15 +#include <dm/lists.h>
  16 +#include <dm/platdata.h>
  17 +#include <dm/uclass.h>
  18 +#include <dm/util.h>
  19 +#include <linux/list.h>
  20 +
  21 +DECLARE_GLOBAL_DATA_PTR;
  22 +
  23 +static const struct driver_info root_info = {
  24 + .name = "root_driver",
  25 +};
  26 +
  27 +struct device *dm_root(void)
  28 +{
  29 + if (!gd->dm_root) {
  30 + dm_warn("Virtual root driver does not exist!\n");
  31 + return NULL;
  32 + }
  33 +
  34 + return gd->dm_root;
  35 +}
  36 +
  37 +int dm_init(void)
  38 +{
  39 + int ret;
  40 +
  41 + if (gd->dm_root) {
  42 + dm_warn("Virtual root driver already exists!\n");
  43 + return -EINVAL;
  44 + }
  45 + INIT_LIST_HEAD(&gd->uclass_root);
  46 +
  47 + ret = device_bind_by_name(NULL, &root_info, &gd->dm_root);
  48 + if (ret)
  49 + return ret;
  50 +
  51 + return 0;
  52 +}
  53 +
  54 +int dm_scan_platdata(void)
  55 +{
  56 + int ret;
  57 +
  58 + ret = lists_bind_drivers(gd->dm_root);
  59 + if (ret == -ENOENT) {
  60 + dm_warn("Some drivers were not found\n");
  61 + ret = 0;
  62 + }
  63 + if (ret)
  64 + return ret;
  65 +
  66 + return 0;
  67 +}
  68 +
  69 +#ifdef CONFIG_OF_CONTROL
  70 +int dm_scan_fdt(const void *blob)
  71 +{
  72 + int offset = 0;
  73 + int ret = 0, err;
  74 + int depth = 0;
  75 +
  76 + do {
  77 + offset = fdt_next_node(blob, offset, &depth);
  78 + if (offset > 0 && depth == 1) {
  79 + err = lists_bind_fdt(gd->dm_root, blob, offset);
  80 + if (err && !ret)
  81 + ret = err;
  82 + }
  83 + } while (offset > 0);
  84 +
  85 + if (ret)
  86 + dm_warn("Some drivers failed to bind\n");
  87 +
  88 + return ret;
  89 +}
  90 +#endif
  91 +
  92 +/* This is the root driver - all drivers are children of this */
  93 +U_BOOT_DRIVER(root_driver) = {
  94 + .name = "root_driver",
  95 + .id = UCLASS_ROOT,
  96 +};
  97 +
  98 +/* This is the root uclass */
  99 +UCLASS_DRIVER(root) = {
  100 + .name = "root",
  101 + .id = UCLASS_ROOT,
  102 +};
drivers/core/uclass.c
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#include <common.h>
  11 +#include <errno.h>
  12 +#include <malloc.h>
  13 +#include <dm/device.h>
  14 +#include <dm/device-internal.h>
  15 +#include <dm/lists.h>
  16 +#include <dm/uclass.h>
  17 +#include <dm/uclass-internal.h>
  18 +#include <dm/util.h>
  19 +
  20 +DECLARE_GLOBAL_DATA_PTR;
  21 +
  22 +struct uclass *uclass_find(enum uclass_id key)
  23 +{
  24 + struct uclass *uc;
  25 +
  26 + /*
  27 + * TODO(sjg@chromium.org): Optimise this, perhaps moving the found
  28 + * node to the start of the list, or creating a linear array mapping
  29 + * id to node.
  30 + */
  31 + list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
  32 + if (uc->uc_drv->id == key)
  33 + return uc;
  34 + }
  35 +
  36 + return NULL;
  37 +}
  38 +
  39 +/**
  40 + * uclass_add() - Create new uclass in list
  41 + * @id: Id number to create
  42 + * @ucp: Returns pointer to uclass, or NULL on error
  43 + * @return 0 on success, -ve on error
  44 + *
  45 + * The new uclass is added to the list. There must be only one uclass for
  46 + * each id.
  47 + */
  48 +static int uclass_add(enum uclass_id id, struct uclass **ucp)
  49 +{
  50 + struct uclass_driver *uc_drv;
  51 + struct uclass *uc;
  52 + int ret;
  53 +
  54 + *ucp = NULL;
  55 + uc_drv = lists_uclass_lookup(id);
  56 + if (!uc_drv) {
  57 + dm_warn("Cannot find uclass for id %d: please add the UCLASS_DRIVER() declaration for this UCLASS_... id\n",
  58 + id);
  59 + return -ENOENT;
  60 + }
  61 + if (uc_drv->ops) {
  62 + dm_warn("No ops for uclass id %d\n", id);
  63 + return -EINVAL;
  64 + }
  65 + uc = calloc(1, sizeof(*uc));
  66 + if (!uc)
  67 + return -ENOMEM;
  68 + if (uc_drv->priv_auto_alloc_size) {
  69 + uc->priv = calloc(1, uc_drv->priv_auto_alloc_size);
  70 + if (!uc->priv) {
  71 + ret = -ENOMEM;
  72 + goto fail_mem;
  73 + }
  74 + }
  75 + uc->uc_drv = uc_drv;
  76 + INIT_LIST_HEAD(&uc->sibling_node);
  77 + INIT_LIST_HEAD(&uc->dev_head);
  78 + list_add(&uc->sibling_node, &gd->uclass_root);
  79 +
  80 + if (uc_drv->init) {
  81 + ret = uc_drv->init(uc);
  82 + if (ret)
  83 + goto fail;
  84 + }
  85 +
  86 + *ucp = uc;
  87 +
  88 + return 0;
  89 +fail:
  90 + if (uc_drv->priv_auto_alloc_size) {
  91 + free(uc->priv);
  92 + uc->priv = NULL;
  93 + }
  94 + list_del(&uc->sibling_node);
  95 +fail_mem:
  96 + free(uc);
  97 +
  98 + return ret;
  99 +}
  100 +
  101 +int uclass_destroy(struct uclass *uc)
  102 +{
  103 + struct uclass_driver *uc_drv;
  104 + struct device *dev, *tmp;
  105 + int ret;
  106 +
  107 + list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) {
  108 + ret = device_remove(dev);
  109 + if (ret)
  110 + return ret;
  111 + ret = device_unbind(dev);
  112 + if (ret)
  113 + return ret;
  114 + }
  115 +
  116 + uc_drv = uc->uc_drv;
  117 + if (uc_drv->destroy)
  118 + uc_drv->destroy(uc);
  119 + list_del(&uc->sibling_node);
  120 + if (uc_drv->priv_auto_alloc_size)
  121 + free(uc->priv);
  122 + free(uc);
  123 +
  124 + return 0;
  125 +}
  126 +
  127 +int uclass_get(enum uclass_id id, struct uclass **ucp)
  128 +{
  129 + struct uclass *uc;
  130 +
  131 + *ucp = NULL;
  132 + uc = uclass_find(id);
  133 + if (!uc)
  134 + return uclass_add(id, ucp);
  135 + *ucp = uc;
  136 +
  137 + return 0;
  138 +}
  139 +
  140 +int uclass_find_device(enum uclass_id id, int index, struct device **devp)
  141 +{
  142 + struct uclass *uc;
  143 + struct device *dev;
  144 + int ret;
  145 +
  146 + *devp = NULL;
  147 + ret = uclass_get(id, &uc);
  148 + if (ret)
  149 + return ret;
  150 +
  151 + list_for_each_entry(dev, &uc->dev_head, uclass_node) {
  152 + if (!index--) {
  153 + *devp = dev;
  154 + return 0;
  155 + }
  156 + }
  157 +
  158 + return -ENODEV;
  159 +}
  160 +
  161 +int uclass_get_device(enum uclass_id id, int index, struct device **devp)
  162 +{
  163 + struct device *dev;
  164 + int ret;
  165 +
  166 + *devp = NULL;
  167 + ret = uclass_find_device(id, index, &dev);
  168 + if (ret)
  169 + return ret;
  170 +
  171 + ret = device_probe(dev);
  172 + if (ret)
  173 + return ret;
  174 +
  175 + *devp = dev;
  176 +
  177 + return 0;
  178 +}
  179 +
  180 +int uclass_first_device(enum uclass_id id, struct device **devp)
  181 +{
  182 + struct uclass *uc;
  183 + struct device *dev;
  184 + int ret;
  185 +
  186 + *devp = NULL;
  187 + ret = uclass_get(id, &uc);
  188 + if (ret)
  189 + return ret;
  190 + if (list_empty(&uc->dev_head))
  191 + return 0;
  192 +
  193 + dev = list_first_entry(&uc->dev_head, struct device, uclass_node);
  194 + ret = device_probe(dev);
  195 + if (ret)
  196 + return ret;
  197 + *devp = dev;
  198 +
  199 + return 0;
  200 +}
  201 +
  202 +int uclass_next_device(struct device **devp)
  203 +{
  204 + struct device *dev = *devp;
  205 + int ret;
  206 +
  207 + *devp = NULL;
  208 + if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
  209 + return 0;
  210 +
  211 + dev = list_entry(dev->uclass_node.next, struct device, uclass_node);
  212 + ret = device_probe(dev);
  213 + if (ret)
  214 + return ret;
  215 + *devp = dev;
  216 +
  217 + return 0;
  218 +}
  219 +
  220 +int uclass_bind_device(struct device *dev)
  221 +{
  222 + struct uclass *uc;
  223 + int ret;
  224 +
  225 + uc = dev->uclass;
  226 +
  227 + list_add_tail(&dev->uclass_node, &uc->dev_head);
  228 +
  229 + if (uc->uc_drv->post_bind) {
  230 + ret = uc->uc_drv->post_bind(dev);
  231 + if (ret) {
  232 + list_del(&dev->uclass_node);
  233 + return ret;
  234 + }
  235 + }
  236 +
  237 + return 0;
  238 +}
  239 +
  240 +int uclass_unbind_device(struct device *dev)
  241 +{
  242 + struct uclass *uc;
  243 + int ret;
  244 +
  245 + uc = dev->uclass;
  246 + if (uc->uc_drv->pre_unbind) {
  247 + ret = uc->uc_drv->pre_unbind(dev);
  248 + if (ret)
  249 + return ret;
  250 + }
  251 +
  252 + list_del(&dev->uclass_node);
  253 + return 0;
  254 +}
  255 +
  256 +int uclass_post_probe_device(struct device *dev)
  257 +{
  258 + struct uclass_driver *uc_drv = dev->uclass->uc_drv;
  259 +
  260 + if (uc_drv->post_probe)
  261 + return uc_drv->post_probe(dev);
  262 +
  263 + return 0;
  264 +}
  265 +
  266 +int uclass_pre_remove_device(struct device *dev)
  267 +{
  268 + struct uclass_driver *uc_drv;
  269 + struct uclass *uc;
  270 + int ret;
  271 +
  272 + uc = dev->uclass;
  273 + uc_drv = uc->uc_drv;
  274 + if (uc->uc_drv->pre_remove) {
  275 + ret = uc->uc_drv->pre_remove(dev);
  276 + if (ret)
  277 + return ret;
  278 + }
  279 + if (uc_drv->per_device_auto_alloc_size) {
  280 + free(dev->uclass_priv);
  281 + dev->uclass_priv = NULL;
  282 + }
  283 +
  284 + return 0;
  285 +}
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <vsprintf.h>
  9 +
  10 +void dm_warn(const char *fmt, ...)
  11 +{
  12 + va_list args;
  13 +
  14 + va_start(args, fmt);
  15 + vprintf(fmt, args);
  16 + va_end(args);
  17 +}
  18 +
  19 +void dm_dbg(const char *fmt, ...)
  20 +{
  21 + va_list args;
  22 +
  23 + va_start(args, fmt);
  24 + vprintf(fmt, args);
  25 + va_end(args);
  26 +}
  27 +
  28 +int list_count_items(struct list_head *head)
  29 +{
  30 + struct list_head *node;
  31 + int count = 0;
  32 +
  33 + list_for_each(node, head)
  34 + count++;
  35 +
  36 + return count;
  37 +}
include/asm-generic/global_data.h
... ... @@ -21,6 +21,8 @@
21 21 */
22 22  
23 23 #ifndef __ASSEMBLY__
  24 +#include <linux/list.h>
  25 +
24 26 typedef struct global_data {
25 27 bd_t *bd;
26 28 unsigned long flags;
... ... @@ -61,6 +63,12 @@
61 63 unsigned long start_addr_sp; /* start_addr_stackpointer */
62 64 unsigned long reloc_off;
63 65 struct global_data *new_gd; /* relocated global data */
  66 +
  67 +#ifdef CONFIG_DM
  68 + struct device *dm_root; /* Root instance for Driver Model */
  69 + struct list_head uclass_root; /* Head of core tree */
  70 +#endif
  71 +
64 72 const void *fdt_blob; /* Our device tree, NULL if none */
65 73 void *new_fdt; /* Relocated FDT */
66 74 unsigned long fdt_size; /* Space reserved for relocated FDT */
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#ifndef _DM_H_
  8 +#define _DM_H
  9 +
  10 +#include <dm/device.h>
  11 +#include <dm/platdata.h>
  12 +#include <dm/uclass.h>
  13 +
  14 +#endif
include/dm/device-internal.h
  1 +/*
  2 + * Copyright (C) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + * Marek Vasut <marex@denx.de>
  7 + *
  8 + * SPDX-License-Identifier: GPL-2.0+
  9 + */
  10 +
  11 +#ifndef _DM_DEVICE_INTERNAL_H
  12 +#define _DM_DEVICE_INTERNAL_H
  13 +
  14 +struct device;
  15 +
  16 +/**
  17 + * device_bind() - Create a device and bind it to a driver
  18 + *
  19 + * Called to set up a new device attached to a driver. The device will either
  20 + * have platdata, or a device tree node which can be used to create the
  21 + * platdata.
  22 + *
  23 + * Once bound a device exists but is not yet active until device_probe() is
  24 + * called.
  25 + *
  26 + * @parent: Pointer to device's parent, under which this driver will exist
  27 + * @drv: Device's driver
  28 + * @name: Name of device (e.g. device tree node name)
  29 + * @platdata: Pointer to data for this device - the structure is device-
  30 + * specific but may include the device's I/O address, etc.. This is NULL for
  31 + * devices which use device tree.
  32 + * @of_offset: Offset of device tree node for this device. This is -1 for
  33 + * devices which don't use device tree.
  34 + * @devp: Returns a pointer to the bound device
  35 + * @return 0 if OK, -ve on error
  36 + */
  37 +int device_bind(struct device *parent, struct driver *drv,
  38 + const char *name, void *platdata, int of_offset,
  39 + struct device **devp);
  40 +
  41 +/**
  42 + * device_bind_by_name: Create a device and bind it to a driver
  43 + *
  44 + * This is a helper function used to bind devices which do not use device
  45 + * tree.
  46 + *
  47 + * @parent: Pointer to device's parent
  48 + * @info: Name and platdata for this device
  49 + * @devp: Returns a pointer to the bound device
  50 + * @return 0 if OK, -ve on error
  51 + */
  52 +int device_bind_by_name(struct device *parent, const struct driver_info *info,
  53 + struct device **devp);
  54 +
  55 +/**
  56 + * device_probe() - Probe a device, activating it
  57 + *
  58 + * Activate a device so that it is ready for use. All its parents are probed
  59 + * first.
  60 + *
  61 + * @dev: Pointer to device to probe
  62 + * @return 0 if OK, -ve on error
  63 + */
  64 +int device_probe(struct device *dev);
  65 +
  66 +/**
  67 + * device_remove() - Remove a device, de-activating it
  68 + *
  69 + * De-activate a device so that it is no longer ready for use. All its
  70 + * children are deactivated first.
  71 + *
  72 + * @dev: Pointer to device to remove
  73 + * @return 0 if OK, -ve on error (an error here is normally a very bad thing)
  74 + */
  75 +int device_remove(struct device *dev);
  76 +
  77 +/**
  78 + * device_unbind() - Unbind a device, destroying it
  79 + *
  80 + * Unbind a device and remove all memory used by it
  81 + *
  82 + * @dev: Pointer to device to unbind
  83 + * @return 0 if OK, -ve on error
  84 + */
  85 +int device_unbind(struct device *dev);
  86 +
  87 +#endif
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + * Marek Vasut <marex@denx.de>
  7 + *
  8 + * SPDX-License-Identifier: GPL-2.0+
  9 + */
  10 +
  11 +#ifndef _DM_DEVICE_H
  12 +#define _DM_DEVICE_H
  13 +
  14 +#include <dm/uclass-id.h>
  15 +#include <linker_lists.h>
  16 +#include <linux/list.h>
  17 +
  18 +struct driver_info;
  19 +
  20 +/* Driver is active (probed). Cleared when it is removed */
  21 +#define DM_FLAG_ACTIVATED (1 << 0)
  22 +
  23 +/* DM is responsible for allocating and freeing platdata */
  24 +#define DM_FLAG_ALLOC_PDATA (2 << 0)
  25 +
  26 +/**
  27 + * struct device - An instance of a driver
  28 + *
  29 + * This holds information about a device, which is a driver bound to a
  30 + * particular port or peripheral (essentially a driver instance).
  31 + *
  32 + * A device will come into existence through a 'bind' call, either due to
  33 + * a U_BOOT_DEVICE() macro (in which case platdata is non-NULL) or a node
  34 + * in the device tree (in which case of_offset is >= 0). In the latter case
  35 + * we translate the device tree information into platdata in a function
  36 + * implemented by the driver ofdata_to_platdata method (called just before the
  37 + * probe method if the device has a device tree node.
  38 + *
  39 + * All three of platdata, priv and uclass_priv can be allocated by the
  40 + * driver, or you can use the auto_alloc_size members of struct driver and
  41 + * struct uclass_driver to have driver model do this automatically.
  42 + *
  43 + * @driver: The driver used by this device
  44 + * @name: Name of device, typically the FDT node name
  45 + * @platdata: Configuration data for this device
  46 + * @of_offset: Device tree node offset for this device (- for none)
  47 + * @parent: Parent of this device, or NULL for the top level device
  48 + * @priv: Private data for this device
  49 + * @uclass: Pointer to uclass for this device
  50 + * @uclass_priv: The uclass's private data for this device
  51 + * @uclass_node: Used by uclass to link its devices
  52 + * @child_head: List of children of this device
  53 + * @sibling_node: Next device in list of all devices
  54 + * @flags: Flags for this device DM_FLAG_...
  55 + */
  56 +struct device {
  57 + struct driver *driver;
  58 + const char *name;
  59 + void *platdata;
  60 + int of_offset;
  61 + struct device *parent;
  62 + void *priv;
  63 + struct uclass *uclass;
  64 + void *uclass_priv;
  65 + struct list_head uclass_node;
  66 + struct list_head child_head;
  67 + struct list_head sibling_node;
  68 + uint32_t flags;
  69 +};
  70 +
  71 +/* Returns the operations for a device */
  72 +#define device_get_ops(dev) (dev->driver->ops)
  73 +
  74 +/* Returns non-zero if the device is active (probed and not removed) */
  75 +#define device_active(dev) ((dev)->flags & DM_FLAG_ACTIVATED)
  76 +
  77 +/**
  78 + * struct device_id - Lists the compatible strings supported by a driver
  79 + * @compatible: Compatible string
  80 + * @data: Data for this compatible string
  81 + */
  82 +struct device_id {
  83 + const char *compatible;
  84 + ulong data;
  85 +};
  86 +
  87 +/**
  88 + * struct driver - A driver for a feature or peripheral
  89 + *
  90 + * This holds methods for setting up a new device, and also removing it.
  91 + * The device needs information to set itself up - this is provided either
  92 + * by platdata or a device tree node (which we find by looking up
  93 + * matching compatible strings with of_match).
  94 + *
  95 + * Drivers all belong to a uclass, representing a class of devices of the
  96 + * same type. Common elements of the drivers can be implemented in the uclass,
  97 + * or the uclass can provide a consistent interface to the drivers within
  98 + * it.
  99 + *
  100 + * @name: Device name
  101 + * @id: Identiies the uclass we belong to
  102 + * @of_match: List of compatible strings to match, and any identifying data
  103 + * for each.
  104 + * @bind: Called to bind a device to its driver
  105 + * @probe: Called to probe a device, i.e. activate it
  106 + * @remove: Called to remove a device, i.e. de-activate it
  107 + * @unbind: Called to unbind a device from its driver
  108 + * @ofdata_to_platdata: Called before probe to decode device tree data
  109 + * @priv_auto_alloc_size: If non-zero this is the size of the private data
  110 + * to be allocated in the device's ->priv pointer. If zero, then the driver
  111 + * is responsible for allocating any data required.
  112 + * @platdata_auto_alloc_size: If non-zero this is the size of the
  113 + * platform data to be allocated in the device's ->platdata pointer.
  114 + * This is typically only useful for device-tree-aware drivers (those with
  115 + * an of_match), since drivers which use platdata will have the data
  116 + * provided in the U_BOOT_DEVICE() instantiation.
  117 + * ops: Driver-specific operations. This is typically a list of function
  118 + * pointers defined by the driver, to implement driver functions required by
  119 + * the uclass.
  120 + */
  121 +struct driver {
  122 + char *name;
  123 + enum uclass_id id;
  124 + const struct device_id *of_match;
  125 + int (*bind)(struct device *dev);
  126 + int (*probe)(struct device *dev);
  127 + int (*remove)(struct device *dev);
  128 + int (*unbind)(struct device *dev);
  129 + int (*ofdata_to_platdata)(struct device *dev);
  130 + int priv_auto_alloc_size;
  131 + int platdata_auto_alloc_size;
  132 + const void *ops; /* driver-specific operations */
  133 +};
  134 +
  135 +/* Declare a new U-Boot driver */
  136 +#define U_BOOT_DRIVER(__name) \
  137 + ll_entry_declare(struct driver, __name, driver)
  138 +
  139 +/**
  140 + * dev_get_platdata() - Get the platform data for a device
  141 + *
  142 + * This checks that dev is not NULL, but no other checks for now
  143 + *
  144 + * @dev Device to check
  145 + * @return platform data, or NULL if none
  146 + */
  147 +void *dev_get_platdata(struct device *dev);
  148 +
  149 +/**
  150 + * dev_get_priv() - Get the private data for a device
  151 + *
  152 + * This checks that dev is not NULL, but no other checks for now
  153 + *
  154 + * @dev Device to check
  155 + * @return private data, or NULL if none
  156 + */
  157 +void *dev_get_priv(struct device *dev);
  158 +
  159 +#endif
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#ifndef _DM_LISTS_H_
  11 +#define _DM_LISTS_H_
  12 +
  13 +#include <dm/uclass-id.h>
  14 +
  15 +/**
  16 + * lists_driver_lookup_name() - Return u_boot_driver corresponding to name
  17 + *
  18 + * This function returns a pointer to a driver given its name. This is used
  19 + * for binding a driver given its name and platdata.
  20 + *
  21 + * @name: Name of driver to look up
  22 + * @return pointer to driver, or NULL if not found
  23 + */
  24 +struct driver *lists_driver_lookup_name(const char *name);
  25 +
  26 +/**
  27 + * lists_uclass_lookup() - Return uclass_driver based on ID of the class
  28 + * id: ID of the class
  29 + *
  30 + * This function returns the pointer to uclass_driver, which is the class's
  31 + * base structure based on the ID of the class. Returns NULL on error.
  32 + */
  33 +struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
  34 +
  35 +int lists_bind_drivers(struct device *parent);
  36 +
  37 +int lists_bind_fdt(struct device *parent, const void *blob, int offset);
  38 +
  39 +#endif
include/dm/platdata.h
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + * Marek Vasut <marex@denx.de>
  7 + *
  8 + * SPDX-License-Identifier: GPL-2.0+
  9 + */
  10 +
  11 +#ifndef _DM_PLATDATA_H
  12 +#define _DM_PLATDATA_H
  13 +
  14 +struct driver_info {
  15 + const char *name;
  16 + const void *platdata;
  17 +};
  18 +
  19 +#define U_BOOT_DEVICE(__name) \
  20 + ll_entry_declare(struct driver_info, __name, driver_info)
  21 +
  22 +#endif
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#ifndef _DM_ROOT_H_
  11 +#define _DM_ROOT_H_
  12 +
  13 +struct device;
  14 +
  15 +/**
  16 + * dm_root() - Return pointer to the top of the driver tree
  17 + *
  18 + * This function returns pointer to the root node of the driver tree,
  19 + *
  20 + * @return pointer to root device, or NULL if not inited yet
  21 + */
  22 +struct device *dm_root(void);
  23 +
  24 +/**
  25 + * dm_scan_platdata() - Scan all platform data and bind drivers
  26 + *
  27 + * This scans all available platdata and creates drivers for each
  28 + *
  29 + * @return 0 if OK, -ve on error
  30 + */
  31 +int dm_scan_platdata(void);
  32 +
  33 +/**
  34 + * dm_scan_fdt() - Scan the device tree and bind drivers
  35 + *
  36 + * This scans the device tree and creates a driver for each node
  37 + *
  38 + * @blob: Pointer to device tree blob
  39 + * @return 0 if OK, -ve on error
  40 + */
  41 +int dm_scan_fdt(const void *blob);
  42 +
  43 +/**
  44 + * dm_init() - Initialize Driver Model structures
  45 + *
  46 + * This function will initialize roots of driver tree and class tree.
  47 + * This needs to be called before anything uses the DM
  48 + *
  49 + * @return 0 if OK, -ve on error
  50 + */
  51 +int dm_init(void);
  52 +
  53 +#endif
include/dm/uclass-id.h
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#ifndef _DM_UCLASS_ID_H
  11 +#define _DM_UCLASS_ID_H
  12 +
  13 +/* TODO(sjg@chromium.org): this could be compile-time generated */
  14 +enum uclass_id {
  15 + /* These are used internally by driver model */
  16 + UCLASS_ROOT = 0,
  17 + UCLASS_DEMO,
  18 + UCLASS_TEST,
  19 + UCLASS_TEST_FDT,
  20 +
  21 + /* U-Boot uclasses start here */
  22 + UCLASS_GPIO,
  23 +
  24 + UCLASS_COUNT,
  25 + UCLASS_INVALID = -1,
  26 +};
  27 +
  28 +#endif
include/dm/uclass-internal.h
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#ifndef _DM_UCLASS_INTERNAL_H
  11 +#define _DM_UCLASS_INTERNAL_H
  12 +
  13 +/**
  14 + * uclass_find_device() - Return n-th child of uclass
  15 + * @id: Id number of the uclass
  16 + * @index: Position of the child in uclass's list
  17 + * #devp: Returns pointer to device, or NULL on error
  18 + *
  19 + * The device is not prepared for use - this is an internal function
  20 + *
  21 + * @return the uclass pointer of a child at the given index or
  22 + * return NULL on error.
  23 + */
  24 +int uclass_find_device(enum uclass_id id, int index, struct device **devp);
  25 +
  26 +/**
  27 + * uclass_bind_device() - Associate device with a uclass
  28 + *
  29 + * Connect the device into uclass's list of devices.
  30 + *
  31 + * @dev: Pointer to the device
  32 + * #return 0 on success, -ve on error
  33 + */
  34 +int uclass_bind_device(struct device *dev);
  35 +
  36 +/**
  37 + * uclass_unbind_device() - Deassociate device with a uclass
  38 + *
  39 + * Disconnect the device from uclass's list of devices.
  40 + *
  41 + * @dev: Pointer to the device
  42 + * #return 0 on success, -ve on error
  43 + */
  44 +int uclass_unbind_device(struct device *dev);
  45 +
  46 +/**
  47 + * uclass_post_probe_device() - Deal with a device that has just been probed
  48 + *
  49 + * Perform any post-processing of a probed device that is needed by the
  50 + * uclass.
  51 + *
  52 + * @dev: Pointer to the device
  53 + * #return 0 on success, -ve on error
  54 + */
  55 +int uclass_post_probe_device(struct device *dev);
  56 +
  57 +/**
  58 + * uclass_pre_remove_device() - Handle a device which is about to be removed
  59 + *
  60 + * Perform any pre-processing of a device that is about to be removed.
  61 + *
  62 + * @dev: Pointer to the device
  63 + * #return 0 on success, -ve on error
  64 + */
  65 +int uclass_pre_remove_device(struct device *dev);
  66 +
  67 +/**
  68 + * uclass_find() - Find uclass by its id
  69 + *
  70 + * @id: Id to serach for
  71 + * @return pointer to uclass, or NULL if not found
  72 + */
  73 +struct uclass *uclass_find(enum uclass_id key);
  74 +
  75 +/**
  76 + * uclass_destroy() - Destroy a uclass
  77 + *
  78 + * Destroy a uclass and all its devices
  79 + *
  80 + * @uc: uclass to destroy
  81 + * @return 0 on success, -ve on error
  82 + */
  83 +int uclass_destroy(struct uclass *uc);
  84 +
  85 +#endif
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * (C) Copyright 2012
  5 + * Pavel Herrmann <morpheus.ibis@gmail.com>
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0+
  8 + */
  9 +
  10 +#ifndef _DM_UCLASS_H
  11 +#define _DM_UCLASS_H
  12 +
  13 +#include <dm/uclass-id.h>
  14 +#include <linux/list.h>
  15 +
  16 +/**
  17 + * struct uclass - a U-Boot drive class, collecting together similar drivers
  18 + *
  19 + * A uclass provides an interface to a particular function, which is
  20 + * implemented by one or more drivers. Every driver belongs to a uclass even
  21 + * if it is the only driver in that uclass. An example uclass is GPIO, which
  22 + * provides the ability to change read inputs, set and clear outputs, etc.
  23 + * There may be drivers for on-chip SoC GPIO banks, I2C GPIO expanders and
  24 + * PMIC IO lines, all made available in a unified way through the uclass.
  25 + *
  26 + * @priv: Private data for this uclass
  27 + * @uc_drv: The driver for the uclass itself, not to be confused with a
  28 + * 'struct driver'
  29 + * dev_head: List of devices in this uclass (devices are attached to their
  30 + * uclass when their bind method is called)
  31 + * @sibling_node: Next uclass in the linked list of uclasses
  32 + */
  33 +struct uclass {
  34 + void *priv;
  35 + struct uclass_driver *uc_drv;
  36 + struct list_head dev_head;
  37 + struct list_head sibling_node;
  38 +};
  39 +
  40 +struct device;
  41 +
  42 +/**
  43 + * struct uclass_driver - Driver for the uclass
  44 + *
  45 + * A uclass_driver provides a consistent interface to a set of related
  46 + * drivers.
  47 + *
  48 + * @name: Name of uclass driver
  49 + * @id: ID number of this uclass
  50 + * @post_bind: Called after a new device is bound to this uclass
  51 + * @pre_unbind: Called before a device is unbound from this uclass
  52 + * @post_probe: Called after a new device is probed
  53 + * @pre_remove: Called before a device is removed
  54 + * @init: Called to set up the uclass
  55 + * @destroy: Called to destroy the uclass
  56 + * @priv_auto_alloc_size: If non-zero this is the size of the private data
  57 + * to be allocated in the uclass's ->priv pointer. If zero, then the uclass
  58 + * driver is responsible for allocating any data required.
  59 + * @per_device_auto_alloc_size: Each device can hold private data owned
  60 + * by the uclass. If required this will be automatically allocated if this
  61 + * value is non-zero.
  62 + * @ops: Uclass operations, providing the consistent interface to devices
  63 + * within the uclass.
  64 + */
  65 +struct uclass_driver {
  66 + const char *name;
  67 + enum uclass_id id;
  68 + int (*post_bind)(struct device *dev);
  69 + int (*pre_unbind)(struct device *dev);
  70 + int (*post_probe)(struct device *dev);
  71 + int (*pre_remove)(struct device *dev);
  72 + int (*init)(struct uclass *class);
  73 + int (*destroy)(struct uclass *class);
  74 + int priv_auto_alloc_size;
  75 + int per_device_auto_alloc_size;
  76 + const void *ops;
  77 +};
  78 +
  79 +/* Declare a new uclass_driver */
  80 +#define UCLASS_DRIVER(__name) \
  81 + ll_entry_declare(struct uclass_driver, __name, uclass)
  82 +
  83 +/**
  84 + * uclass_get() - Get a uclass based on an ID, creating it if needed
  85 + *
  86 + * Every uclass is identified by an ID, a number from 0 to n-1 where n is
  87 + * the number of uclasses. This function allows looking up a uclass by its
  88 + * ID.
  89 + *
  90 + * @key: ID to look up
  91 + * @ucp: Returns pointer to uclass (there is only one per ID)
  92 + * @return 0 if OK, -ve on error
  93 + */
  94 +int uclass_get(enum uclass_id key, struct uclass **ucp);
  95 +
  96 +/**
  97 + * uclass_get_device() - Get a uclass device based on an ID and index
  98 + *
  99 + * id: ID to look up
  100 + * @index: Device number within that uclass (0=first)
  101 + * @ucp: Returns pointer to uclass (there is only one per for each ID)
  102 + * @return 0 if OK, -ve on error
  103 + */
  104 +int uclass_get_device(enum uclass_id id, int index, struct device **ucp);
  105 +
  106 +/**
  107 + * uclass_first_device() - Get the first device in a uclass
  108 + *
  109 + * @id: Uclass ID to look up
  110 + * @devp: Returns pointer to the first device in that uclass, or NULL if none
  111 + * @return 0 if OK (found or not found), -1 on error
  112 + */
  113 +int uclass_first_device(enum uclass_id id, struct device **devp);
  114 +
  115 +/**
  116 + * uclass_next_device() - Get the next device in a uclass
  117 + *
  118 + * @devp: On entry, pointer to device to lookup. On exit, returns pointer
  119 + * to the next device in the same uclass, or NULL if none
  120 + * @return 0 if OK (found or not found), -1 on error
  121 + */
  122 +int uclass_next_device(struct device **devp);
  123 +
  124 +/**
  125 + * uclass_foreach_dev() - Helper function to iteration through devices
  126 + *
  127 + * This creates a for() loop which works through the available devices in
  128 + * a uclass in order from start to end.
  129 + *
  130 + * @pos: struct device * to hold the current device. Set to NULL when there
  131 + * are no more devices.
  132 + * uc: uclass to scan
  133 + */
  134 +#define uclass_foreach_dev(pos, uc) \
  135 + for (pos = list_entry((&(uc)->dev_head)->next, typeof(*pos), \
  136 + uclass_node); \
  137 + prefetch(pos->uclass_node.next), \
  138 + &pos->uclass_node != (&(uc)->dev_head); \
  139 + pos = list_entry(pos->uclass_node.next, typeof(*pos), \
  140 + uclass_node))
  141 +
  142 +#endif
  1 +/*
  2 + * Copyright (c) 2013 Google, Inc
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#ifndef __DM_UTIL_H
  8 +
  9 +void dm_warn(const char *fmt, ...);
  10 +
  11 +#ifdef DEBUG
  12 +void dm_dbg(const char *fmt, ...);
  13 +#else
  14 +static inline void dm_dbg(const char *fmt, ...)
  15 +{
  16 +}
  17 +#endif
  18 +
  19 +struct list_head;
  20 +
  21 +/**
  22 + * list_count_items() - Count number of items in a list
  23 + *
  24 + * @param head: Head of list
  25 + * @return number of items, or 0 if empty
  26 + */
  27 +int list_count_items(struct list_head *head);
  28 +
  29 +#endif