diff --git a/drivers/staging/greybus/Makefile b/drivers/staging/greybus/Makefile
index 42a3944f4eeb2253a30096da603637550a2e3336..39874deacab08eae66514354ee20c54ee6f7d914 100644
--- a/drivers/staging/greybus/Makefile
+++ b/drivers/staging/greybus/Makefile
@@ -7,6 +7,7 @@ greybus-y :=	core.o		\
 		module.o	\
 		interface.o	\
 		connection.o	\
+		protocol.o	\
 		operation.o	\
 		i2c-gb.o	\
 		gpio-gb.o	\
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 6d5085d2b6aaec4efb8c99f8a26df18e2772c09c..dac47b33855f257395b4a1a6e8272380ac883b94 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -116,7 +116,7 @@ protocol_id_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct gb_connection *connection = to_gb_connection(dev);
 
-	return sprintf(buf, "%d", connection->protocol_id);
+	return sprintf(buf, "%d", connection->protocol->id);
 }
 static DEVICE_ATTR_RO(protocol_id);
 
@@ -162,17 +162,23 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
 	if (!connection)
 		return NULL;
 
+	INIT_LIST_HEAD(&connection->protocol_links);
+	if (!gb_protocol_get(connection, protocol_id)) {
+		kfree(connection);
+		return NULL;
+	}
+
 	hd = interface->gmod->hd;
 	connection->hd = hd;			/* XXX refcount? */
 	if (!gb_connection_hd_cport_id_alloc(connection)) {
 		/* kref_put(connection->hd); */
+		gb_protocol_put(connection);
 		kfree(connection);
 		return NULL;
 	}
 
 	connection->interface = interface;
 	connection->interface_cport_id = cport_id;
-	connection->protocol_id = protocol_id;
 	connection->state = GB_CONNECTION_STATE_DISABLED;
 
 	connection->dev.parent = &interface->dev;
@@ -188,6 +194,7 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
 	if (retval) {
 		gb_connection_hd_cport_id_free(connection);
 		/* kref_put(connection->hd); */
+		gb_protocol_put(connection);
 		kfree(connection);
 		return NULL;
 	}
@@ -228,6 +235,8 @@ void gb_connection_destroy(struct gb_connection *connection)
 	spin_unlock_irq(&gb_connections_lock);
 
 	gb_connection_hd_cport_id_free(connection);
+	/* kref_put(connection->hd); */
+	gb_protocol_put(connection);
 
 	device_del(&connection->dev);
 }
@@ -267,7 +276,7 @@ int gb_connection_init(struct gb_connection *connection)
 
 	/* Need to enable the connection to initialize it */
 	connection->state = GB_CONNECTION_STATE_ENABLED;
-	switch (connection->protocol_id) {
+	switch (connection->protocol->id) {
 	case GREYBUS_PROTOCOL_I2C:
 		connection->handler = &gb_i2c_connection_handler;
 		break;
@@ -287,7 +296,7 @@ int gb_connection_init(struct gb_connection *connection)
 	case GREYBUS_PROTOCOL_VENDOR:
 	default:
 		gb_connection_err(connection, "unimplemented protocol %hhu",
-			connection->protocol_id);
+			connection->protocol->id);
 		ret = -ENXIO;
 		break;
 	}
diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h
index 830abe7060ba8a29d5e064e672aae57e6625a235..8056993c00acf1465dc7978b379ef8d890367b67 100644
--- a/drivers/staging/greybus/connection.h
+++ b/drivers/staging/greybus/connection.h
@@ -39,7 +39,9 @@ struct gb_connection {
 
 	struct rb_node			hd_node;
 	struct list_head		interface_links;
-	u8				protocol_id;
+
+	struct gb_protocol		*protocol;
+	struct list_head		protocol_links;
 
 	enum gb_connection_state	state;
 
diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h
index 3a8d8f1c077ca7eda6abf9303aa5099482a53104..f6c90e0c0f22a968ff3239c6dedcd9b6ace1ca2f 100644
--- a/drivers/staging/greybus/greybus.h
+++ b/drivers/staging/greybus/greybus.h
@@ -26,6 +26,7 @@
 #include "module.h"
 #include "interface.h"
 #include "connection.h"
+#include "protocol.h"
 #include "operation.h"
 
 
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 0388242d9b79585eed8a439d3679ecd7cff81be7..cc278bcb499d88fdc3e33652f6648319fcce9f76 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -200,7 +200,7 @@ static gb_operation_recv_handler gb_operation_recv_handlers[] = {
 
 static void gb_operation_request_handle(struct gb_operation *operation)
 {
-	u8 protocol_id = operation->connection->protocol_id;
+	u8 protocol_id = operation->connection->protocol->id;
 
 	/* Subtract one from array size to stay within u8 range */
 	if (protocol_id <= (u8)(ARRAY_SIZE(gb_operation_recv_handlers) - 1)) {
diff --git a/drivers/staging/greybus/protocol.c b/drivers/staging/greybus/protocol.c
new file mode 100644
index 0000000000000000000000000000000000000000..52944ecea075a6fdb04dfd76e4a5ce1556215efa
--- /dev/null
+++ b/drivers/staging/greybus/protocol.c
@@ -0,0 +1,122 @@
+/*
+ * Greybus protocol handling
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#include "greybus.h"
+
+/* Global list of registered protocols */
+static DEFINE_SPINLOCK(gb_protocols_lock);
+static LIST_HEAD(gb_protocols);
+
+/* Caller must hold gb_protocols_lock */
+struct gb_protocol *_gb_protocol_find(u8 id)
+{
+	struct gb_protocol *protocol;
+
+	list_for_each_entry(protocol, &gb_protocols, links)
+		if (protocol->id == id)
+			return protocol;
+	return NULL;
+}
+
+/* This is basically for debug */
+static struct gb_protocol *gb_protocol_find(u8 id)
+{
+	struct gb_protocol *protocol;
+
+	spin_lock_irq(&gb_protocols_lock);
+	protocol = _gb_protocol_find(id);
+	spin_unlock_irq(&gb_protocols_lock);
+
+	return protocol;
+}
+
+/* Returns true if protocol was succesfully registered, false otherwise */
+bool gb_protocol_register(u8 id)
+{
+	struct gb_protocol *protocol;
+	struct gb_protocol *existing;
+
+	/* Initialize it speculatively */
+	protocol = kzalloc(sizeof(*protocol), GFP_KERNEL);
+	if (!protocol)
+		return false;
+	protocol->id = id;
+	INIT_LIST_HEAD(&protocol->connections);
+
+	spin_lock_irq(&gb_protocols_lock);
+	existing = _gb_protocol_find(id);
+	if (!existing)
+		list_add(&protocol->links, &gb_protocols);
+	spin_unlock_irq(&gb_protocols_lock);
+
+	if (existing) {
+		kfree(protocol);
+		protocol = NULL;
+	}
+
+	return protocol != NULL;
+}
+
+/* Returns true if successful, false otherwise */
+bool gb_protocol_deregister(struct gb_protocol *protocol)
+{
+	spin_lock_irq(&gb_protocols_lock);
+	if (list_empty(&protocol->connections))
+		list_del(&protocol->links);
+	else
+		protocol = NULL;	/* Protocol is still in use */
+	spin_unlock_irq(&gb_protocols_lock);
+	kfree(protocol);
+
+	return protocol != NULL;
+}
+
+/* Returns true if successful, false otherwise */
+bool gb_protocol_get(struct gb_connection *connection, u8 id)
+{
+	struct gb_protocol *protocol;
+
+	/* Sanity */
+	if (!list_empty(&connection->protocol_links) ||
+			!connection->protocol->id) {
+		gb_connection_err(connection,
+			"connection already has protocol");
+		return false;
+	}
+
+	spin_lock_irq(&gb_protocols_lock);
+	protocol = _gb_protocol_find(id);
+	if (protocol)
+		list_add(&connection->protocol_links, &protocol->connections);
+	spin_unlock_irq(&gb_protocols_lock);
+	connection->protocol = protocol;
+
+	return protocol != NULL;
+}
+
+void gb_protocol_put(struct gb_connection *connection)
+{
+	struct gb_protocol *protocol = connection->protocol;
+
+	/* Sanity checks */
+	if (list_empty(&connection->protocol_links)) {
+		gb_connection_err(connection,
+			"connection protocol not recorded");
+		return;
+	}
+	if (!protocol || gb_protocol_find(protocol->id) != protocol)  {
+		gb_connection_err(connection,
+			"connection has undefined protocol");
+		return;
+	}
+
+	spin_lock_irq(&gb_protocols_lock);
+	list_del(&connection->protocol_links);
+	connection->protocol = NULL;
+	spin_unlock_irq(&gb_protocols_lock);
+}
diff --git a/drivers/staging/greybus/protocol.h b/drivers/staging/greybus/protocol.h
new file mode 100644
index 0000000000000000000000000000000000000000..d244e9d3eca1770fb82b58a4c82c299830f600ea
--- /dev/null
+++ b/drivers/staging/greybus/protocol.h
@@ -0,0 +1,26 @@
+/*
+ * Greybus protocol handling
+ *
+ * Copyright 2014 Google Inc.
+ *
+ * Released under the GPLv2 only.
+ */
+
+#ifndef __PROTOCOL_H
+#define __PROTOCOL_H
+
+#include "greybus.h"
+
+struct gb_protocol {
+	u8				id;
+	struct list_head		connections;	/* protocol users */
+	struct list_head		links;		/* global list */
+};
+
+bool gb_protocol_register(u8 id);
+bool gb_protocol_deregister(struct gb_protocol *protocol);
+
+bool gb_protocol_get(struct gb_connection *connection, u8 id);
+void gb_protocol_put(struct gb_connection *connection);
+
+#endif /* __PROTOCOL_H */