aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass2015-01-25 08:27:10 -0700
committerSimon Glass2015-01-29 17:09:56 -0700
commit83c7e434c9dd3ca81f8b763e23c1881b973bcf2f (patch)
treec0fc096ee51bbcd66ccabd77826e236f49329845
parent1603bf3cc189da65362b83b85831e094a2fe8516 (diff)
dm: core: Allow uclass to set up a device's child before it is probed
Some buses need to set up their devices before they can be used. This setup may well be common to all buses in a particular uclass. Support a common pre-probe method for the uclass, called before any bus devices are probed. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
-rw-r--r--drivers/core/device.c4
-rw-r--r--drivers/core/uclass.c13
-rw-r--r--include/dm/test.h3
-rw-r--r--include/dm/uclass-internal.h11
-rw-r--r--include/dm/uclass.h1
-rw-r--r--test/dm/bus.c46
-rw-r--r--test/dm/test-fdt.c7
7 files changed, 85 insertions, 0 deletions
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 78bc460d35f..b73d3b8961d 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -227,6 +227,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
}
dev->seq = seq;
+ ret = uclass_pre_probe_child(dev);
+ if (ret)
+ goto fail;
+
if (dev->parent && dev->parent->driver->child_pre_probe) {
ret = dev->parent->driver->child_pre_probe(dev);
if (ret)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index a5445518f57..289a5d2d53d 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -391,6 +391,19 @@ int uclass_resolve_seq(struct udevice *dev)
return seq;
}
+int uclass_pre_probe_child(struct udevice *dev)
+{
+ struct uclass_driver *uc_drv;
+
+ if (!dev->parent)
+ return 0;
+ uc_drv = dev->parent->uclass->uc_drv;
+ if (uc_drv->child_pre_probe)
+ return uc_drv->child_pre_probe(dev);
+
+ return 0;
+}
+
int uclass_post_probe_device(struct udevice *dev)
{
struct uclass_driver *uc_drv = dev->uclass->uc_drv;
diff --git a/include/dm/test.h b/include/dm/test.h
index f08c05da814..707c69e07f0 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -67,6 +67,8 @@ enum {
struct dm_test_priv {
int ping_total;
int op_count[DM_TEST_OP_COUNT];
+ int uclass_flag;
+ int uclass_total;
};
/**
@@ -88,6 +90,7 @@ struct dm_test_uclass_priv {
*
* @sum: Test value used to check parent data works correctly
* @flag: Used to track calling of parent operations
+ * @uclass_flag: Used to track calling of parent operations by uclass
*/
struct dm_test_parent_data {
int sum;
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index f718f37affb..f2f254a8259 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -44,6 +44,17 @@ int uclass_bind_device(struct udevice *dev);
int uclass_unbind_device(struct udevice *dev);
/**
+ * uclass_pre_probe_child() - Deal with a child that is about to be probed
+ *
+ * Perform any pre-processing that is needed by the uclass before it can be
+ * probed.
+ *
+ * @dev: Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_probe_child(struct udevice *dev);
+
+/**
* uclass_post_probe_device() - Deal with a device that has just been probed
*
* Perform any post-processing of a probed device that is needed by the
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 5c5b8f42083..d6c40c60dda 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -83,6 +83,7 @@ struct uclass_driver {
int (*post_probe)(struct udevice *dev);
int (*pre_remove)(struct udevice *dev);
int (*child_post_bind)(struct udevice *dev);
+ int (*child_pre_probe)(struct udevice *dev);
int (*init)(struct uclass *class);
int (*destroy)(struct uclass *class);
int priv_auto_alloc_size;
diff --git a/test/dm/bus.c b/test/dm/bus.c
index c123ed79310..faffe6a385b 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -53,6 +53,15 @@ static int testbus_child_pre_probe(struct udevice *dev)
return 0;
}
+static int testbus_child_pre_probe_uclass(struct udevice *dev)
+{
+ struct dm_test_priv *priv = dev_get_priv(dev);
+
+ priv->uclass_flag++;
+
+ return 0;
+}
+
static int testbus_child_post_remove(struct udevice *dev)
{
struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
@@ -91,6 +100,7 @@ UCLASS_DRIVER(testbus) = {
.name = "testbus",
.id = UCLASS_TEST_BUS,
.flags = DM_UC_FLAG_SEQ_ALIAS,
+ .child_pre_probe = testbus_child_pre_probe_uclass,
};
/* Test that we can probe for children */
@@ -469,3 +479,39 @@ static int dm_test_bus_child_post_bind_uclass(struct dm_test_state *dms)
}
DM_TEST(dm_test_bus_child_post_bind_uclass,
DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/*
+ * Test that the bus' uclass' child_pre_probe() is called before the
+ * device's probe() method
+ */
+static int dm_test_bus_child_pre_probe_uclass(struct dm_test_state *dms)
+{
+ struct udevice *bus, *dev;
+ int child_count;
+
+ /*
+ * See testfdt_drv_probe() which effectively checks that the uclass
+ * flag is set before that method is called
+ */
+ ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+ for (device_find_first_child(bus, &dev), child_count = 0;
+ dev;
+ device_find_next_child(&dev)) {
+ struct dm_test_priv *priv = dev_get_priv(dev);
+
+ /* Check that things happened in the right order */
+ ut_asserteq_ptr(NULL, priv);
+ ut_assertok(device_probe(dev));
+
+ priv = dev_get_priv(dev);
+ ut_assert(priv != NULL);
+ ut_asserteq(1, priv->uclass_flag);
+ ut_asserteq(1, priv->uclass_total);
+ child_count++;
+ }
+ ut_asserteq(3, child_count);
+
+ return 0;
+}
+DM_TEST(dm_test_bus_child_pre_probe_uclass,
+ DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index dfcb3af61bb..b8ee9599a22 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -51,6 +51,13 @@ static int testfdt_drv_probe(struct udevice *dev)
priv->ping_total += DM_TEST_START_TOTAL;
+ /*
+ * If this device is on a bus, the uclass_flag will be set before
+ * calling this function. This is used by
+ * dm_test_bus_child_pre_probe_uclass().
+ */
+ priv->uclass_total += priv->uclass_flag;
+
return 0;
}