Merge changes Ief2357bb,Iac66d768,Ib49a41f5 into msm-3.0

* changes:
  defconfig: 9615: Enable USB BAM driver
  msm: board-9615: Add USB BAM driver
  usb: gadget: SPS BAM-to-BAM - USB BAM driver
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 003f9c1..b5aa1b4 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -188,6 +188,7 @@
 CONFIG_MSM_SSBI=y
 CONFIG_SPS=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_USB_BAM=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 5efafae..be0e4e6 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -727,6 +727,39 @@
 	0x13, 0x83,/* set source impedance adjustment */
 	-1};
 
+#define USB_BAM_PHY_BASE	0x12502000
+#define USB_BAM_PHY_SIZE	0x10000
+#define A2_BAM_PHY_BASE		0x124C2000
+static struct usb_bam_pipe_connect msm_usb_bam_connections[4][2] = {
+	[0][USB_TO_PEER_PERIPHERAL] = {
+		.src_phy_addr = USB_BAM_PHY_BASE,
+		.src_pipe_index = 11,
+		.dst_phy_addr = A2_BAM_PHY_BASE,
+		.dst_pipe_index = 0,
+		.data_fifo_base_offset = 0xf00,
+		.data_fifo_size = 0x400,
+		.desc_fifo_base_offset = 0x1300,
+		.desc_fifo_size = 0x300,
+	},
+	[0][PEER_PERIPHERAL_TO_USB] = {
+		.src_phy_addr = A2_BAM_PHY_BASE,
+		.src_pipe_index = 1,
+		.dst_phy_addr = USB_BAM_PHY_BASE,
+		.dst_pipe_index = 10,
+		.data_fifo_base_offset = 0xa00,
+		.data_fifo_size = 0x400,
+		.desc_fifo_base_offset = 0xe00,
+		.desc_fifo_size = 0x100,
+	},
+};
+
+static struct msm_usb_bam_platform_data msm_usb_bam_pdata = {
+	.connections = &msm_usb_bam_connections[0][0],
+	.usb_bam_phy_base = USB_BAM_PHY_BASE,
+	.usb_bam_phy_size = USB_BAM_PHY_SIZE,
+	.usb_bam_num_pipes = 32,
+};
+
 static struct msm_otg_platform_data msm_otg_pdata = {
 	.mode			= USB_OTG,
 	.otg_control	= OTG_PHY_CONTROL,
@@ -781,6 +814,7 @@
 	&msm_device_otg,
 	&msm_device_gadget_peripheral,
 	&msm_device_hsusb_host,
+	&msm_device_usb_bam,
 	&android_usb_device,
 	&msm9615_device_uart_gsbi4,
 	&msm9615_device_ext_2p95v_vreg,
@@ -833,6 +867,7 @@
 
 	msm_device_otg.dev.platform_data = &msm_otg_pdata;
 	msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
+	msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
 	platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
 
 	acpuclk_init(&acpuclk_9615_soc_data);
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 012eb85..63a86cb 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -99,6 +99,9 @@
 	},
 };
 
+#define MSM_USB_BAM_BASE     0x12502000
+#define MSM_USB_BAM_SIZE     0x3DFFF
+
 static struct resource resources_otg[] = {
 	{
 		.start	= MSM9615_HSUSB_PHYS,
@@ -135,6 +138,28 @@
 	},
 };
 
