summaryrefslogtreecommitdiff
path: root/drivers/core
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2014-07-23 06:55:19 -0600
committerSimon Glass <sjg@chromium.org>2014-07-23 14:08:37 +0100
commit997c87bb0b1981fd33e34cefc26d9138f27326ce (patch)
tree450a1bc245f3c0984cf4827b6dd43c3948dafcdb /drivers/core
parent1ca7e2062b4e8c3b211753dcb19c063b5b9b73ca (diff)
dm: Add functions to access a device's children
Devices can have childen that can be addressed by a simple index, the sequence number or a device tree offset. Add functions to access a child in each of these ways. The index is typically used as a fallback when the sequence number is not available. For example we may use a serial UART with sequence number 0 as the console, but if no UART has sequence number 0, then we can fall back to just using the first UART (index 0). The device tree offset function is useful for buses, where they want to locate one of their children. The device tree can be scanned to find the offset of each child, and that offset can then find the device. Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/core')
-rw-r--r--drivers/core/device.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 848ce3b675..74bb5f0f8e 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -376,3 +376,96 @@ void *dev_get_priv(struct udevice *dev)
return dev->priv;
}
+
+static int device_get_device_tail(struct udevice *dev, int ret,
+ struct udevice **devp)
+{
+ if (ret)
+ return ret;
+
+ ret = device_probe(dev);
+ if (ret)
+ return ret;
+
+ *devp = dev;
+
+ return 0;
+}
+
+int device_get_child(struct udevice *parent, int index, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (!index--)
+ return device_get_device_tail(dev, 0, devp);
+ }
+
+ return -ENODEV;
+}
+
+int device_find_child_by_seq(struct udevice *parent, int seq_or_req_seq,
+ bool find_req_seq, struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+ if (seq_or_req_seq == -1)
+ return -ENODEV;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if ((find_req_seq ? dev->req_seq : dev->seq) ==
+ seq_or_req_seq) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_get_child_by_seq(struct udevice *parent, int seq,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = device_find_child_by_seq(parent, seq, false, &dev);
+ if (ret == -ENODEV) {
+ /*
+ * We didn't find it in probed devices. See if there is one
+ * that will request this seq if probed.
+ */
+ ret = device_find_child_by_seq(parent, seq, true, &dev);
+ }
+ return device_get_device_tail(dev, ret, devp);
+}
+
+int device_find_child_by_of_offset(struct udevice *parent, int of_offset,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+
+ *devp = NULL;
+
+ list_for_each_entry(dev, &parent->child_head, sibling_node) {
+ if (dev->of_offset == of_offset) {
+ *devp = dev;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
+int device_get_child_by_of_offset(struct udevice *parent, int seq,
+ struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret;
+
+ *devp = NULL;
+ ret = device_find_child_by_of_offset(parent, seq, &dev);
+ return device_get_device_tail(dev, ret, devp);
+}