soc: qcom: ipc_router: Update transport name from HSIC to USB

Currently the ipc_router_hsic_xprt transport driver which
interfaces with available USB endpoints for IPC message exchange,
uses "hsic" in the code and comments.
Update this string to "usb" and make similar change to filename,
Makefile and Documentation.

Change-Id: I37f8f8dafd85bfde300804b36f1b6f20ed565352
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_hsic_xprt.txt b/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_usb_xprt.txt
similarity index 62%
rename from Documentation/devicetree/bindings/arm/msm/msm_ipc_router_hsic_xprt.txt
rename to Documentation/devicetree/bindings/arm/msm/msm_ipc_router_usb_xprt.txt
index 71d0c0d..e7256af 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_hsic_xprt.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_ipc_router_usb_xprt.txt
@@ -1,17 +1,17 @@
-Qualcomm Technologies, Inc. IPC Router HSIC Transport
+Qualcomm Technologies, Inc. IPC Router USB Transport
 
 Required properties:
--compatible:		should be "qcom,ipc_router_hsic_xprt"
--qcom,ch-name:		the HSIC channel name used by the HSIC transport
+-compatible:		should be "qcom,ipc_router_usb_xprt"
+-qcom,ch-name:		the USB channel name used by the USB transport
 -qcom,xprt-remote:	string that defines the edge of the transport (PIL Name)
 -qcom,xprt-linkid:	unique integer to identify the tier to which the link
 			belongs to in the network and is used to avoid the
 			routing loops while forwarding the broadcast messages