+static struct resource resources_usb_bam[] = {
+	{
+		.name	= "usb_bam_addr",
+		.start	= MSM_USB_BAM_BASE,
+		.end	= MSM_USB_BAM_BASE + MSM_USB_BAM_SIZE,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "usb_bam_irq",
+		.start	= USB1_HS_BAM_IRQ,
+		.end	= USB1_HS_BAM_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_usb_bam = {
+	.name		= "usb_bam",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_usb_bam),
+	.resource	= resources_usb_bam,
+};
+
 struct platform_device msm_device_gadget_peripheral = {
 	.name		= "msm_hsusb",
 	.id		= -1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 2fac2ef..ffe22f8 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -118,6 +118,7 @@
 
 extern struct platform_device msm_slim_ctrl;
 extern struct platform_device msm_device_sps;
+extern struct platform_device msm_device_usb_bam;
 extern struct platform_device msm_device_sps_apq8064;
 extern struct platform_device msm_device_bam_dmux;
 extern struct platform_device msm_device_smd;
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
new file mode 100644
index 0000000..4caa71b
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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.
+ */
+
+#ifndef _USB_BAM_H_
+#define _USB_BAM_H_
+
+/**
+ * Connect USB-to-Periperal SPS connection.
+ *
+ * This function returns the allocated pipes number.
+ *
+ * @idx - Connection index.
+ *
+ * @src_pipe_idx - allocated pipe index - USB as a
+ *  source (output)
+ *
+ * @dst_pipe_idx - allocated pipe index - USB as a
+ * destination (output)
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+#ifdef CONFIG_USB_BAM
+int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+#else
+int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+{
+	return -ENODEV;
+}
+#endif
+#endif				/* _USB_BAM_H_ */
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 26441cd..23efb00 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -23,6 +23,14 @@
 		2. Peripheral-to-Memory.
 		3. Memory-to-Memory.
 
+config USB_BAM
+	boolean "USB BAM Driver"
+	depends on SPS && USB_GADGET
+	help
+	  Enabling this option adds USB BAM Driver.
+	  USB BAM driver was added to supports SPS Peripheral-to-Peripheral
+	  transfers between the USB and other peripheral.
+
 config SPS_SUPPORT_BAMDMA
 	bool "SPS support BAM DMA"
 	depends on SPS
diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile
index f6f212e..92eb492 100644
--- a/drivers/platform/msm/Makefile
+++ b/drivers/platform/msm/Makefile
@@ -2,4 +2,5 @@
 # Makefile for the MSM specific device drivers.
 #
 obj-$(CONFIG_MSM_SSBI) += ssbi.o
+obj-$(CONFIG_USB_BAM) += usb_bam.o
 obj-$(CONFIG_SPS) += sps/
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
new file mode 100644
index 0000000..b34c35e
--- /dev/null
+++ b/drivers/platform/msm/usb_bam.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 2011, Code Aurora Forum. 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.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/usb/msm_hsusb.h>
+#include <mach/usb_bam.h>
+#include <mach/sps.h>
+
+#define USB_SUMMING_THRESHOLD 512
+#define CONNECTIONS_NUM		4
+
+static struct sps_bam_props usb_props;
+static struct sps_pipe *sps_pipes[CONNECTIONS_NUM][2];
+static struct sps_connect sps_connections[CONNECTIONS_NUM][2];
+static struct sps_mem_buffer data_mem_buf[CONNECTIONS_NUM][2];
+static struct sps_mem_buffer desc_mem_buf[CONNECTIONS_NUM][2];
+static struct platform_device *usb_bam_pdev;
+
+struct usb_bam_connect_info {
+	u8 idx;
+	u8 *src_pipe;
+	u8 *dst_pipe;
+	bool enabled;
+};
+
+static struct usb_bam_connect_info usb_bam_connections[CONNECTIONS_NUM];
+
+static int connect_pipe(u8 connection_idx, enum usb_bam_pipe_dir pipe_dir,
+						u8 *usb_pipe_idx)
+{
+	int ret;
+	struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
+	struct sps_connect *connection =
+		&sps_connections[connection_idx][pipe_dir];
+	struct msm_usb_bam_platform_data *pdata =
+		(struct msm_usb_bam_platform_data *)
+			(usb_bam_pdev->dev.platform_data);
+	struct usb_bam_pipe_connect *pipe_connection =
+			(struct usb_bam_pipe_connect *)(pdata->connections +
+						(2*connection_idx+pipe_dir));
+
+	pipe = sps_alloc_endpoint();
+	if (pipe == NULL) {
+		pr_err("%s: sps_alloc_endpoint failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	ret = sps_get_config(pipe, connection);
+	if (ret) {
+		pr_err("%s: tx get config failed %d\n", __func__, ret);
+		goto get_config_failed;
+	}
+
+	ret = sps_phy2h(pipe_connection->src_phy_addr, &(connection->source));
+	if (ret) {
+		pr_err("%s: sps_phy2h failed (src BAM) %d\n", __func__, ret);
+		goto get_config_failed;
+	}
+
+	connection->src_pipe_index = pipe_connection->src_pipe_index;
+	ret = sps_phy2h(pipe_connection->dst_phy_addr,
+					&(connection->destination));
+	if (ret) {
+		pr_err("%s: sps_phy2h failed (dst BAM) %d\n", __func__, ret);
+		goto get_config_failed;
+	}
+	connection->dest_pipe_index = pipe_connection->dst_pipe_index;
+
+	if (pipe_dir == USB_TO_PEER_PERIPHERAL) {
+		connection->mode = SPS_MODE_SRC;
+		*usb_pipe_idx = connection->src_pipe_index;
+	} else {
+		connection->mode = SPS_MODE_DEST;
+		*usb_pipe_idx = connection->dest_pipe_index;
+	}
+
+	ret = sps_setup_bam2bam_fifo(
+				&data_mem_buf[connection_idx][pipe_dir],
+				pipe_connection->data_fifo_base_offset,
+				pipe_connection->data_fifo_size, 1);
+	if (ret) {
+		pr_err("%s: data fifo setup failure %d\n", __func__, ret);
+		goto fifo_setup_error;
+	}
+	connection->data = data_mem_buf[connection_idx][pipe_dir];
+
+	ret = sps_setup_bam2bam_fifo(
+				&desc_mem_buf[connection_idx][pipe_dir],
+				pipe_connection->desc_fifo_base_offset,
+				pipe_connection->desc_fifo_size, 1);
+	if (ret) {
+		pr_err("%s: desc. fifo setup failure %d\n", __func__, ret);
+		goto fifo_setup_error;
+	}
+	connection->desc = desc_mem_buf[connection_idx][pipe_dir];
+	connection->event_thresh = 512;
+
+	ret = sps_connect(pipe, connection);
+	if (ret < 0) {
+		pr_err("%s: tx connect error %d\n", __func__, ret);
+		goto error;
+	}
+	return 0;
+
+error:
+	sps_disconnect(pipe);
+fifo_setup_error:
+get_config_failed:
+	sps_free_endpoint(pipe);
+	return ret;
+}
+
+int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+{
+	struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+	int ret;
+
+	if (idx >= CONNECTIONS_NUM) {
+		pr_err("%s: Invalid connection index\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (connection->enabled) {
+		pr_info("%s: connection %d was already established\n",
+			__func__, idx);
+		return 0;
+	}
+	connection->src_pipe = src_pipe_idx;
+	connection->dst_pipe = dst_pipe_idx;
+	connection->idx = idx;
+
+	/* open USB -> Peripheral pipe */
+	ret = connect_pipe(connection->idx, USB_TO_PEER_PERIPHERAL,
+					   connection->src_pipe);
+	if (ret) {
+		pr_err("%s: src pipe connection failure\n", __func__);
+		return ret;
+	}
+	/* open Peripheral -> USB pipe */
+	ret = connect_pipe(connection->idx, PEER_PERIPHERAL_TO_USB,
+				 connection->dst_pipe);
+	if (ret) {
+		pr_err("%s: dst pipe connection failure\n", __func__);
+		return ret;
+	}
+	connection->enabled = 1;
+
+	return 0;
+}
+static int usb_bam_init(void)
+{
+	u32 h_usb;
+	int ret;
+	void *usb_virt_addr;
+	struct msm_usb_bam_platform_data *pdata =
+		(struct msm_usb_bam_platform_data *)
+			(usb_bam_pdev->dev.platform_data);
+
+	usb_virt_addr = ioremap_nocache(
+						pdata->usb_bam_phy_base,
+						pdata->usb_bam_phy_size);
+	if (!usb_virt_addr) {
+		pr_err("%s: ioremap failed\n", __func__);
+		return -ENOMEM;
+	}
+	usb_props.phys_addr = pdata->usb_bam_phy_base;
+	usb_props.virt_addr = usb_virt_addr;
+	usb_props.virt_size = pdata->usb_bam_phy_size;
+	usb_props.irq = USB1_HS_BAM_IRQ;
+	usb_props.num_pipes = pdata->usb_bam_num_pipes;
+	usb_props.summing_threshold = USB_SUMMING_THRESHOLD;
+	ret = sps_register_bam_device(&usb_props, &h_usb);
+	if (ret < 0) {
+		pr_err("%s: register bam error %d\n", __func__, ret);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int usb_bam_probe(struct platform_device *pdev)
+{
+	int ret, i;
+
+	dev_dbg(&pdev->dev, "usb_bam_probe\n");
+
+	for (i = 0; i < CONNECTIONS_NUM; i++)
+		usb_bam_connections[i].enabled = 0;
+
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "missing platform_data\n");
+		return -ENODEV;
+	}
+	usb_bam_pdev = pdev;
+
+	ret = usb_bam_init();
+	if (ret) {
+		dev_err(&pdev->dev, "failed to get platform resource mem\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver usb_bam_driver = {
+	.probe = usb_bam_probe,
+	.driver = { .name = "usb_bam", },
+};
+
+static int __init init(void)
+{
+	return platform_driver_register(&usb_bam_driver);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+	platform_driver_unregister(&usb_bam_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION("MSM USB BAM DRIVER");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 68fc67c..eb2c543 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -132,6 +132,19 @@
 };
 
 /**
+ * SPS Pipes direction.
+ *
+ * USB_TO_PEER_PERIPHERAL	USB (as Producer) to other
+ *                          peer peripheral.
+ * PEER_PERIPHERAL_TO_USB	Other Peripheral to
+ *                          USB (as consumer).
+ */
+enum usb_bam_pipe_dir {
+	USB_TO_PEER_PERIPHERAL,
+	PEER_PERIPHERAL_TO_USB,
+};
+
+/**
  * struct msm_otg_platform_data - platform device data
  *              for msm_otg driver.
  * @phy_init_seq: PHY configuration sequence. val, reg pairs
@@ -258,4 +271,21 @@
 	unsigned hub_reset;
 };
 
+struct usb_bam_pipe_connect {
+	u32 src_phy_addr;
+	int src_pipe_index;
+	u32 dst_phy_addr;
+	int dst_pipe_index;
+	u32 data_fifo_base_offset;
+	u32 data_fifo_size;
+	u32 desc_fifo_base_offset;
+	u32 desc_fifo_size;
+};
+
+struct msm_usb_bam_platform_data {
+	struct usb_bam_pipe_connect *connections;
+	unsigned long usb_bam_phy_base;
+	unsigned long usb_bam_phy_size;
+	int usb_bam_num_pipes;
+};
 #endif