{
struct uclass *uc;
+ if (!gd->dm_root)
+ return NULL;
/*
* TODO(sjg@chromium.org): Optimise this, perhaps moving the found
* node to the start of the list, or creating a linear array mapping
uc->uc_drv = uc_drv;
INIT_LIST_HEAD(&uc->sibling_node);
INIT_LIST_HEAD(&uc->dev_head);
- list_add(&uc->sibling_node, &gd->uclass_root);
+ list_add(&uc->sibling_node, &DM_UCLASS_ROOT_NON_CONST);
if (uc_drv->init) {
ret = uc_drv->init(uc);
int uclass_destroy(struct uclass *uc)
{
struct uclass_driver *uc_drv;
- struct device *dev, *tmp;
+ struct udevice *dev, *tmp;
int ret;
list_for_each_entry_safe(dev, tmp, &uc->dev_head, uclass_node) {
return 0;
}
-int uclass_find_device(enum uclass_id id, int index, struct device **devp)
+int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
{
struct uclass *uc;
- struct device *dev;
+ struct udevice *dev;
int ret;
*devp = NULL;
return -ENODEV;
}
-int uclass_get_device(enum uclass_id id, int index, struct device **devp)
+int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
+ bool find_req_seq, struct udevice **devp)
{
- struct device *dev;
+ struct uclass *uc;
+ struct udevice *dev;
int ret;
*devp = NULL;
- ret = uclass_find_device(id, index, &dev);
+ debug("%s: %d %d\n", __func__, find_req_seq, seq_or_req_seq);
+ if (seq_or_req_seq == -1)
+ return -ENODEV;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ debug(" - %d %d\n", dev->req_seq, dev->seq);
+ if ((find_req_seq ? dev->req_seq : dev->seq) ==
+ seq_or_req_seq) {
+ *devp = dev;
+ debug(" - found\n");
+ return 0;
+ }
+ }
+ debug(" - not found\n");
+
+ return -ENODEV;
+}
+
+static int uclass_find_device_by_of_offset(enum uclass_id id, int node,
+ struct udevice **devp)
+{
+ struct uclass *uc;
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ if (node < 0)
+ return -ENODEV;
+ ret = uclass_get(id, &uc);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+ if (dev->of_offset == node) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+/**
+ * uclass_get_device_tail() - handle the end of a get_device call
+ *
+ * This handles returning an error or probing a device as needed.
+ *
+ * @dev: Device that needs to be probed
+ * @ret: Error to return. If non-zero then the device is not probed
+ * @devp: Returns the value of 'dev' if there is no error
+ * @return ret, if non-zero, else the result of the device_probe() call
+ */
+static int uclass_get_device_tail(struct udevice *dev, int ret,
+ struct udevice **devp)
+{
if (ret)
return ret;
return 0;
}
-int uclass_first_device(enum uclass_id id, struct device **devp)
+int uclass_get_device(enum uclass_id id, int index, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device(id, index, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_seq(id, seq, false, &dev);
+ if (ret == -ENODEV) {
+ /*
+ * We didn't find it in probed devices. See if there is one
+ * that will request this seq if probed.
+ */
+ ret = uclass_find_device_by_seq(id, seq, true, &dev);
+ }
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_get_device_by_of_offset(enum uclass_id id, int node,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = uclass_find_device_by_of_offset(id, node, &dev);
+ return uclass_get_device_tail(dev, ret, devp);
+}
+
+int uclass_first_device(enum uclass_id id, struct udevice **devp)
{
struct uclass *uc;
- struct device *dev;
+ struct udevice *dev;
int ret;
*devp = NULL;
if (list_empty(&uc->dev_head))
return 0;
- dev = list_first_entry(&uc->dev_head, struct device, uclass_node);
+ dev = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
ret = device_probe(dev);
if (ret)
return ret;
return 0;
}
-int uclass_next_device(struct device **devp)
+int uclass_next_device(struct udevice **devp)
{
- struct device *dev = *devp;
+ struct udevice *dev = *devp;
int ret;
*devp = NULL;
if (list_is_last(&dev->uclass_node, &dev->uclass->dev_head))
return 0;
- dev = list_entry(dev->uclass_node.next, struct device, uclass_node);
+ dev = list_entry(dev->uclass_node.next, struct udevice,
+ uclass_node);
ret = device_probe(dev);
if (ret)
return ret;
return 0;
}
-int uclass_bind_device(struct device *dev)
+int uclass_bind_device(struct udevice *dev)
{
struct uclass *uc;
int ret;
return 0;
}
-int uclass_unbind_device(struct device *dev)
+int uclass_unbind_device(struct udevice *dev)
{
struct uclass *uc;
int ret;
return 0;
}
-int uclass_post_probe_device(struct device *dev)
+int uclass_resolve_seq(struct udevice *dev)
+{
+ struct udevice *dup;
+ int seq;
+ int ret;
+
+ assert(dev->seq == -1);
+ ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, dev->req_seq,
+ false, &dup);
+ if (!ret) {
+ dm_warn("Device '%s': seq %d is in use by '%s'\n",
+ dev->name, dev->req_seq, dup->name);
+ } else if (ret == -ENODEV) {
+ /* Our requested sequence number is available */
+ if (dev->req_seq != -1)
+ return dev->req_seq;
+ } else {
+ return ret;
+ }
+
+ for (seq = 0; seq < DM_MAX_SEQ; seq++) {
+ ret = uclass_find_device_by_seq(dev->uclass->uc_drv->id, seq,
+ false, &dup);
+ if (ret == -ENODEV)
+ break;
+ if (ret)
+ return ret;
+ }
+ return seq;
+}
+
+int uclass_post_probe_device(struct udevice *dev)
{
struct uclass_driver *uc_drv = dev->uclass->uc_drv;
return 0;
}
-int uclass_pre_remove_device(struct device *dev)
+int uclass_pre_remove_device(struct udevice *dev)
{
struct uclass_driver *uc_drv;
struct uclass *uc;
free(dev->uclass_priv);
dev->uclass_priv = NULL;
}
+ dev->seq = -1;
return 0;
}