--qcom,xprt-version:	unique version ID used by HSIC transport header
+-qcom,xprt-version:	unique version ID used by USB transport header
 
 Example:
 	qcom,ipc_router_external_modem_xprt {
-		compatible = "qcom,ipc_router_hsic_xprt";
+		compatible = "qcom,ipc-router-usb-xprt";
 	        qcom,ch-name = "ipc_bridge";
 		qcom,xprt-remote = "external-modem";
 		qcom,xprt-linkid = <1>;
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 0e16501..9583336 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -533,15 +533,16 @@
 	  this layer registers a transport with IPC Router and enable
 	  message exchange.
 
-config MSM_IPC_ROUTER_HSIC_XPRT
-	depends on USB_QCOM_IPC_BRIDGE
+config MSM_IPC_ROUTER_USB_XPRT
+	depends on USB_QCOM_IPC_BRIDGE || USB_F_IPC
 	depends on IPC_ROUTER
-	bool "MSM HSIC XPRT Layer"
+	bool "MSM USB XPRT Layer"
 	help
-	  HSIC Transport Layer that enables off-chip communication of
-	  IPC Router. When the HSIC endpoint becomes available, this layer
-	  registers the transport with IPC Router and enable message
-	  exchange.
+	  USB Transport Layer that enables off-chip communication of IPC Router.
+	  When the USB endpoint becomes available, this layer registers the
+	  transport with IPC Router and enable message exchange. This layer is
+	  independent of USB host or device mode IPC bridge and can interface
+	  with only one of them on a given platform.
 
 config MSM_IPC_ROUTER_MHI_XPRT
 	depends on MSM_MHI
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 1da8346..2e59e77 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -57,7 +57,7 @@
 obj-$(CONFIG_MSM_SERVICE_LOCATOR) += service-locator.o
 obj-$(CONFIG_MSM_SMP2P) += msm_smp2p.o smp2p_loopback.o smp2p_debug.o smp2p_sleepstate.o
 obj-$(CONFIG_MSM_IPC_ROUTER_SMD_XPRT) += ipc_router_smd_xprt.o
-obj-$(CONFIG_MSM_IPC_ROUTER_HSIC_XPRT) += ipc_router_hsic_xprt.o
+obj-$(CONFIG_MSM_IPC_ROUTER_USB_XPRT) += ipc_router_usb_xprt.o
 obj-$(CONFIG_MSM_IPC_ROUTER_MHI_XPRT) += ipc_router_mhi_xprt.o
 obj-$(CONFIG_MSM_IPC_ROUTER_GLINK_XPRT) += ipc_router_glink_xprt.o
 obj-$(CONFIG_MSM_QMI_INTERFACE) += qmi_interface.o
diff --git a/drivers/soc/qcom/ipc_router_hsic_xprt.c b/drivers/soc/qcom/ipc_router_hsic_xprt.c
deleted file mode 100644
index 937c9f7..0000000
--- a/drivers/soc/qcom/ipc_router_hsic_xprt.c
+++ /dev/null
@@ -1,784 +0,0 @@
-/* Copyright (c) 2013-2016, The Linux Foundation. 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 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-/*
- * IPC ROUTER HSIC XPRT module.
- */
-#define DEBUG
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/types.h>
-#include <linux/of.h>
-#include <linux/ipc_router_xprt.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <soc/qcom/subsystem_restart.h>
-
-#include <mach/ipc_bridge.h>
-
-static int msm_ipc_router_hsic_xprt_debug_mask;
-module_param_named(debug_mask, msm_ipc_router_hsic_xprt_debug_mask,
-		   int, 0664);
-
-#if defined(DEBUG)
-#define D(x...) do { \
-if (msm_ipc_router_hsic_xprt_debug_mask) \
-	pr_info(x); \
-} while (0)
-#else
-#define D(x...) do { } while (0)
-#endif
-
-#define NUM_HSIC_XPRTS 1
-#define XPRT_NAME_LEN 32
-
-/**
- * msm_ipc_router_hsic_xprt - IPC Router's HSIC XPRT structure
- * @list: IPC router's HSIC XPRTs list.
- * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
- * @xprt_name: Name of the XPRT to be registered with IPC Router.
- * @driver: Platform drivers register by this XPRT.
- * @xprt: IPC Router XPRT structure to contain HSIC XPRT specific info.
- * @pdev: Platform device registered by IPC Bridge function driver.
- * @hsic_xprt_wq: Workqueue to queue read & other XPRT related works.
- * @read_work: Read Work to perform read operation from HSIC's ipc_bridge.
- * @in_pkt: Pointer to any partially read packet.
- * @ss_reset_lock: Lock to protect access to the ss_reset flag.
- * @ss_reset: flag used to check SSR state.
- * @sft_close_complete: Variable to indicate completion of SSR handling
- *                      by IPC Router.
- * @xprt_version: IPC Router header version supported by this XPRT.
- * @xprt_option: XPRT specific options to be handled by IPC Router.
- */
-struct msm_ipc_router_hsic_xprt {
-	struct list_head list;
-	char ch_name[XPRT_NAME_LEN];
-	char xprt_name[XPRT_NAME_LEN];
-	struct platform_driver driver;
-	struct msm_ipc_router_xprt xprt;
-	struct platform_device *pdev;
-	struct workqueue_struct *hsic_xprt_wq;
-	struct delayed_work read_work;
-	struct rr_packet *in_pkt;
-	struct mutex ss_reset_lock;
-	int ss_reset;
-	struct completion sft_close_complete;
-	unsigned int xprt_version;
-	unsigned int xprt_option;
-};
-
-struct msm_ipc_router_hsic_xprt_work {
-	struct msm_ipc_router_xprt *xprt;
-	struct work_struct work;
-};
-
-static void hsic_xprt_read_data(struct work_struct *work);
-
-/**
- * msm_ipc_router_hsic_xprt_config - Config. Info. of each HSIC XPRT
- * @ch_name: Name of the HSIC endpoint exported by ipc_bridge driver.
- * @xprt_name: Name of the XPRT to be registered with IPC Router.
- * @hsic_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
- * @link_id: Network Cluster ID to which this XPRT belongs to.
- * @xprt_version: IPC Router header version supported by this XPRT.
- */
-struct msm_ipc_router_hsic_xprt_config {
-	char ch_name[XPRT_NAME_LEN];
-	char xprt_name[XPRT_NAME_LEN];
-	int hsic_pdev_id;
-	uint32_t link_id;
-	unsigned int xprt_version;
-};
-
-struct msm_ipc_router_hsic_xprt_config hsic_xprt_cfg[] = {
-	{"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 1, 3},
-};
-
-#define MODULE_NAME "ipc_router_hsic_xprt"
-#define IPC_ROUTER_HSIC_XPRT_WAIT_TIMEOUT 3000
-static int ipc_router_hsic_xprt_probe_done;
-static struct delayed_work ipc_router_hsic_xprt_probe_work;
-static DEFINE_MUTEX(hsic_remote_xprt_list_lock_lha1);
-static LIST_HEAD(hsic_remote_xprt_list);
-
-/**
- * find_hsic_xprt_list() - Find xprt item specific to an HSIC endpoint
- * @name: Name of the platform device to find in list
- *
- * @return: pointer to msm_ipc_router_hsic_xprt if matching endpoint is found,
- *		else NULL.
- *
- * This function is used to find specific xprt item from the global xprt list
- */
-static struct msm_ipc_router_hsic_xprt *
-		find_hsic_xprt_list(const char *name)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	mutex_lock(&hsic_remote_xprt_list_lock_lha1);
-	list_for_each_entry(hsic_xprtp, &hsic_remote_xprt_list, list) {
-		if (!strcmp(name, hsic_xprtp->ch_name)) {
-			mutex_unlock(&hsic_remote_xprt_list_lock_lha1);
-			return hsic_xprtp;
-		}
-	}
-	mutex_unlock(&hsic_remote_xprt_list_lock_lha1);
-	return NULL;
-}
-
-/**
- * ipc_router_hsic_set_xprt_version() - Set IPC Router header version
- *                                          in the transport
- * @xprt: Reference to the transport structure.
- * @version: The version to be set in transport.
- */
-static void ipc_router_hsic_set_xprt_version(
-	struct msm_ipc_router_xprt *xprt, unsigned int version)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	if (!xprt)
-		return;
-	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-	hsic_xprtp->xprt_version = version;
-}
-
-/**
- * msm_ipc_router_hsic_get_xprt_version() - Get IPC Router header version
- *                                          supported by the XPRT
- * @xprt: XPRT for which the version information is required.
- *
- * @return: IPC Router header version supported by the XPRT.
- */
-static int msm_ipc_router_hsic_get_xprt_version(
-	struct msm_ipc_router_xprt *xprt)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	if (!xprt)
-		return -EINVAL;
-	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-
-	return (int)hsic_xprtp->xprt_version;
-}
-
-/**
- * msm_ipc_router_hsic_get_xprt_option() - Get XPRT options
- * @xprt: XPRT for which the option information is required.
- *
- * @return: Options supported by the XPRT.
- */
-static int msm_ipc_router_hsic_get_xprt_option(
-	struct msm_ipc_router_xprt *xprt)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	if (!xprt)
-		return -EINVAL;
-	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-
-	return (int)hsic_xprtp->xprt_option;
-}
-
-/**
- * msm_ipc_router_hsic_remote_write_avail() - Get available write space
- * @xprt: XPRT for which the available write space info. is required.
- *
- * @return: Write space in bytes on success, 0 on SSR.
- */
-static int msm_ipc_router_hsic_remote_write_avail(
-	struct msm_ipc_router_xprt *xprt)
-{
-	struct ipc_bridge_platform_data *pdata;
-	int write_avail;
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
-		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-
-	mutex_lock(&hsic_xprtp->ss_reset_lock);
-	if (hsic_xprtp->ss_reset || !hsic_xprtp->pdev) {
-		write_avail = 0;
-	} else {
-		pdata = hsic_xprtp->pdev->dev.platform_data;
-		write_avail = pdata->max_write_size;
-	}
-	mutex_unlock(&hsic_xprtp->ss_reset_lock);
-	return write_avail;
-}
-
-/**
- * msm_ipc_router_hsic_remote_write() - Write to XPRT
- * @data: Data to be written to the XPRT.
- * @len: Length of the data to be written.
- * @xprt: XPRT to which the data has to be written.
- *
- * @return: Data Length on success, standard Linux error codes on failure.
- */
-static int msm_ipc_router_hsic_remote_write(void *data,
-		uint32_t len, struct msm_ipc_router_xprt *xprt)
-{
-	struct rr_packet *pkt = (struct rr_packet *)data;
-	struct sk_buff *skb;
-	struct ipc_bridge_platform_data *pdata;
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-	int ret;
-	uint32_t bytes_written = 0;
-	uint32_t bytes_to_write;
-	unsigned char *tx_data;
-
-	if (!pkt || pkt->length != len || !xprt) {
-		IPC_RTR_ERR("%s: Invalid input parameters\n", __func__);
-		return -EINVAL;
-	}
-
-	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-	mutex_lock(&hsic_xprtp->ss_reset_lock);
-	if (hsic_xprtp->ss_reset) {
-		IPC_RTR_ERR("%s: Trying to write on a reset link\n", __func__);
-		mutex_unlock(&hsic_xprtp->ss_reset_lock);
-		return -ENETRESET;
-	}
-
-	if (!hsic_xprtp->pdev) {
-		IPC_RTR_ERR("%s: Trying to write on a closed link\n", __func__);
-		mutex_unlock(&hsic_xprtp->ss_reset_lock);
-		return -ENODEV;
-	}
-
-	pdata = hsic_xprtp->pdev->dev.platform_data;
-	if (!pdata || !pdata->write) {
-		IPC_RTR_ERR("%s on a uninitialized link\n", __func__);
-		mutex_unlock(&hsic_xprtp->ss_reset_lock);
-		return -EFAULT;
-	}
-
-	skb = skb_peek(pkt->pkt_fragment_q);
-	if (!skb) {
-		IPC_RTR_ERR("%s SKB is NULL\n", __func__);
-		mutex_unlock(&hsic_xprtp->ss_reset_lock);
-		return -EINVAL;
-	}
-	D("%s: About to write %d bytes\n", __func__, len);
-
-	while (bytes_written < len) {
-		bytes_to_write = min_t(uint32_t, (skb->len - bytes_written),
-				       pdata->max_write_size);
-		tx_data = skb->data + bytes_written;
-		ret = pdata->write(hsic_xprtp->pdev, tx_data, bytes_to_write);
-		if (ret < 0) {
-			IPC_RTR_ERR("%s: Error writing data %d\n",
-				    __func__, ret);
-			break;
-		}
-		if (ret != bytes_to_write)
-			IPC_RTR_ERR("%s: Partial write %d < %d, retrying...\n",
-				    __func__, ret, bytes_to_write);
-		bytes_written += bytes_to_write;
-	}
-	if (bytes_written == len) {
-		ret = bytes_written;
-	} else if (ret > 0 && bytes_written != len) {
-		IPC_RTR_ERR("%s: Fault writing data %d != %d\n",
-			    __func__, bytes_written, len);
-		ret = -EFAULT;
-	}
-	D("%s: Finished writing %d bytes\n", __func__, len);
-	mutex_unlock(&hsic_xprtp->ss_reset_lock);
-	return ret;
-}
-
-/**
- * msm_ipc_router_hsic_remote_close() - Close the XPRT
- * @xprt: XPRT which needs to be closed.
- *
- * @return: 0 on success, standard Linux error codes on failure.
- */
-static int msm_ipc_router_hsic_remote_close(
-	struct msm_ipc_router_xprt *xprt)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-	struct ipc_bridge_platform_data *pdata;
-
-	if (!xprt)
-		return -EINVAL;
-	hsic_xprtp = container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-
-	mutex_lock(&hsic_xprtp->ss_reset_lock);
-	hsic_xprtp->ss_reset = 1;
-	mutex_unlock(&hsic_xprtp->ss_reset_lock);
-	flush_workqueue(hsic_xprtp->hsic_xprt_wq);
-	destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
-	pdata = hsic_xprtp->pdev->dev.platform_data;
-	if (pdata && pdata->close)
-		pdata->close(hsic_xprtp->pdev);
-	hsic_xprtp->pdev = NULL;
-	return 0;
-}
-
-/**
- * hsic_xprt_read_data() - Read work to read from the XPRT
- * @work: Read work to be executed.
- *
- * This function is a read work item queued on a XPRT specific workqueue.
- * The work parameter contains information regarding the XPRT on which this
- * read work has to be performed. The work item keeps reading from the HSIC
- * endpoint, until the endpoint returns an error.
- */
-static void hsic_xprt_read_data(struct work_struct *work)
-{
-	int bytes_to_read;
-	int bytes_read;
-	int skb_size;
-	struct sk_buff *skb = NULL;
-	struct ipc_bridge_platform_data *pdata;
-	struct delayed_work *rwork = to_delayed_work(work);
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
-		container_of(rwork, struct msm_ipc_router_hsic_xprt, read_work);
-
-	while (1) {
-		mutex_lock(&hsic_xprtp->ss_reset_lock);
-		if (hsic_xprtp->ss_reset) {
-			mutex_unlock(&hsic_xprtp->ss_reset_lock);
-			break;
-		}
-		pdata = hsic_xprtp->pdev->dev.platform_data;
-		mutex_unlock(&hsic_xprtp->ss_reset_lock);
-		while (!hsic_xprtp->in_pkt) {
-			hsic_xprtp->in_pkt = create_pkt(NULL);
-			if (hsic_xprtp->in_pkt)
-				break;
-			IPC_RTR_ERR("%s: packet allocation failure\n",
-								__func__);
-			msleep(100);
-		}
-		D("%s: Allocated rr_packet\n", __func__);
-
-		bytes_to_read = 0;
-		skb_size = pdata->max_read_size;
-		do {
-			do {
-				skb = alloc_skb(skb_size, GFP_KERNEL);
-				if (skb)
-					break;
-				IPC_RTR_ERR("%s: Couldn't alloc SKB\n",
-					    __func__);
-				msleep(100);
-			} while (!skb);
-			bytes_read = pdata->read(hsic_xprtp->pdev, skb->data,
-						 pdata->max_read_size);
-			if (bytes_read < 0) {
-				IPC_RTR_ERR("%s: Error %d @ read operation\n",
-					    __func__, bytes_read);
-				kfree_skb(skb);
-				goto out_read_data;
-			}
-			if (!bytes_to_read) {
-				bytes_to_read = ipc_router_peek_pkt_size(
-						skb->data);
-				if (bytes_to_read < 0) {
-					IPC_RTR_ERR("%s: Invalid size %d\n",
-						__func__, bytes_to_read);
-					kfree_skb(skb);
-					goto out_read_data;
-				}
-			}
-			bytes_to_read -= bytes_read;
-			skb_put(skb, bytes_read);
-			skb_queue_tail(hsic_xprtp->in_pkt->pkt_fragment_q, skb);
-			hsic_xprtp->in_pkt->length += bytes_read;
-			skb_size = min_t(uint32_t, pdata->max_read_size,
-					 (uint32_t)bytes_to_read);
-		} while (bytes_to_read > 0);
-
-		D("%s: Packet size read %d\n",
-		  __func__, hsic_xprtp->in_pkt->length);
-		msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
-			IPC_ROUTER_XPRT_EVENT_DATA, (void *)hsic_xprtp->in_pkt);
-		release_pkt(hsic_xprtp->in_pkt);
-		hsic_xprtp->in_pkt = NULL;
-	}
-out_read_data:
-	release_pkt(hsic_xprtp->in_pkt);
-	hsic_xprtp->in_pkt = NULL;
-}
-
-/**
- * hsic_xprt_sft_close_done() - Completion of XPRT reset
- * @xprt: XPRT on which the reset operation is complete.
- *
- * This function is used by IPC Router to signal this HSIC XPRT Abstraction
- * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
- */
-static void hsic_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp =
-		container_of(xprt, struct msm_ipc_router_hsic_xprt, xprt);
-
-	complete_all(&hsic_xprtp->sft_close_complete);
-}
-
-/**
- * msm_ipc_router_hsic_remote_remove() - Remove an HSIC endpoint
- * @pdev: Platform device corresponding to HSIC endpoint.
- *
- * @return: 0 on success, standard Linux error codes on error.
- *
- * This function is called when the underlying ipc_bridge driver unregisters
- * a platform device, mapped to an HSIC endpoint, during SSR.
- */
-static int msm_ipc_router_hsic_remote_remove(struct platform_device *pdev)
-{
-	struct ipc_bridge_platform_data *pdata;
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	hsic_xprtp = find_hsic_xprt_list(pdev->name);
-	if (!hsic_xprtp) {
-		IPC_RTR_ERR("%s No device with name %s\n",
-					__func__, pdev->name);
-		return -ENODEV;
-	}
-
-	mutex_lock(&hsic_xprtp->ss_reset_lock);
-	hsic_xprtp->ss_reset = 1;
-	mutex_unlock(&hsic_xprtp->ss_reset_lock);
-	flush_workqueue(hsic_xprtp->hsic_xprt_wq);
-	destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
-	init_completion(&hsic_xprtp->sft_close_complete);
-	msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
-				   IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
-	D("%s: Notified IPC Router of %s CLOSE\n",
-	  __func__, hsic_xprtp->xprt.name);
-	wait_for_completion(&hsic_xprtp->sft_close_complete);
-	hsic_xprtp->pdev = NULL;
-	pdata = pdev->dev.platform_data;
-	if (pdata && pdata->close)
-		pdata->close(pdev);
-	return 0;
-}
-
-/**
- * msm_ipc_router_hsic_remote_probe() - Probe an HSIC endpoint
- * @pdev: Platform device corresponding to HSIC endpoint.
- *
- * @return: 0 on success, standard Linux error codes on error.
- *
- * This function is called when the underlying ipc_bridge driver registers
- * a platform device, mapped to an HSIC endpoint.
- */
-static int msm_ipc_router_hsic_remote_probe(struct platform_device *pdev)
-{
-	int rc;
-	struct ipc_bridge_platform_data *pdata;
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	pdata = pdev->dev.platform_data;
-	if (!pdata || !pdata->open || !pdata->read ||
-	    !pdata->write || !pdata->close) {
-		IPC_RTR_ERR("%s: pdata or pdata->operations is NULL\n",
-								__func__);
-		return -EINVAL;
-	}
-
-	hsic_xprtp = find_hsic_xprt_list(pdev->name);
-	if (!hsic_xprtp) {
-		IPC_RTR_ERR("%s No device with name %s\n",
-						__func__, pdev->name);
-		return -ENODEV;
-	}
-
-	hsic_xprtp->hsic_xprt_wq =
-		create_singlethread_workqueue(pdev->name);
-	if (!hsic_xprtp->hsic_xprt_wq) {
-		IPC_RTR_ERR("%s: WQ creation failed for %s\n",
-			__func__, pdev->name);
-		return -EFAULT;
-	}
-
-	rc = pdata->open(pdev);
-	if (rc < 0) {
-		IPC_RTR_ERR("%s: Channel open failed for %s.%d\n",
-			__func__, pdev->name, pdev->id);
-		destroy_workqueue(hsic_xprtp->hsic_xprt_wq);
-		return rc;
-	}
-	hsic_xprtp->pdev = pdev;
-	mutex_lock(&hsic_xprtp->ss_reset_lock);
-	hsic_xprtp->ss_reset = 0;
-	mutex_unlock(&hsic_xprtp->ss_reset_lock);
-	msm_ipc_router_xprt_notify(&hsic_xprtp->xprt,
-				   IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
-	D("%s: Notified IPC Router of %s OPEN\n",
-	  __func__, hsic_xprtp->xprt.name);
-	queue_delayed_work(hsic_xprtp->hsic_xprt_wq,
-			   &hsic_xprtp->read_work, 0);
-	return 0;
-}
-
-/**
- * msm_ipc_router_hsic_driver_register() - register HSIC XPRT drivers
- *
- * @hsic_xprtp: pointer to IPC router hsic xprt structure.
- *
- * @return: 0 on success, standard Linux error codes on error.
- *
- * This function is called when a new XPRT is added to register platform
- * drivers for new XPRT.
- */
-static int msm_ipc_router_hsic_driver_register(
-			struct msm_ipc_router_hsic_xprt *hsic_xprtp)
-{
-	int ret;
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp_item;
-
-	hsic_xprtp_item = find_hsic_xprt_list(hsic_xprtp->ch_name);
-
-	mutex_lock(&hsic_remote_xprt_list_lock_lha1);
-	list_add(&hsic_xprtp->list, &hsic_remote_xprt_list);
-	mutex_unlock(&hsic_remote_xprt_list_lock_lha1);
-
-	if (!hsic_xprtp_item) {
-		hsic_xprtp->driver.driver.name = hsic_xprtp->ch_name;
-		hsic_xprtp->driver.driver.owner = THIS_MODULE;
-		hsic_xprtp->driver.probe = msm_ipc_router_hsic_remote_probe;
-		hsic_xprtp->driver.remove = msm_ipc_router_hsic_remote_remove;
-
-		ret = platform_driver_register(&hsic_xprtp->driver);
-		if (ret) {
-			IPC_RTR_ERR(
-			"%s: Failed to register platform driver[%s]\n",
-					__func__, hsic_xprtp->ch_name);
-			return ret;
-		}
-	} else {
-		IPC_RTR_ERR("%s Already driver registered %s\n",
-					__func__, hsic_xprtp->ch_name);
-	}
-
-	return 0;
-}
-
-/**
- * msm_ipc_router_hsic_config_init() - init HSIC xprt configs
- *
- * @hsic_xprt_config: pointer to HSIC xprt configurations.
- *
- * @return: 0 on success, standard Linux error codes on error.
- *
- * This function is called to initialize the HSIC XPRT pointer with
- * the HSIC XPRT configurations either from device tree or static arrays.
- */
-static int msm_ipc_router_hsic_config_init(
-		struct msm_ipc_router_hsic_xprt_config *hsic_xprt_config)
-{
-	struct msm_ipc_router_hsic_xprt *hsic_xprtp;
-
-	hsic_xprtp = kzalloc(sizeof(struct msm_ipc_router_hsic_xprt),
-							GFP_KERNEL);
-	if (IS_ERR_OR_NULL(hsic_xprtp)) {
-		IPC_RTR_ERR("%s: kzalloc() failed for hsic_xprtp id:%s\n",
-				__func__, hsic_xprt_config->ch_name);
-		return -ENOMEM;
-	}
-
-	hsic_xprtp->xprt.link_id = hsic_xprt_config->link_id;
-	hsic_xprtp->xprt_version = hsic_xprt_config->xprt_version;
-
-	strlcpy(hsic_xprtp->ch_name, hsic_xprt_config->ch_name,
-					XPRT_NAME_LEN);
-
-	strlcpy(hsic_xprtp->xprt_name, hsic_xprt_config->xprt_name,
-						XPRT_NAME_LEN);
-	hsic_xprtp->xprt.name = hsic_xprtp->xprt_name;
-
-	hsic_xprtp->xprt.set_version =
-		ipc_router_hsic_set_xprt_version;
-	hsic_xprtp->xprt.get_version =
-		msm_ipc_router_hsic_get_xprt_version;
-	hsic_xprtp->xprt.get_option =
-		 msm_ipc_router_hsic_get_xprt_option;
-	hsic_xprtp->xprt.read_avail = NULL;
-	hsic_xprtp->xprt.read = NULL;
-	hsic_xprtp->xprt.write_avail =
-		msm_ipc_router_hsic_remote_write_avail;
-	hsic_xprtp->xprt.write = msm_ipc_router_hsic_remote_write;
-	hsic_xprtp->xprt.close = msm_ipc_router_hsic_remote_close;
-	hsic_xprtp->xprt.sft_close_done = hsic_xprt_sft_close_done;
-	hsic_xprtp->xprt.priv = NULL;
-
-	hsic_xprtp->in_pkt = NULL;
-	INIT_DELAYED_WORK(&hsic_xprtp->read_work, hsic_xprt_read_data);
-	mutex_init(&hsic_xprtp->ss_reset_lock);
-	hsic_xprtp->ss_reset = 0;
-	hsic_xprtp->xprt_option = 0;
-
-	msm_ipc_router_hsic_driver_register(hsic_xprtp);
-	return 0;
-
-}
-
-/**
- * parse_devicetree() - parse device tree binding
- *
- * @node: pointer to device tree node
- * @hsic_xprt_config: pointer to HSIC XPRT configurations
- *
- * @return: 0 on success, -ENODEV on failure.
- */
-static int parse_devicetree(struct device_node *node,
-		struct msm_ipc_router_hsic_xprt_config *hsic_xprt_config)
-{
-	int ret;
-	int link_id;
-	int version;
-	char *key;
-	const char *ch_name;
-	const char *remote_ss;
-
-	key = "qcom,ch-name";
-	ch_name = of_get_property(node, key, NULL);
-	if (!ch_name)
-		goto error;
-	strlcpy(hsic_xprt_config->ch_name, ch_name, XPRT_NAME_LEN);
-
-	key = "qcom,xprt-remote";
-	remote_ss = of_get_property(node, key, NULL);
-	if (!remote_ss)
-		goto error;
-
-	key = "qcom,xprt-linkid";
-	ret = of_property_read_u32(node, key, &link_id);
-	if (ret)
-		goto error;
-	hsic_xprt_config->link_id = link_id;
-
-	key = "qcom,xprt-version";
-	ret = of_property_read_u32(node, key, &version);
-	if (ret)
-		goto error;
-	hsic_xprt_config->xprt_version = version;
-
-	scnprintf(hsic_xprt_config->xprt_name, XPRT_NAME_LEN, "%s_%s",
-			remote_ss, hsic_xprt_config->ch_name);
-
-	return 0;
-
-error:
-	IPC_RTR_ERR("%s: missing key: %s\n", __func__, key);
-	return -ENODEV;
-}
-
-/**
- * msm_ipc_router_hsic_xprt_probe() - Probe an HSIC xprt
- * @pdev: Platform device corresponding to HSIC xprt.
- *
- * @return: 0 on success, standard Linux error codes on error.
- *
- * This function is called when the underlying device tree driver registers
- * a platform device, mapped to an HSIC transport.
- */
-static int msm_ipc_router_hsic_xprt_probe(
-				struct platform_device *pdev)
-{
-	int ret;
-	struct msm_ipc_router_hsic_xprt_config hsic_xprt_config;
-
-	if (pdev && pdev->dev.of_node) {
-		mutex_lock(&hsic_remote_xprt_list_lock_lha1);
-		ipc_router_hsic_xprt_probe_done = 1;
-		mutex_unlock(&hsic_remote_xprt_list_lock_lha1);
-
-		ret = parse_devicetree(pdev->dev.of_node,
-						&hsic_xprt_config);
-		if (ret) {
-			IPC_RTR_ERR("%s: Failed to parse device tree\n",
-								__func__);
-			return ret;
-		}
-
-		ret = msm_ipc_router_hsic_config_init(
-						&hsic_xprt_config);
-		if (ret) {
-			IPC_RTR_ERR(" %s init failed\n", __func__);
-			return ret;
-		}
-	}
-	return ret;
-}
-
-/**
- * ipc_router_hsic_xprt_probe_worker() - probe worker for non DT configurations
- *
- * @work: work item to process
- *
- * This function is called by schedule_delay_work after 3sec and check if
- * device tree probe is done or not. If device tree probe fails the default
- * configurations read from static array.
- */
-static void ipc_router_hsic_xprt_probe_worker(struct work_struct *work)
-{
-	int i, ret;
-
-	if (WARN_ON(ARRAY_SIZE(hsic_xprt_cfg) != NUM_HSIC_XPRTS))
-		return;
-
-	mutex_lock(&hsic_remote_xprt_list_lock_lha1);
-	if (!ipc_router_hsic_xprt_probe_done) {
-		mutex_unlock(&hsic_remote_xprt_list_lock_lha1);
-		for (i = 0; i < ARRAY_SIZE(hsic_xprt_cfg); i++) {
-			ret = msm_ipc_router_hsic_config_init(
-							&hsic_xprt_cfg[i]);
-			if (ret)
-				IPC_RTR_ERR(" %s init failed config idx %d\n",
-								__func__, i);
-		}
-		mutex_lock(&hsic_remote_xprt_list_lock_lha1);
-	}
-	mutex_unlock(&hsic_remote_xprt_list_lock_lha1);
-}
-
-static const struct of_device_id msm_ipc_router_hsic_xprt_match_table[] = {
-	{ .compatible = "qcom,ipc_router_hsic_xprt" },
-	{},
-};
-
-static struct platform_driver msm_ipc_router_hsic_xprt_driver = {
-	.probe = msm_ipc_router_hsic_xprt_probe,
-	.driver = {
-		.name = MODULE_NAME,
-		.owner = THIS_MODULE,
-		.of_match_table = msm_ipc_router_hsic_xprt_match_table,
-	 },
-};
-
-static int __init msm_ipc_router_hsic_xprt_init(void)
-{
-	int rc;
-
-	rc = platform_driver_register(&msm_ipc_router_hsic_xprt_driver);
-	if (rc) {
-		IPC_RTR_ERR(
-		"%s: msm_ipc_router_hsic_xprt_driver register failed %d\n",
-								__func__, rc);
-		return rc;
-	}
-
-	INIT_DELAYED_WORK(&ipc_router_hsic_xprt_probe_work,
-					ipc_router_hsic_xprt_probe_worker);
-	schedule_delayed_work(&ipc_router_hsic_xprt_probe_work,
-			msecs_to_jiffies(IPC_ROUTER_HSIC_XPRT_WAIT_TIMEOUT));
-	return 0;
-}
-
-module_init(msm_ipc_router_hsic_xprt_init);
-MODULE_DESCRIPTION("IPC Router HSIC XPRT");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/ipc_router_usb_xprt.c b/drivers/soc/qcom/ipc_router_usb_xprt.c
new file mode 100644
index 0000000..0c6fda6
--- /dev/null
+++ b/drivers/soc/qcom/ipc_router_usb_xprt.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2013-2016, 2018 The Linux Foundation. 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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * IPC ROUTER USB XPRT module.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/ipc_router_xprt.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <soc/qcom/subsystem_restart.h>
+
+#include <linux/usb/ipc_bridge.h>
+
+static int msm_ipc_router_usb_xprt_debug_mask;
+module_param_named(debug_mask, msm_ipc_router_usb_xprt_debug_mask,
+		   int, 0664);
+
+#define D(x...) do { \
+if (msm_ipc_router_usb_xprt_debug_mask) \
+	pr_info(x); \
+} while (0)
+
+#define NUM_USB_XPRTS 1
+#define XPRT_NAME_LEN 32
+
+/**
+ * msm_ipc_router_usb_xprt - IPC Router's USB XPRT structure
+ * @list: IPC router's USB XPRTs list.
+ * @ch_name: Name of the USB endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @driver: Platform drivers register by this XPRT.
+ * @xprt: IPC Router XPRT structure to contain USB XPRT specific info.
+ * @pdev: Platform device registered by IPC Bridge function driver.
+ * @usb_xprt_wq: Workqueue to queue read & other XPRT related works.
+ * @read_work: Read Work to perform read operation from USB's ipc_bridge.
+ * @in_pkt: Pointer to any partially read packet.
+ * @ss_reset_lock: Lock to protect access to the ss_reset flag.
+ * @ss_reset: flag used to check SSR state.
+ * @sft_close_complete: Variable to indicate completion of SSR handling
+ *                      by IPC Router.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ * @xprt_option: XPRT specific options to be handled by IPC Router.
+ */
+struct msm_ipc_router_usb_xprt {
+	struct list_head list;
+	char ch_name[XPRT_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	struct platform_driver driver;
+	struct msm_ipc_router_xprt xprt;
+	struct platform_device *pdev;
+	struct workqueue_struct *usb_xprt_wq;
+	struct delayed_work read_work;
+	struct rr_packet *in_pkt;
+	struct mutex ss_reset_lock;
+	int ss_reset;
+	struct completion sft_close_complete;
+	unsigned int xprt_version;
+	unsigned int xprt_option;
+};
+
+struct msm_ipc_router_usb_xprt_work {
+	struct msm_ipc_router_xprt *xprt;
+	struct work_struct work;
+};
+
+static void usb_xprt_read_data(struct work_struct *work);
+
+/**
+ * msm_ipc_router_usb_xprt_config - Config. Info. of each USB XPRT
+ * @ch_name: Name of the USB endpoint exported by ipc_bridge driver.
+ * @xprt_name: Name of the XPRT to be registered with IPC Router.
+ * @usb_pdev_id: ID to differentiate among multiple ipc_bridge endpoints.
+ * @link_id: Network Cluster ID to which this XPRT belongs to.
+ * @xprt_version: IPC Router header version supported by this XPRT.
+ */
+struct msm_ipc_router_usb_xprt_config {
+	char ch_name[XPRT_NAME_LEN];
+	char xprt_name[XPRT_NAME_LEN];
+	int usb_pdev_id;
+	uint32_t link_id;
+	unsigned int xprt_version;
+};
+
+static struct msm_ipc_router_usb_xprt_config usb_xprt_cfg[] = {
+	{"ipc_bridge", "ipc_rtr_ipc_bridge1", 1, 2, 3},
+};
+
+#define MODULE_NAME "ipc_router_usb_xprt"
+#define IPC_ROUTER_USB_XPRT_WAIT_TIMEOUT 3000
+static int ipc_router_usb_xprt_probe_done;
+static struct delayed_work ipc_router_usb_xprt_probe_work;
+static DEFINE_MUTEX(usb_remote_xprt_list_lock_lha1);
+static LIST_HEAD(usb_remote_xprt_list);
+
+/**
+ * find_usb_xprt_list() - Find xprt item specific to an USB endpoint
+ * @name: Name of the platform device to find in list
+ *
+ * @return: pointer to msm_ipc_router_usb_xprt if matching endpoint is found,
+ *		else NULL.
+ *
+ * This function is used to find specific xprt item from the global xprt list
+ */
+static struct msm_ipc_router_usb_xprt *
+		find_usb_xprt_list(const char *name)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	mutex_lock(&usb_remote_xprt_list_lock_lha1);
+	list_for_each_entry(usb_xprtp, &usb_remote_xprt_list, list) {
+		if (!strcmp(name, usb_xprtp->ch_name)) {
+			mutex_unlock(&usb_remote_xprt_list_lock_lha1);
+			return usb_xprtp;
+		}
+	}
+	mutex_unlock(&usb_remote_xprt_list_lock_lha1);
+	return NULL;
+}
+
+/**
+ * ipc_router_usb_set_xprt_version() - Set IPC Router header version
+ *                                          in the transport
+ * @xprt: Reference to the transport structure.
+ * @version: The version to be set in transport.
+ */
+static void ipc_router_usb_set_xprt_version(
+	struct msm_ipc_router_xprt *xprt, unsigned int version)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	if (!xprt)
+		return;
+	usb_xprtp = container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+	usb_xprtp->xprt_version = version;
+}
+
+/**
+ * msm_ipc_router_usb_get_xprt_version() - Get IPC Router header version
+ *                                          supported by the XPRT
+ * @xprt: XPRT for which the version information is required.
+ *
+ * @return: IPC Router header version supported by the XPRT.
+ */
+static int msm_ipc_router_usb_get_xprt_version(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	if (!xprt)
+		return -EINVAL;
+	usb_xprtp = container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+
+	return (int)usb_xprtp->xprt_version;
+}
+
+/**
+ * msm_ipc_router_usb_get_xprt_option() - Get XPRT options
+ * @xprt: XPRT for which the option information is required.
+ *
+ * @return: Options supported by the XPRT.
+ */
+static int msm_ipc_router_usb_get_xprt_option(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	if (!xprt)
+		return -EINVAL;
+	usb_xprtp = container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+
+	return (int)usb_xprtp->xprt_option;
+}
+
+/**
+ * msm_ipc_router_usb_remote_write_avail() - Get available write space
+ * @xprt: XPRT for which the available write space info. is required.
+ *
+ * @return: Write space in bytes on success, 0 on SSR.
+ */
+static int msm_ipc_router_usb_remote_write_avail(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct ipc_bridge_platform_data *pdata;
+	int write_avail;
+	struct msm_ipc_router_usb_xprt *usb_xprtp =
+		container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+
+	mutex_lock(&usb_xprtp->ss_reset_lock);
+	if (usb_xprtp->ss_reset || !usb_xprtp->pdev) {
+		write_avail = 0;
+	} else {
+		pdata = usb_xprtp->pdev->dev.platform_data;
+		write_avail = pdata->max_write_size;
+	}
+	mutex_unlock(&usb_xprtp->ss_reset_lock);
+	return write_avail;
+}
+
+/**
+ * msm_ipc_router_usb_remote_write() - Write to XPRT
+ * @data: Data to be written to the XPRT.
+ * @len: Length of the data to be written.
+ * @xprt: XPRT to which the data has to be written.
+ *
+ * @return: Data Length on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_usb_remote_write(void *data,
+		uint32_t len, struct msm_ipc_router_xprt *xprt)
+{
+	struct rr_packet *pkt = (struct rr_packet *)data;
+	struct sk_buff *skb;
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+	int ret;
+	uint32_t bytes_written = 0;
+	uint32_t bytes_to_write;
+	unsigned char *tx_data;
+
+	if (!pkt || pkt->length != len || !xprt) {
+		IPC_RTR_ERR("%s: Invalid input parameters\n", __func__);
+		return -EINVAL;
+	}
+
+	usb_xprtp = container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+	mutex_lock(&usb_xprtp->ss_reset_lock);
+	if (usb_xprtp->ss_reset) {
+		IPC_RTR_ERR("%s: Trying to write on a reset link\n", __func__);
+		mutex_unlock(&usb_xprtp->ss_reset_lock);
+		return -ENETRESET;
+	}
+
+	if (!usb_xprtp->pdev) {
+		IPC_RTR_ERR("%s: Trying to write on a closed link\n", __func__);
+		mutex_unlock(&usb_xprtp->ss_reset_lock);
+		return -ENODEV;
+	}
+
+	pdata = usb_xprtp->pdev->dev.platform_data;
+	if (!pdata || !pdata->write) {
+		IPC_RTR_ERR("%s on a uninitialized link\n", __func__);
+		mutex_unlock(&usb_xprtp->ss_reset_lock);
+		return -EFAULT;
+	}
+
+	skb = skb_peek(pkt->pkt_fragment_q);
+	if (!skb) {
+		IPC_RTR_ERR("%s SKB is NULL\n", __func__);
+		mutex_unlock(&usb_xprtp->ss_reset_lock);
+		return -EINVAL;
+	}
+
+	if (len > pdata->max_write_size)
+		pr_warn("%s: Data size exceeds max write size %d\n",
+					__func__, pdata->max_write_size);
+
+	D("%s: About to write %d bytes\n", __func__, len);
+
+	while (bytes_written < len) {
+		bytes_to_write = min_t(uint32_t, (skb->len - bytes_written),
+				       pdata->max_write_size);
+		tx_data = skb->data + bytes_written;
+		ret = pdata->write(usb_xprtp->pdev, tx_data, bytes_to_write);
+		if (ret < 0) {
+			IPC_RTR_ERR("%s: Error writing data %d\n",
+				    __func__, ret);
+			break;
+		}
+		if (ret != bytes_to_write)
+			IPC_RTR_ERR("%s: Partial write %d < %d, retrying...\n",
+				    __func__, ret, bytes_to_write);
+		bytes_written += bytes_to_write;
+	}
+	if (bytes_written == len) {
+		ret = bytes_written;
+	} else if (ret > 0 && bytes_written != len) {
+		IPC_RTR_ERR("%s: Fault writing data %d != %d\n",
+			    __func__, bytes_written, len);
+		ret = -EFAULT;
+	}
+	D("%s: Finished writing %d bytes\n", __func__, len);
+	mutex_unlock(&usb_xprtp->ss_reset_lock);
+	return ret;
+}
+
+/**
+ * msm_ipc_router_usb_remote_close() - Close the XPRT
+ * @xprt: XPRT which needs to be closed.
+ *
+ * @return: 0 on success, standard Linux error codes on failure.
+ */
+static int msm_ipc_router_usb_remote_close(
+	struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+	struct ipc_bridge_platform_data *pdata;
+
+	if (!xprt)
+		return -EINVAL;
+	usb_xprtp = container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+
+	mutex_lock(&usb_xprtp->ss_reset_lock);
+	usb_xprtp->ss_reset = 1;
+	mutex_unlock(&usb_xprtp->ss_reset_lock);
+	flush_workqueue(usb_xprtp->usb_xprt_wq);
+	destroy_workqueue(usb_xprtp->usb_xprt_wq);
+	pdata = usb_xprtp->pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(usb_xprtp->pdev);
+	usb_xprtp->pdev = NULL;
+	return 0;
+}
+
+/**
+ * usb_xprt_read_data() - Read work to read from the XPRT
+ * @work: Read work to be executed.
+ *
+ * This function is a read work item queued on a XPRT specific workqueue.
+ * The work parameter contains information regarding the XPRT on which this
+ * read work has to be performed. The work item keeps reading from the USB
+ * endpoint, until the endpoint returns an error.
+ */
+static void usb_xprt_read_data(struct work_struct *work)
+{
+	int bytes_to_read;
+	int bytes_read;
+	int skb_size;
+	struct sk_buff *skb = NULL;
+	struct ipc_bridge_platform_data *pdata;
+	struct delayed_work *rwork = to_delayed_work(work);
+	struct msm_ipc_router_usb_xprt *usb_xprtp =
+		container_of(rwork, struct msm_ipc_router_usb_xprt, read_work);
+
+	while (1) {
+		mutex_lock(&usb_xprtp->ss_reset_lock);
+		if (usb_xprtp->ss_reset) {
+			mutex_unlock(&usb_xprtp->ss_reset_lock);
+			break;
+		}
+		pdata = usb_xprtp->pdev->dev.platform_data;
+		mutex_unlock(&usb_xprtp->ss_reset_lock);
+		while (!usb_xprtp->in_pkt) {
+			usb_xprtp->in_pkt = create_pkt(NULL);
+			if (usb_xprtp->in_pkt)
+				break;
+			IPC_RTR_ERR("%s: packet allocation failure\n",
+								__func__);
+			msleep(100);
+		}
+		D("%s: Allocated rr_packet\n", __func__);
+
+		bytes_to_read = 0;
+		skb_size = pdata->max_read_size;
+		do {
+			do {
+				skb = alloc_skb(skb_size, GFP_KERNEL);
+				if (skb)
+					break;
+				IPC_RTR_ERR("%s: Couldn't alloc SKB\n",
+					    __func__);
+				msleep(100);
+			} while (!skb);
+			bytes_read = pdata->read(usb_xprtp->pdev, skb->data,
+						 pdata->max_read_size);
+			if (bytes_read < 0) {
+				IPC_RTR_ERR("%s: Error %d @ read operation\n",
+					    __func__, bytes_read);
+				kfree_skb(skb);
+				goto out_read_data;
+			}
+			if (!bytes_to_read) {
+				bytes_to_read = ipc_router_peek_pkt_size(
+						skb->data);
+				if (bytes_to_read < 0) {
+					IPC_RTR_ERR("%s: Invalid size %d\n",
+						__func__, bytes_to_read);
+					kfree_skb(skb);
+					goto out_read_data;
+				}
+			}
+			bytes_to_read -= bytes_read;
+			skb_put(skb, bytes_read);
+			skb_queue_tail(usb_xprtp->in_pkt->pkt_fragment_q, skb);
+			usb_xprtp->in_pkt->length += bytes_read;
+			skb_size = min_t(uint32_t, pdata->max_read_size,
+					 (uint32_t)bytes_to_read);
+		} while (bytes_to_read > 0);
+
+		D("%s: Packet size read %d\n",
+		  __func__, usb_xprtp->in_pkt->length);
+		msm_ipc_router_xprt_notify(&usb_xprtp->xprt,
+			IPC_ROUTER_XPRT_EVENT_DATA, (void *)usb_xprtp->in_pkt);
+		release_pkt(usb_xprtp->in_pkt);
+		usb_xprtp->in_pkt = NULL;
+	}
+out_read_data:
+	release_pkt(usb_xprtp->in_pkt);
+	usb_xprtp->in_pkt = NULL;
+}
+
+/**
+ * usb_xprt_sft_close_done() - Completion of XPRT reset
+ * @xprt: XPRT on which the reset operation is complete.
+ *
+ * This function is used by IPC Router to signal this USB XPRT Abstraction
+ * Layer(XAL) that the reset of XPRT is completely handled by IPC Router.
+ */
+static void usb_xprt_sft_close_done(struct msm_ipc_router_xprt *xprt)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp =
+		container_of(xprt, struct msm_ipc_router_usb_xprt, xprt);
+
+	complete_all(&usb_xprtp->sft_close_complete);
+}
+
+/**
+ * msm_ipc_router_usb_remote_remove() - Remove an USB endpoint
+ * @pdev: Platform device corresponding to USB endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver unregisters
+ * a platform device, mapped to an USB endpoint, during SSR.
+ */
+static int msm_ipc_router_usb_remote_remove(struct platform_device *pdev)
+{
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	usb_xprtp = find_usb_xprt_list(pdev->name);
+	if (!usb_xprtp) {
+		IPC_RTR_ERR("%s No device with name %s\n",
+					__func__, pdev->name);
+		return -ENODEV;
+	}
+
+	mutex_lock(&usb_xprtp->ss_reset_lock);
+	usb_xprtp->ss_reset = 1;
+	mutex_unlock(&usb_xprtp->ss_reset_lock);
+	flush_workqueue(usb_xprtp->usb_xprt_wq);
+	destroy_workqueue(usb_xprtp->usb_xprt_wq);
+	init_completion(&usb_xprtp->sft_close_complete);
+	msm_ipc_router_xprt_notify(&usb_xprtp->xprt,
+				   IPC_ROUTER_XPRT_EVENT_CLOSE, NULL);
+	D("%s: Notified IPC Router of %s CLOSE\n",
+	  __func__, usb_xprtp->xprt.name);
+	wait_for_completion(&usb_xprtp->sft_close_complete);
+	usb_xprtp->pdev = NULL;
+	pdata = pdev->dev.platform_data;
+	if (pdata && pdata->close)
+		pdata->close(pdev);
+	return 0;
+}
+
+/**
+ * msm_ipc_router_usb_remote_probe() - Probe an USB endpoint
+ * @pdev: Platform device corresponding to USB endpoint.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying ipc_bridge driver registers
+ * a platform device, mapped to an USB endpoint.
+ */
+static int msm_ipc_router_usb_remote_probe(struct platform_device *pdev)
+{
+	int rc;
+	struct ipc_bridge_platform_data *pdata;
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	pdata = pdev->dev.platform_data;
+	if (!pdata || !pdata->open || !pdata->read ||
+	    !pdata->write || !pdata->close) {
+		IPC_RTR_ERR("%s: pdata or pdata->operations is NULL\n",
+								__func__);
+		return -EINVAL;
+	}
+
+	usb_xprtp = find_usb_xprt_list(pdev->name);
+	if (!usb_xprtp) {
+		IPC_RTR_ERR("%s No device with name %s\n",
+						__func__, pdev->name);
+		return -ENODEV;
+	}
+
+	usb_xprtp->usb_xprt_wq =
+		create_singlethread_workqueue(pdev->name);
+	if (!usb_xprtp->usb_xprt_wq) {
+		IPC_RTR_ERR("%s: WQ creation failed for %s\n",
+			__func__, pdev->name);
+		return -EFAULT;
+	}
+
+	rc = pdata->open(pdev);
+	if (rc < 0) {
+		IPC_RTR_ERR("%s: Channel open failed for %s.%d\n",
+			__func__, pdev->name, pdev->id);
+		destroy_workqueue(usb_xprtp->usb_xprt_wq);
+		return rc;
+	}
+	usb_xprtp->pdev = pdev;
+	mutex_lock(&usb_xprtp->ss_reset_lock);
+	usb_xprtp->ss_reset = 0;
+	mutex_unlock(&usb_xprtp->ss_reset_lock);
+	msm_ipc_router_xprt_notify(&usb_xprtp->xprt,
+				   IPC_ROUTER_XPRT_EVENT_OPEN, NULL);
+	D("%s: Notified IPC Router of %s OPEN\n",
+	  __func__, usb_xprtp->xprt.name);
+	queue_delayed_work(usb_xprtp->usb_xprt_wq,
+			   &usb_xprtp->read_work, 0);
+	return 0;
+}
+
+/**
+ * msm_ipc_router_usb_driver_register() - register USB XPRT drivers
+ *
+ * @usb_xprtp: pointer to IPC router usb xprt structure.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when a new XPRT is added to register platform
+ * drivers for new XPRT.
+ */
+static int msm_ipc_router_usb_driver_register(
+			struct msm_ipc_router_usb_xprt *usb_xprtp)
+{
+	int ret;
+	struct msm_ipc_router_usb_xprt *usb_xprtp_item;
+
+	usb_xprtp_item = find_usb_xprt_list(usb_xprtp->ch_name);
+
+	mutex_lock(&usb_remote_xprt_list_lock_lha1);
+	list_add(&usb_xprtp->list, &usb_remote_xprt_list);
+	mutex_unlock(&usb_remote_xprt_list_lock_lha1);
+
+	if (!usb_xprtp_item) {
+		usb_xprtp->driver.driver.name = usb_xprtp->ch_name;
+		usb_xprtp->driver.driver.owner = THIS_MODULE;
+		usb_xprtp->driver.probe = msm_ipc_router_usb_remote_probe;
+		usb_xprtp->driver.remove = msm_ipc_router_usb_remote_remove;
+
+		ret = platform_driver_register(&usb_xprtp->driver);
+		if (ret) {
+			IPC_RTR_ERR(
+			"%s: Failed to register platform driver[%s]\n",
+					__func__, usb_xprtp->ch_name);
+			return ret;
+		}
+	} else {
+		IPC_RTR_ERR("%s Already driver registered %s\n",
+					__func__, usb_xprtp->ch_name);
+	}
+
+	return 0;
+}
+
+/**
+ * msm_ipc_router_usb_config_init() - init USB xprt configs
+ *
+ * @usb_xprt_config: pointer to USB xprt configurations.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called to initialize the USB XPRT pointer with
+ * the USB XPRT configurations either from device tree or static arrays.
+ */
+static int msm_ipc_router_usb_config_init(
+		struct msm_ipc_router_usb_xprt_config *usb_xprt_config)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+
+	usb_xprtp = kzalloc(sizeof(struct msm_ipc_router_usb_xprt),
+							GFP_KERNEL);
+	if (IS_ERR_OR_NULL(usb_xprtp)) {
+		IPC_RTR_ERR("%s: kzalloc() failed for usb_xprtp id:%s\n",
+				__func__, usb_xprt_config->ch_name);
+		return -ENOMEM;
+	}
+
+	usb_xprtp->xprt.link_id = usb_xprt_config->link_id;
+	usb_xprtp->xprt_version = usb_xprt_config->xprt_version;
+
+	strlcpy(usb_xprtp->ch_name, usb_xprt_config->ch_name,
+					XPRT_NAME_LEN);
+
+	strlcpy(usb_xprtp->xprt_name, usb_xprt_config->xprt_name,
+						XPRT_NAME_LEN);
+	usb_xprtp->xprt.name = usb_xprtp->xprt_name;
+
+	usb_xprtp->xprt.set_version =
+		ipc_router_usb_set_xprt_version;
+	usb_xprtp->xprt.get_version =
+		msm_ipc_router_usb_get_xprt_version;
+	usb_xprtp->xprt.get_option =
+		 msm_ipc_router_usb_get_xprt_option;
+	usb_xprtp->xprt.read_avail = NULL;
+	usb_xprtp->xprt.read = NULL;
+	usb_xprtp->xprt.write_avail =
+		msm_ipc_router_usb_remote_write_avail;
+	usb_xprtp->xprt.write = msm_ipc_router_usb_remote_write;
+	usb_xprtp->xprt.close = msm_ipc_router_usb_remote_close;
+	usb_xprtp->xprt.sft_close_done = usb_xprt_sft_close_done;
+	usb_xprtp->xprt.priv = NULL;
+
+	usb_xprtp->in_pkt = NULL;
+	INIT_DELAYED_WORK(&usb_xprtp->read_work, usb_xprt_read_data);
+	mutex_init(&usb_xprtp->ss_reset_lock);
+	usb_xprtp->ss_reset = 0;
+	usb_xprtp->xprt_option = 0;
+
+	msm_ipc_router_usb_driver_register(usb_xprtp);
+	return 0;
+
+}
+
+/**
+ * parse_devicetree() - parse device tree binding
+ *
+ * @node: pointer to device tree node
+ * @usb_xprt_config: pointer to USB XPRT configurations
+ *
+ * @return: 0 on success, -ENODEV on failure.
+ */
+static int parse_devicetree(struct device_node *node,
+		struct msm_ipc_router_usb_xprt_config *usb_xprt_config)
+{
+	int ret;
+	int link_id;
+	int version;
+	char *key;
+	const char *ch_name;
+	const char *remote_ss;
+
+	key = "qcom,ch-name";
+	ch_name = of_get_property(node, key, NULL);
+	if (!ch_name)
+		goto error;
+	strlcpy(usb_xprt_config->ch_name, ch_name, XPRT_NAME_LEN);
+
+	key = "qcom,xprt-remote";
+	remote_ss = of_get_property(node, key, NULL);
+	if (!remote_ss)
+		goto error;
+
+	key = "qcom,xprt-linkid";
+	ret = of_property_read_u32(node, key, &link_id);
+	if (ret)
+		goto error;
+	usb_xprt_config->link_id = link_id;
+
+	key = "qcom,xprt-version";
+	ret = of_property_read_u32(node, key, &version);
+	if (ret)
+		goto error;
+	usb_xprt_config->xprt_version = version;
+
+	scnprintf(usb_xprt_config->xprt_name, XPRT_NAME_LEN, "%s_%s",
+			remote_ss, usb_xprt_config->ch_name);
+
+	return 0;
+
+error:
+	IPC_RTR_ERR("%s: missing key: %s\n", __func__, key);
+	return -ENODEV;
+}
+
+/**
+ * msm_ipc_router_usb_xprt_probe() - Probe an USB xprt
+ * @pdev: Platform device corresponding to USB xprt.
+ *
+ * @return: 0 on success, standard Linux error codes on error.
+ *
+ * This function is called when the underlying device tree driver registers
+ * a platform device, mapped to an USB transport.
+ */
+static int msm_ipc_router_usb_xprt_probe(
+				struct platform_device *pdev)
+{
+	int ret;
+	struct msm_ipc_router_usb_xprt_config usb_xprt_config;
+
+	if (pdev && pdev->dev.of_node) {
+		mutex_lock(&usb_remote_xprt_list_lock_lha1);
+		ipc_router_usb_xprt_probe_done = 1;
+		mutex_unlock(&usb_remote_xprt_list_lock_lha1);
+
+		ret = parse_devicetree(pdev->dev.of_node,
+						&usb_xprt_config);
+		if (ret) {
+			IPC_RTR_ERR("%s: Failed to parse device tree\n",
+								__func__);
+			return ret;
+		}
+
+		ret = msm_ipc_router_usb_config_init(
+						&usb_xprt_config);
+		if (ret) {
+			IPC_RTR_ERR(" %s init failed\n", __func__);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * ipc_router_usb_xprt_probe_worker() - probe worker for non DT configurations
+ *
+ * @work: work item to process
+ *
+ * This function is called by schedule_delay_work after 3sec and check if
+ * device tree probe is done or not. If device tree probe fails the default
+ * configurations read from static array.
+ */
+static void ipc_router_usb_xprt_probe_worker(struct work_struct *work)
+{
+	int i, ret;
+
+	if (WARN_ON(ARRAY_SIZE(usb_xprt_cfg) != NUM_USB_XPRTS))
+		return;
+
+	mutex_lock(&usb_remote_xprt_list_lock_lha1);
+	if (!ipc_router_usb_xprt_probe_done) {
+		mutex_unlock(&usb_remote_xprt_list_lock_lha1);
+		for (i = 0; i < ARRAY_SIZE(usb_xprt_cfg); i++) {
+			ret = msm_ipc_router_usb_config_init(
+							&usb_xprt_cfg[i]);
+			if (ret)
+				IPC_RTR_ERR(" %s init failed config idx %d\n",
+								__func__, i);
+		}
+		mutex_lock(&usb_remote_xprt_list_lock_lha1);
+	}
+	mutex_unlock(&usb_remote_xprt_list_lock_lha1);
+}
+
+static const struct of_device_id msm_ipc_router_usb_xprt_match_table[] = {
+	{ .compatible = "qcom,ipc-router-usb-xprt" },
+	{},
+};
+
+static struct platform_driver msm_ipc_router_usb_xprt_driver = {
+	.probe = msm_ipc_router_usb_xprt_probe,
+	.driver = {
+		.name = MODULE_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = msm_ipc_router_usb_xprt_match_table,
+	 },
+};
+
+static int __init msm_ipc_router_usb_xprt_init(void)
+{
+	int rc;
+
+	rc = platform_driver_register(&msm_ipc_router_usb_xprt_driver);
+	if (rc) {
+		IPC_RTR_ERR(
+		"%s: msm_ipc_router_usb_xprt_driver register failed %d\n",
+								__func__, rc);
+		return rc;
+	}
+
+	INIT_DELAYED_WORK(&ipc_router_usb_xprt_probe_work,
+					ipc_router_usb_xprt_probe_worker);
+	schedule_delayed_work(&ipc_router_usb_xprt_probe_work,
+			msecs_to_jiffies(IPC_ROUTER_USB_XPRT_WAIT_TIMEOUT));
+	return 0;
+}
+
+static void __exit msm_ipc_router_usb_xprt_exit(void)
+{
+	struct msm_ipc_router_usb_xprt *usb_xprtp;
+	struct msm_ipc_router_usb_xprt *temp_usb_xprtp;
+
+	list_for_each_entry_safe(usb_xprtp, temp_usb_xprtp,
+					&usb_remote_xprt_list, list) {
+		kfree(usb_xprtp);
+	}
+
+	platform_driver_unregister(&msm_ipc_router_usb_xprt_driver);
+}
+
+module_init(msm_ipc_router_usb_xprt_init);
+module_exit(msm_ipc_router_usb_xprt_exit);
+MODULE_DESCRIPTION("IPC Router USB XPRT");
+MODULE_LICENSE("GPL v2");