diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index b34b5cd..3324a55 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -282,4 +282,10 @@ config CMA_AREAS
 
 endif
 
+config DEVICEPATH
+	bool "Device path api"
+	default n
+	help
+	  Include dynamicly probed path matching API
+
 endmenu
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 5aa2d70..b8d5723 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -22,5 +22,7 @@ obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
 obj-$(CONFIG_REGMAP)	+= regmap/
 obj-$(CONFIG_SOC_BUS) += soc.o
 
+obj-$(CONFIG_DEVICEPATH) += path.o
+
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 
diff --git a/drivers/base/core.c b/drivers/base/core.c
index abea76c..cc0ba02 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1368,6 +1368,8 @@ int __init devices_init(void)
 	if (!sysfs_dev_char_kobj)
 		goto char_kobj_err;
 
+	device_path_init();
+
 	return 0;
 
  char_kobj_err:
diff --git a/drivers/base/path.c b/drivers/base/path.c
new file mode 100644
index 0000000..384e792
--- /dev/null
+++ b/drivers/base/path.c
@@ -0,0 +1,181 @@
+/*
+ * drivers/base/path.c - device_path apis for matching dynamic / variable
+ *  device paths on buses like usb / mmc to wildcard constants from
+ *  platform or DT
+ *
+ * Copyright (c) 2012 Linaro, LTD
+ * Author: Andy Green <andy.green@linaro.org>
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+
+struct device_path {
+	char *path;
+	struct list_head list;
+};
+
+struct device_path list;
+DEFINE_MUTEX(lock);
+
+static int device_path_compare_wildcard(const char *awc, const char *b)
+{
+	while (*awc && *b) {
+		if (*awc == '*') {
+			awc++;
+			/* wildcard disallowed from extening past / */
+			while (*b && *b != *awc && *b != '/')
+				b++;
+		}
+		if (*awc != *b)
+			return -ENOENT;
+		if (!*awc)
+			return 0;
+		awc++;
+		b++;
+	}
+
+	if (!*awc && !*b)
+		return 0;
+
+	return -ENOENT;
+}
+
+static const char *device_path_find_wildcard(const char *device_path)
+{
+	struct device_path *dp;
+
+	mutex_lock(&lock);
+	list_for_each_entry(dp, &list.list, list) {
+		if (device_path_compare_wildcard(dp->path, device_path) == 0) {
+			mutex_unlock(&lock);
+			return dp->path;
+		}
+	}
+
+	mutex_unlock(&lock);
+	return NULL;
+}
+
+static int _device_path_generate(struct device *device, char *name, int len)
+{
+	int n = 0;
+	int l;
+
+	if (!device)
+		return -ENODEV;
+
+	if (device->parent) {
+		n = _device_path_generate(device->parent, name, len);
+		if (n < 0)
+			return n;
+	}
+
+	l = strlen(dev_name(device));
+
+	if ((len - n) < l + 3)
+		return -E2BIG;
+
+	name[n++] = '/';
+	strcpy(&name[n], dev_name(device));
+
+	return n + l;
+}
+
+int device_path_generate(struct device *device, char *name, int len)
+{
+	int n;
+	const char *match;
+
+	n = _device_path_generate(device, name, len);
+	if (n < 0)
+		return n;
+
+	/*
+	 * if any registered wildcard matches, report that instead
+	 */
+	match = device_path_find_wildcard(name);
+	if (!match)
+		return 0;
+
+	n = strlen(match);
+	if (n >= len - 1)
+		return -E2BIG;
+
+	memcpy(name, match, n);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(device_path_generate);
+
+int device_path_register_wildcard_path(const char *wildcard_devpath)
+{
+	struct device_path *dp;
+	int ret = -ENOMEM;
+
+	if (strchr(wildcard_devpath, '*') == NULL)
+		return 0;
+
+	mutex_lock(&lock);
+	dp = kmalloc(sizeof(struct device_path), GFP_KERNEL);
+	if (!dp)
+		goto bail;
+
+	dp->path = kmalloc(strlen(wildcard_devpath) + 1, GFP_KERNEL);
+	if (!dp->path) {
+		kfree(dp);
+		goto bail;
+	}
+
+	strcpy(dp->path, wildcard_devpath);
+	list_add(&dp->list, &list.list);
+	ret = 0;
+
+bail:
+	mutex_unlock(&lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(device_path_register_wildcard_path);
+
+static void device_path_free(struct device_path *dp)
+{
+	kfree(dp->path);
+	kfree(dp);
+}
+
+int device_path_unregister_wildcard_path(const char *wildcard_devpath)
+{
+	struct device_path *dp;
+	struct list_head *pos, *q;
+
+	mutex_lock(&lock);
+	list_for_each_safe(pos, q, &list.list) {
+		dp = list_entry(pos, struct device_path, list);
+		if (strcmp(dp->path, wildcard_devpath) == 0) {
+			list_del(pos);
+			device_path_free(dp);
+			mutex_unlock(&lock);
+			return 0;
+		}
+	}
+
+	mutex_unlock(&lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(device_path_unregister_wildcard_path);
+
+void __init device_path_init(void)
+{
+	INIT_LIST_HEAD(&list.list);
+	mutex_init(&lock);
+}
+EXPORT_SYMBOL_GPL(device_path_init);
diff --git a/include/linux/device.h b/include/linux/device.h
index 86ef6ab..ecaf3aa 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -875,6 +875,18 @@ extern int (*platform_notify)(struct device *dev);
 
 extern int (*platform_notify_remove)(struct device *dev);
 
+/*
+ * optional device path api
+ */
+#ifdef CONFIG_DEVICEPATH
+#define MAX_DEV_PATH_SIZE 512
+extern int device_path_generate(struct device *device, char *name, int len);
+extern int device_path_unregister_wildcard_path(const char *wildcard_devpath);
+extern int device_path_register_wildcard_path(const char *wildcard_devpath);
+extern void device_path_init(void);
+#else
+static inline void device_path_init(void) { ; }
+#endif
 
 /*
  * get_device - atomically increment the reference count for the device.
