goto fail_alloc1;
                }
        }
+       if (parent) {
+               int size = parent->driver->per_child_platdata_auto_alloc_size;
+
+               if (size) {
+                       dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
+                       dev->parent_platdata = calloc(1, size);
+                       if (!dev->parent_platdata) {
+                               ret = -ENOMEM;
+                               goto fail_alloc2;
+                       }
+               }
+       }
 
        /* put dev into parent's successor list */
        if (parent)
                        dev->name);
        }
 fail_uclass_bind:
-       if (parent)
-               list_del(&dev->sibling_node);
+       list_del(&dev->sibling_node);
+       if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+               free(dev->parent_platdata);
+               dev->parent_platdata = NULL;
+       }
+fail_alloc2:
        if (dev->flags & DM_FLAG_ALLOC_PDATA) {
                free(dev->platdata);
                dev->platdata = NULL;
        return dev->platdata;
 }
 
+void *dev_get_parent_platdata(struct udevice *dev)
+{
+       if (!dev) {
+               dm_warn("%s: null device", __func__);
+               return NULL;
+       }
+
+       return dev->parent_platdata;
+}
+
 void *dev_get_priv(struct udevice *dev)
 {
        if (!dev) {
 
 /* DM should init this device prior to relocation */
 #define DM_FLAG_PRE_RELOC      (1 << 2)
 
+/* DM is responsible for allocating and freeing parent_platdata */
+#define DM_FLAG_ALLOC_PARENT_PDATA     (1 << 3)
+
 /**
  * struct udevice - An instance of a driver
  *
  * @driver: The driver used by this device
  * @name: Name of device, typically the FDT node name
  * @platdata: Configuration data for this device
+ * @parent_platdata: The parent bus's configuration data for this device
  * @of_offset: Device tree node offset for this device (- for none)
  * @of_id: Pointer to the udevice_id structure which created the device
  * @parent: Parent of this device, or NULL for the top level device
        struct driver *driver;
        const char *name;
        void *platdata;
+       void *parent_platdata;
        int of_offset;
        const struct udevice_id *of_id;
        struct udevice *parent;
  * device_probe_child() pass it in. So far the use case for allocating it
  * is SPI, but I found that unsatisfactory. Since it is here I will leave it
  * until things are clearer.
+ * @per_child_platdata_auto_alloc_size: A bus likes to store information about
+ * its children. If non-zero this is the size of this data, to be allocated
+ * in the child's parent_platdata pointer.
  * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
        int priv_auto_alloc_size;
        int platdata_auto_alloc_size;
        int per_child_auto_alloc_size;
+       int per_child_platdata_auto_alloc_size;
        const void *ops;        /* driver-specific operations */
        uint32_t flags;
 };
  */
 void *dev_get_platdata(struct udevice *dev);
 
+/**
+ * dev_get_parent_platdata() - Get the parent platform data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev                Device to check
+ * @return parent's platform data, or NULL if none
+ */
+void *dev_get_parent_platdata(struct udevice *dev);
+
 /**
  * dev_get_parentdata() - Get the parent data for a device
  *
 
 #include <dm/device-internal.h>
 #include <dm/root.h>
 #include <dm/test.h>
+#include <dm/uclass-internal.h>
 #include <dm/ut.h>
 #include <dm/util.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct dm_test_parent_platdata {
+       int count;
+};
+
 enum {
        FLAG_CHILD_PROBED       = 10,
        FLAG_CHILD_REMOVED      = -7,
        .priv_auto_alloc_size = sizeof(struct dm_test_priv),
        .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
        .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
+       .per_child_platdata_auto_alloc_size =
+                       sizeof(struct dm_test_parent_platdata),
        .child_pre_probe = testbus_child_pre_probe,
        .child_post_remove = testbus_child_post_remove,
 };
        return 0;
 }
 DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that the bus can store platform data about each child */
+static int dm_test_bus_parent_platdata(struct dm_test_state *dms)
+{
+       struct dm_test_parent_platdata *plat;
+       struct udevice *bus, *dev;
+       int child_count;
+
+       /* Check that the bus has no children */
+       ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
+       device_find_first_child(bus, &dev);
+       ut_asserteq_ptr(NULL, dev);
+
+       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)) {
+               /* Check that platform data is allocated */
+               plat = dev_get_parent_platdata(dev);
+               ut_assert(plat != NULL);
+
+               /*
+                * Check that it is not affected by the device being
+                * probed/removed
+                */
+               plat->count++;
+               ut_asserteq(1, plat->count);
+               device_probe(dev);
+               device_remove(dev);
+
+               ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
+               ut_asserteq(1, plat->count);
+               ut_assertok(device_probe(dev));
+               child_count++;
+       }
+       ut_asserteq(3, child_count);
+
+       /* Removing the bus should also have no effect (it is still bound) */
+       device_remove(bus);
+       for (device_find_first_child(bus, &dev), child_count = 0;
+            dev;
+            device_find_next_child(&dev)) {
+               /* Check that platform data is allocated */
+               plat = dev_get_parent_platdata(dev);
+               ut_assert(plat != NULL);
+               ut_asserteq(1, plat->count);
+               child_count++;
+       }
+       ut_asserteq(3, child_count);
+
+       /* Unbind all the children */
+       do {
+               device_find_first_child(bus, &dev);
+               if (dev)
+                       device_unbind(dev);
+       } while (dev);
+
+       /* Now the child platdata should be removed and re-added */
+       device_probe(bus);
+       for (device_find_first_child(bus, &dev), child_count = 0;
+            dev;
+            device_find_next_child(&dev)) {
+               /* Check that platform data is allocated */
+               plat = dev_get_parent_platdata(dev);
+               ut_assert(plat != NULL);
+               ut_asserteq(0, plat->count);
+               child_count++;
+       }
+       ut_asserteq(3, child_count);
+
+       return 0;
+}
+DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);