diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 04b314e0fa51..b5278904e443 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -4,7 +4,7 @@ obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o \
-			   topology.o container.o
+			   topology.o container.o interface.o
 obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o
 obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
 obj-y			+= power/
diff --git a/drivers/base/interface.c b/drivers/base/interface.c
new file mode 100644
index 000000000000..411f6cdf90e7
--- /dev/null
+++ b/drivers/base/interface.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2014 NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "interface: " fmt
+
+#include <linux/device.h>
+#include <linux/interface.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(interfaces_lock);
+static LIST_HEAD(interfaces);
+static LIST_HEAD(drivers);
+
+struct interface_attachment {
+	struct interface_driver *driver;
+	struct list_head list;
+};
+
+static bool interface_match(struct interface *intf,
+			    struct interface_driver *driver)
+{
+	return strcmp(intf->name, driver->name) == 0;
+}
+
+static bool interface_attached(struct interface *intf,
+			       struct interface_driver *driver)
+{
+	struct interface_attachment *attach;
+
+	list_for_each_entry(attach, &intf->drivers, list)
+		if (attach->driver == driver)
+			return true;
+
+	return false;
+}
+
+static int interface_attach(struct interface *intf,
+			    struct interface_driver *driver)
+{
+	struct interface_attachment *attach;
+
+	attach = kzalloc(sizeof(*attach), GFP_KERNEL);
+	if (!attach)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&attach->list);
+	attach->driver = driver;
+
+	list_add_tail(&attach->list, &intf->drivers);
+
+	return 0;
+}
+
+static void interface_detach(struct interface *intf,
+			     struct interface_driver *driver)
+{
+	struct interface_attachment *attach;
+
+	list_for_each_entry(attach, &intf->drivers, list) {
+		if (attach->driver == driver) {
+			list_del(&attach->list);
+			kfree(attach);
+			return;
+		}
+	}
+}
+
+static void interface_bind(struct interface *intf,
+			   struct interface_driver *driver)
+{
+	int err;
+
+	if (interface_attached(intf, driver))
+		return;
+
+	if (!interface_match(intf, driver))
+		return;
+
+	err = interface_attach(intf, driver);
+	if (err < 0) {
+		pr_err("failed to attach driver %ps to interface %s: %d\n",
+		       driver, intf->name, err);
+		return;
+	}
+
+	err = driver->bind(intf);
+	if (err < 0) {
+		pr_err("failed to bind driver %ps to interface %s: %d\n",
+		       driver, intf->name, err);
+		interface_detach(intf, driver);
+		return;
+	}
+
+	pr_debug("driver %ps bound to interface %s\n", driver, intf->name);
+}
+
+static void interface_unbind(struct interface *intf,
+			     struct interface_driver *driver)
+{
+	if (!interface_attached(intf, driver))
+		return;
+
+	interface_detach(intf, driver);
+	driver->unbind(intf);
+
+	pr_debug("driver %ps unbound from interface %s\n", driver, intf->name);
+}
+
+int interface_add(struct interface *intf)
+{
+	struct interface_driver *driver;
+
+	INIT_LIST_HEAD(&intf->drivers);
+	INIT_LIST_HEAD(&intf->list);
+
+	mutex_lock(&interfaces_lock);
+
+	list_add_tail(&intf->list, &interfaces);
+
+	pr_debug("interface %s added for device %s\n", intf->name,
+		 dev_name(intf->dev));
+
+	list_for_each_entry(driver, &drivers, list)
+		interface_bind(intf, driver);
+
+	mutex_unlock(&interfaces_lock);
+
+	return 0;
+}
+
+void interface_remove(struct interface *intf)
+{
+	struct interface_driver *driver;
+
+	mutex_lock(&interfaces_lock);
+
+	list_for_each_entry(driver, &drivers, list)
+		interface_unbind(intf, driver);
+
+	list_del_init(&intf->list);
+
+	pr_debug("interface %s removed for device %s\n", intf->name,
+		 dev_name(intf->dev));
+
+	mutex_unlock(&interfaces_lock);
+}
+
+int interface_register_driver(struct interface_driver *driver)
+{
+	struct interface *intf;
+
+	mutex_lock(&interfaces_lock);
+
+	list_add_tail(&driver->list, &drivers);
+
+	pr_debug("driver %ps added\n", driver);
+
+	list_for_each_entry(intf, &interfaces, list)
+		interface_bind(intf, driver);
+
+	mutex_unlock(&interfaces_lock);
+
+	return 0;
+}
+
+void interface_unregister_driver(struct interface_driver *driver)
+{
+	struct interface *intf;
+
+	mutex_lock(&interfaces_lock);
+
+	list_for_each_entry(intf, &interfaces, list)
+		interface_unbind(intf, driver);
+
+	list_del_init(&driver->list);
+
+	pr_debug("driver %ps removed\n", driver);
+
+	mutex_unlock(&interfaces_lock);
+}
diff --git a/include/linux/interface.h b/include/linux/interface.h
new file mode 100644
index 000000000000..2c49ad3912fe
--- /dev/null
+++ b/include/linux/interface.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <linux/list.h>
+
+struct device;
+struct interface;
+
+struct interface_driver {
+	const char *name;
+
+	int (*bind)(struct interface *intf);
+	void (*unbind)(struct interface *intf);
+
+	struct list_head list;
+};
+
+int interface_register_driver(struct interface_driver *driver);
+void interface_unregister_driver(struct interface_driver *driver);
+
+struct interface {
+	const char *name;
+	struct device *dev;
+
+	struct list_head drivers;
+	struct list_head list;
+};
+
+int interface_add(struct interface *intf);
+void interface_remove(struct interface *intf);
+
+#endif
