#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
+#include <linux/idr.h>
 
 #include "base.h"
 
+/* For automatically allocated device IDs */
+static DEFINE_IDA(platform_devid_ida);
+
 #define to_platform_driver(drv)        (container_of((drv), struct platform_driver, \
                                 driver))
 
  */
 int platform_device_add(struct platform_device *pdev)
 {
-       int i, ret = 0;
+       int i, ret;
 
        if (!pdev)
                return -EINVAL;
 
        pdev->dev.bus = &platform_bus_type;
 
-       if (pdev->id != -1)
+       switch (pdev->id) {
+       default:
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
-       else
+               break;
+       case PLATFORM_DEVID_NONE:
                dev_set_name(&pdev->dev, "%s", pdev->name);
+               break;
+       case PLATFORM_DEVID_AUTO:
+               /*
+                * Automatically allocated device ID. We mark it as such so
+                * that we remember it must be freed, and we append a suffix
+                * to avoid namespace collision with explicit IDs.
+                */
+               ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL);
+               if (ret < 0)
+                       goto err_out;
+               pdev->id = ret;
+               pdev->id_auto = true;
+               dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id);
+               break;
+       }
 
        for (i = 0; i < pdev->num_resources; i++) {
                struct resource *p, *r = &pdev->resource[i];
                return ret;
 
  failed:
+       if (pdev->id_auto) {
+               ida_simple_remove(&platform_devid_ida, pdev->id);
+               pdev->id = PLATFORM_DEVID_AUTO;
+       }
+
        while (--i >= 0) {
                struct resource *r = &pdev->resource[i];
                unsigned long type = resource_type(r);
                        release_resource(r);
        }
 
+ err_out:
        return ret;
 }
 EXPORT_SYMBOL_GPL(platform_device_add);
        if (pdev) {
                device_del(&pdev->dev);
 
+               if (pdev->id_auto) {
+                       ida_simple_remove(&platform_devid_ida, pdev->id);
+                       pdev->id = PLATFORM_DEVID_AUTO;
+               }
+
                for (i = 0; i < pdev->num_resources; i++) {
                        struct resource *r = &pdev->resource[i];
                        unsigned long type = resource_type(r);