diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 42613031ff..69456ebcb0 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -456,6 +456,33 @@ int uclass_next_device(struct udevice **devp)
 	return uclass_get_device_tail(dev, ret, devp);
 }
 
+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;
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 63da868ae5..4a713412a6 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -262,6 +262,37 @@ int uclass_first_device_err(enum uclass_id id, struct udevice **devp);
 int uclass_next_device(struct udevice **devp);
 
 /**
+ * uclass_first_device() - Get the first device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly and can be probed.
+ *
+ * @id: Uclass ID to look up
+ * @devp: Returns pointer to the first device in that uclass, or NULL if there
+ * is no first device
+ * @return 0 if OK (found or not found), other -ve on error. If an error occurs
+ * it is still possible to move to the next device.
+ */
+int uclass_first_device_check(enum uclass_id id, struct udevice **devp);
+
+/**
+ * uclass_next_device() - Get the next device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly and can be probed.
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the uclass if any
+ * @return 0 if OK (found or not found), other -ve on error. If an error occurs
+ * it is still possible to move to the next device.
+ */
+int uclass_next_device_check(struct udevice **devp);
+
+/**
  * uclass_resolve_seq() - Resolve a device's sequence number
  *
  * On entry dev->seq is -1, and dev->req_seq may be -1 (to allocate a
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 1770b86fed..f028fe5935 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -338,3 +338,83 @@ static int dm_test_first_next_device(struct unit_test_state *uts)
 	return 0;
 }
 DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/**
+ * check_devices() - Check return values and pointers
+ *
+ * This runs through a full sequence of uclass_first_device_check()...
+ * uclass_next_device_check() checking that the return values and devices
+ * are correct.
+ *
+ * @uts: Test state
+ * @devlist: List of expected devices
+ * @mask: Indicates which devices should return an error. Device n should
+ *	  return error (-NOENT - n) if bit n is set, or no error (i.e. 0) if
+ *	  bit n is clear.
+ */
+static int check_devices(struct unit_test_state *uts,
+			 struct udevice *devlist[], int mask)
+{
+	int expected_ret;
+	struct udevice *dev;
+	int i;
+
+	expected_ret = (mask & 1) ? -ENOENT : 0;
+	mask >>= 1;
+	ut_asserteq(expected_ret,
+		    uclass_first_device_check(UCLASS_TEST_PROBE, &dev));
+	for (i = 0; i < 4; i++) {
+		ut_asserteq_ptr(devlist[i], dev);
+		expected_ret = (mask & 1) ? -ENOENT - (i + 1) : 0;
+		mask >>= 1;
+		ut_asserteq(expected_ret, uclass_next_device_check(&dev));
+	}
+	ut_asserteq_ptr(NULL, dev);
+
+	return 0;
+}
+
+/* Test uclass_first_device_check() and uclass_next_device_check() */
+static int dm_test_first_next_ok_device(struct unit_test_state *uts)
+{
+	struct dm_testprobe_pdata *pdata;
+	struct udevice *dev, *parent = NULL, *devlist[4];
+	int count;
+	int ret;
+
+	/* There should be 4 devices */
+	count = 0;
+	for (ret = uclass_first_device_check(UCLASS_TEST_PROBE, &dev);
+	     dev;
+	     ret = uclass_next_device_check(&dev)) {
+		ut_assertok(ret);
+		devlist[count++] = dev;
+		parent = dev_get_parent(dev);
+		}
+	ut_asserteq(4, count);
+	ut_assertok(uclass_first_device_check(UCLASS_TEST_PROBE, &dev));
+	ut_assertok(check_devices(uts, devlist, 0));
+
+	/* Remove them and try again, with an error on the second one */
+	pdata = dev_get_platdata(devlist[1]);
+	pdata->probe_err = -ENOENT - 1;
+	device_remove(parent, DM_REMOVE_NORMAL);
+	ut_assertok(check_devices(uts, devlist, 1 << 1));
+
+	/* Now an error on the first one */
+	pdata = dev_get_platdata(devlist[0]);
+	pdata->probe_err = -ENOENT - 0;
+	device_remove(parent, DM_REMOVE_NORMAL);
+	ut_assertok(check_devices(uts, devlist, 3 << 0));
+
+	/* Now errors on all */
+	pdata = dev_get_platdata(devlist[2]);
+	pdata->probe_err = -ENOENT - 2;
+	pdata = dev_get_platdata(devlist[3]);
+	pdata->probe_err = -ENOENT - 3;
+	device_remove(parent, DM_REMOVE_NORMAL);
+	ut_assertok(check_devices(uts, devlist, 0xf << 0));
+
+	return 0;
+}
+DM_TEST(dm_test_first_next_ok_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
