diff --git a/drivers/staging/greybus/battery.c b/drivers/staging/greybus/battery.c
index 2130d73cbfde..c14f44b4e86a 100644
--- a/drivers/staging/greybus/battery.c
+++ b/drivers/staging/greybus/battery.c
@@ -88,32 +88,8 @@ struct gb_battery_voltage_response {
 	__le32	voltage;
 };
 
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int get_version(struct gb_battery *gb)
-{
-	struct gb_battery_proto_version_response version_response;
-	int retval;
-
-	retval = gb_operation_sync(gb->connection,
-				   GB_BATTERY_TYPE_PROTOCOL_VERSION,
-				   NULL, 0,
-				   &version_response, sizeof(version_response));
-	if (retval)
-		return retval;
-
-	if (version_response.major > GB_BATTERY_VERSION_MAJOR) {
-		pr_err("unsupported major version (%hhu > %hhu)\n",
-			version_response.major, GB_BATTERY_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-
-	gb->version_major = version_response.major;
-	gb->version_minor = version_response.minor;
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_battery, BATTERY);
 
 static int get_tech(struct gb_battery *gb)
 {
diff --git a/drivers/staging/greybus/gpio.c b/drivers/staging/greybus/gpio.c
index 4997588e2617..a93583341811 100644
--- a/drivers/staging/greybus/gpio.c
+++ b/drivers/staging/greybus/gpio.c
@@ -113,29 +113,8 @@ struct gb_gpio_set_debounce_request {
 /* debounce response has no payload */
 
 
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int gb_gpio_proto_version_operation(struct gb_gpio_controller *ggc)
-{
-	struct gb_gpio_proto_version_response response;
-	int ret;
-
-	ret = gb_operation_sync(ggc->connection, GB_GPIO_TYPE_PROTOCOL_VERSION,
-				NULL, 0, &response, sizeof(response));
-	if (ret)
-		return ret;
-
-	if (response.major > GB_GPIO_VERSION_MAJOR) {
-		pr_err("unsupported major version (%hhu > %hhu)\n",
-			response.major, GB_GPIO_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-	ggc->version_major = response.major;
-	ggc->version_minor = response.minor;
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_gpio_controller, GPIO);
 
 static int gb_gpio_line_count_operation(struct gb_gpio_controller *ggc)
 {
@@ -446,7 +425,7 @@ static int gb_gpio_controller_setup(struct gb_gpio_controller *gb_gpio_controlle
 	int ret;
 
 	/* First thing we need to do is check the version */
-	ret = gb_gpio_proto_version_operation(gb_gpio_controller);
+	ret = get_version(gb_gpio_controller);
 	if (ret)
 		;	/* return ret; */
 
diff --git a/drivers/staging/greybus/i2c.c b/drivers/staging/greybus/i2c.c
index c967ae3161c5..589691d05750 100644
--- a/drivers/staging/greybus/i2c.c
+++ b/drivers/staging/greybus/i2c.c
@@ -87,30 +87,8 @@ struct gb_i2c_transfer_response {
 	__u8				data[0];	/* inbound data */
 };
 
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int gb_i2c_proto_version_operation(struct gb_i2c_device *gb_i2c_dev)
-{
-	struct gb_i2c_proto_version_response response;
-	int ret;
-
-	ret = gb_operation_sync(gb_i2c_dev->connection,
-				GB_I2C_TYPE_PROTOCOL_VERSION,
-				NULL, 0, &response, sizeof(response));
-	if (ret)
-		return ret;
-
-	if (response.major > GB_I2C_VERSION_MAJOR) {
-		pr_err("unsupported major version (%hhu > %hhu)\n",
-			response.major, GB_I2C_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-	gb_i2c_dev->version_major = response.major;
-	gb_i2c_dev->version_minor = response.minor;
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_i2c_device, I2C);
 
 /*
  * Map Greybus i2c functionality bits into Linux ones
@@ -361,7 +339,7 @@ static int gb_i2c_device_setup(struct gb_i2c_device *gb_i2c_dev)
 	int ret;
 
 	/* First thing we need to do is check the version */
-	ret = gb_i2c_proto_version_operation(gb_i2c_dev);
+	ret = get_version(gb_i2c_dev);
 	if (ret)
 		return ret;
 
diff --git a/drivers/staging/greybus/protocol.c b/drivers/staging/greybus/protocol.c
index 12bbc2f2191f..ae8ab21ee920 100644
--- a/drivers/staging/greybus/protocol.c
+++ b/drivers/staging/greybus/protocol.c
@@ -148,6 +148,32 @@ struct gb_protocol *gb_protocol_get(u8 id, u8 major, u8 minor)
 	return protocol;
 }
 
+int gb_protocol_get_version(struct gb_connection *connection, int type,
+			    void *request, int request_size,
+			    struct gb_protocol_version_response *response,
+			    __u8 major)
+{
+	int retval;
+
+	retval = gb_operation_sync(connection, type, request, request_size,
+				   response, sizeof(*response));
+	if (retval)
+		return retval;
+
+	if (response->major > major) {
+		dev_err(&connection->dev,
+			"unsupported major version (%hhu > %hhu)\n",
+			response->major, major);
+		return -ENOTSUPP;
+	}
+
+	dev_dbg(&connection->dev, "version_major = %u version_minor = %u\n",
+		response->major, response->minor);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gb_protocol_get_version);
+
 void gb_protocol_put(struct gb_protocol *protocol)
 {
 	u8 major;
diff --git a/drivers/staging/greybus/protocol.h b/drivers/staging/greybus/protocol.h
index 8bda524a4d6d..e65cc18f4dfa 100644
--- a/drivers/staging/greybus/protocol.h
+++ b/drivers/staging/greybus/protocol.h
@@ -14,6 +14,12 @@
 
 struct gb_operation;
 
+/* version request has no payload */
+struct gb_protocol_version_response {
+	__u8	major;
+	__u8	minor;
+};
+
 typedef int (*gb_connection_init_t)(struct gb_connection *);
 typedef void (*gb_connection_exit_t)(struct gb_connection *);
 typedef void (*gb_request_recv_t)(u8, struct gb_operation *);
@@ -45,6 +51,11 @@ int gb_protocol_deregister(struct gb_protocol *protocol);
 	__gb_protocol_register(protocol, THIS_MODULE)
 
 struct gb_protocol *gb_protocol_get(u8 id, u8 major, u8 minor);
+int gb_protocol_get_version(struct gb_connection *connection, int type,
+			    void *request, int request_size,
+			    struct gb_protocol_version_response *response,
+			    __u8 major);
+
 void gb_protocol_put(struct gb_protocol *protocol);
 
 /*
@@ -82,4 +93,27 @@ static void __exit protocol_exit(void)			\
 }							\
 module_exit(protocol_exit);
 
+/*
+ * Macro to create get_version() routine for protocols
+ * @__device: name of the device struct
+ * @__protocol: name of protocol in CAPITALS
+ */
+#define define_get_version(__device, __protocol)	\
+static int get_version(struct __device *dev)		\
+{							\
+	struct gb_protocol_version_response response;	\
+	int retval;					\
+							\
+	retval = gb_protocol_get_version(dev->connection,			\
+					 GB_##__protocol##_TYPE_PROTOCOL_VERSION,\
+					 NULL, 0, &response,			\
+					 GB_##__protocol##_VERSION_MAJOR);	\
+	if (retval)					\
+		return retval;				\
+							\
+	dev->version_major = response.major;		\
+	dev->version_minor = response.minor;		\
+	return 0;					\
+}
+
 #endif /* __PROTOCOL_H */
diff --git a/drivers/staging/greybus/pwm.c b/drivers/staging/greybus/pwm.c
index 91f7b87a1cae..7b7252358575 100644
--- a/drivers/staging/greybus/pwm.c
+++ b/drivers/staging/greybus/pwm.c
@@ -79,30 +79,8 @@ struct gb_pwm_disable_request {
 	__u8	which;
 };
 
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int gb_pwm_proto_version_operation(struct gb_pwm_chip *pwmc)
-{
-	struct gb_pwm_proto_version_response response;
-	int ret;
-
-	ret = gb_operation_sync(pwmc->connection, GB_PWM_TYPE_PROTOCOL_VERSION,
-				NULL, 0, &response, sizeof(response));
-
-	if (ret)
-		return ret;
-
-	if (response.major > GB_PWM_VERSION_MAJOR) {
-		pr_err("unsupported major version (%hhu > %hhu)\n",
-			response.major, GB_PWM_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-	pwmc->version_major = response.major;
-	pwmc->version_minor = response.minor;
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_pwm_chip, PWM);
 
 static int gb_pwm_count_operation(struct gb_pwm_chip *pwmc)
 {
@@ -269,7 +247,7 @@ static int gb_pwm_connection_init(struct gb_connection *connection)
 	connection->private = pwmc;
 
 	/* Check for compatible protocol version */
-	ret = gb_pwm_proto_version_operation(pwmc);
+	ret = get_version(pwmc);
 	if (ret)
 		goto out_err;
 
diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c
index 543c88992b0d..d0669ae2d4c1 100644
--- a/drivers/staging/greybus/uart.c
+++ b/drivers/staging/greybus/uart.c
@@ -131,33 +131,8 @@ static DEFINE_IDR(tty_minors);
 static DEFINE_MUTEX(table_lock);
 static atomic_t reference_count = ATOMIC_INIT(0);
 
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int get_version(struct gb_tty *tty)
-{
-	struct gb_uart_proto_version_response response;
-	int ret;
-
-	ret = gb_operation_sync(tty->connection,
-				GB_UART_TYPE_PROTOCOL_VERSION,
-				NULL, 0, &response, sizeof(response));
-	if (ret)
-		return ret;
-
-	if (response.major > GB_UART_VERSION_MAJOR) {
-		pr_err("unsupported major version (%hhu > %hhu)\n",
-			response.major, GB_UART_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-	tty->version_major = response.major;
-	tty->version_minor = response.minor;
-
-	pr_debug("%s: version_major = %u version_minor = %u\n",
-		__func__, tty->version_major, tty->version_minor);
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_tty, UART);
 
 static int send_data(struct gb_tty *tty, u16 size, const u8 *data)
 {
diff --git a/drivers/staging/greybus/usb.c b/drivers/staging/greybus/usb.c
index 010ef9ee831f..c66d7681d4b3 100644
--- a/drivers/staging/greybus/usb.c
+++ b/drivers/staging/greybus/usb.c
@@ -93,26 +93,8 @@ struct gb_usb_device {
 
 #define to_gb_usb_device(d) ((struct gb_usb_device*) d->hcd_priv)
 
-static int get_version(struct gb_usb_device *dev)
-{
-	struct gb_usb_proto_version_response response;
-	int ret;
-
-	ret = gb_operation_sync(dev->connection,
-				GB_USB_TYPE_PROTOCOL_VERSION,
-				NULL, 0, &response, sizeof(response));
-	if (ret)
-		return ret;
-
-	if (response.major > GB_USB_VERSION_MAJOR) {
-		pr_err("unsupported major version (%hhu > %hhu)\n",
-			response.major, GB_USB_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-	dev->version_major = response.major;
-	dev->version_minor = response.minor;
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_usb_device, USB);
 
 static void hcd_stop(struct usb_hcd *hcd)
 {
diff --git a/drivers/staging/greybus/vibrator.c b/drivers/staging/greybus/vibrator.c
index b5332df7039c..141ccdbf7b64 100644
--- a/drivers/staging/greybus/vibrator.c
+++ b/drivers/staging/greybus/vibrator.c
@@ -43,34 +43,8 @@ struct gb_vibrator_on_request {
 	__le16	timeout_ms;
 };
 
-/*
- * This request only uses the connection field, and if successful,
- * fills in the major and minor protocol version of the target.
- */
-static int get_version(struct gb_vibrator_device *vib)
-{
-	struct gb_connection *connection = vib->connection;
-	struct gb_vibrator_proto_version_response version_response;
-	int retval;
-
-	retval = gb_operation_sync(connection,
-				   GB_VIBRATOR_TYPE_PROTOCOL_VERSION,
-				   NULL, 0,
-				   &version_response, sizeof(version_response));
-	if (retval)
-		return retval;
-
-	if (version_response.major > GB_VIBRATOR_VERSION_MAJOR) {
-		dev_err(&connection->dev,
-			"unsupported major version (%hhu > %hhu)\n",
-			version_response.major, GB_VIBRATOR_VERSION_MAJOR);
-		return -ENOTSUPP;
-	}
-
-	vib->version_major = version_response.major;
-	vib->version_minor = version_response.minor;
-	return 0;
-}
+/* Define get_version() routine */
+define_get_version(gb_vibrator_device, VIBRATOR);
 
 static int turn_on(struct gb_vibrator_device *vib, u16 timeout_ms)
 {