Merge "Bluetooth: If link is encrypted, do not send encrpt link request" into msm-3.0
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 9c6ebdf..23b4668 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -319,12 +319,18 @@
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_USB_VIDEO_CLASS=y
-CONFIG_IMX074=y
+CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
+CONFIG_IMX074=y
+CONFIG_IMX074_ACT=y
+CONFIG_OV7692=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_GEMINI=y
 CONFIG_RADIO_TAVARUA=y
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index aae900a..fddd385 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -320,12 +320,18 @@
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_REGULATOR_GPIO=y
 CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_DEV=y
 # CONFIG_MEDIA_TUNER_CUSTOMISE is not set
 CONFIG_USB_VIDEO_CLASS=y
-CONFIG_IMX074=y
+CONFIG_MSM_CAMERA_V4L2=y
 CONFIG_WEBCAM_OV9726=y
 CONFIG_MT9E013=y
+CONFIG_IMX074=y
+CONFIG_IMX074_ACT=y
+CONFIG_OV7692=y
+CONFIG_MSM_CAMERA_SENSOR=y
+CONFIG_MSM_ACTUATOR=y
 CONFIG_MSM_GEMINI=y
 CONFIG_RADIO_TAVARUA=y
 CONFIG_ION=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index dc2db27..b5a17cd 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -90,6 +90,7 @@
 CONFIG_MSM_CACHE_ERP=y
 CONFIG_MSM_L2_ERP_2BIT_PANIC=y
 CONFIG_MSM_DCVS=y
+CONFIG_MSM_HSIC_SYSMON=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index ba616b0..e18f0ea 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -97,6 +97,7 @@
 CONFIG_MSM_DCVS=y
 CONFIG_MSM_CACHE_DUMP=y
 CONFIG_MSM_CACHE_DUMP_ON_PANIC=y
+CONFIG_MSM_HSIC_SYSMON=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index 3dfb62f..7a5b21a 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -141,7 +141,7 @@
 	unsigned int msmsdcc_fmax;
 	bool nonremovable;
 	bool pclk_src_dfab;
-	int (*cfg_mpm_sdiowakeup)(struct device *, unsigned);
+	unsigned int mpm_sdiowakeup_int;
 	unsigned int wpswitch_gpio;
 	unsigned char wpswitch_polarity;
 	struct msm_mmc_slot_reg_data *vreg_data;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 33c84a6..4ea24a4 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2275,4 +2275,21 @@
 	  want to dump the L1 and L2 caches on panic before any flush occurs.
 	  If unsure, say N
 
+config MSM_HSIC_SYSMON
+	tristate "MSM HSIC system monitor driver"
+	depends on USB
+	help
+	  Add support for bridging with the system monitor interface of MDM
+	  over HSIC. This driver allows the local system monitor to
+	  communicate with the remote system monitor interface.
+
+config MSM_HSIC_SYSMON_TEST
+	tristate "MSM HSIC system monitor bridge test"
+	depends on USB && MSM_HSIC_SYSMON && DEBUG_FS
+	help
+	  Enable the test hook for the Qualcomm system monitor HSIC driver.
+	  This will create a debugfs file entry named "hsic_sysmon_test" which
+	  can be read and written to send character data to the sysmon port of
+	  the modem over USB.
+
 endif
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 14bae2d..3ef61f4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -345,3 +345,6 @@
 obj-$(CONFIG_MSM_RTB) += msm_rtb.o
 obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
 obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o
+
+obj-$(CONFIG_MSM_HSIC_SYSMON) += hsic_sysmon.o
+obj-$(CONFIG_MSM_HSIC_SYSMON_TEST) += hsic_sysmon_test.o
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 2d1c31c..0d1c72d 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -412,9 +412,11 @@
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 	{
-		.ioclk.mclk_clk_rate = 24000000,
-		.ioclk.vfe_clk_rate  = 228570000,
 		.csid_core = 2,
+		.is_csiphy = 1,
+		.is_csid   = 1,
+		.is_ispif  = 1,
+		.is_vpe    = 1,
 		.cam_bus_scale_table = &cam_bus_client_pdata,
 	},
 };
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index 95561e4..c12dce6 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -12,7 +12,6 @@
  */
 
 #include <asm/mach-types.h>
-#include <devices-msm8x60.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/mfd/pmic8901.h>
@@ -20,6 +19,7 @@
 #include <mach/board-msm8660.h>
 #include <mach/gpiomux.h>
 #include <mach/msm_bus_board.h>
+#include "devices-msm8x60.h"
 #include "devices.h"
 
 #define GPIO_EXT_CAMIF_PWR_EN1 (PM8901_MPP_BASE + PM8901_MPPS + 13)
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 824cad8..7832b878 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -2630,7 +2630,7 @@
 #endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
 
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x3BC000
-#define MSM_PMEM_ADSP_SIZE         0x2000000
+#define MSM_PMEM_ADSP_SIZE         0x4200000
 #define MSM_PMEM_AUDIO_SIZE        0x4CF000
 
 #define MSM_SMI_BASE          0x38000000
@@ -8311,45 +8311,10 @@
 }
 #endif
 #endif
+#endif
 
-#ifdef	CONFIG_MMC_MSM_SDC4_SUPPORT
+#define MSM_MPM_PIN_SDC3_DAT1	21
 #define MSM_MPM_PIN_SDC4_DAT1	23
-static int msm_sdcc_cfg_mpm_sdiowakeup(struct device *dev, unsigned mode)
-{
-	struct platform_device *pdev;
-	unsigned int pin;
-	int ret = 0;
-
-	pdev = container_of(dev, struct platform_device, dev);
-
-	/* Only SDCC4 slot connected to WLAN chip has wakeup capability */
-	if (pdev->id == 4)
-		pin = MSM_MPM_PIN_SDC4_DAT1;
-	else
-		return -EINVAL;
-
-	switch (mode) {
-	case SDC_DAT1_DISABLE:
-		ret = msm_mpm_enable_pin(pin, 0);
-		break;
-	case SDC_DAT1_ENABLE:
-		ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
-		ret = msm_mpm_enable_pin(pin, 1);
-		break;
-	case SDC_DAT1_ENWAKE:
-		ret = msm_mpm_set_pin_wake(pin, 1);
-		break;
-	case SDC_DAT1_DISWAKE:
-		ret = msm_mpm_set_pin_wake(pin, 0);
-		break;
-	default:
-		ret = -EINVAL;
-		break;
-	}
-	return ret;
-}
-#endif
-#endif
 
 #ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
 static struct mmc_platform_data msm8x60_sdc1_data = {
@@ -8416,7 +8381,7 @@
 	.msmsdcc_fmax	= 48000000,
 	.nonremovable	= 0,
 	.pclk_src_dfab  = 1,
-	.cfg_mpm_sdiowakeup = msm_sdcc_cfg_mpm_sdiowakeup,
+	.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC4_DAT1,
 };
 #endif
 
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 17719d6..ef14b93 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2848,7 +2848,7 @@
 			.bus_freq = 0,
 		},
 	},
-	.init_level = 0,
+	.init_level = 1,
 	.num_levels = ARRAY_SIZE(grp3d_freq) + 1,
 	.set_grp_async = NULL,
 	.idle_timeout = HZ/12,
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
new file mode 100644
index 0000000..2dedbac
--- /dev/null
+++ b/arch/arm/mach-msm/hsic_sysmon.c
@@ -0,0 +1,449 @@
+/* Copyright (c) 2012, 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.
+ */
+
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+
+#include "hsic_sysmon.h"
+#include "sysmon.h"
+
+#define DRIVER_DESC	"HSIC System monitor driver"
+
+enum hsic_sysmon_op {
+	HSIC_SYSMON_OP_READ = 0,
+	HSIC_SYSMON_OP_WRITE,
+	NUM_OPS
+};
+
+struct hsic_sysmon {
+	struct usb_device	*udev;
+	struct usb_interface	*ifc;
+	__u8			in_epaddr;
+	__u8			out_epaddr;
+	unsigned int		pipe[NUM_OPS];
+	struct kref		kref;
+	struct platform_device	pdev;
+	int			id;
+
+	/* debugging counters */
+	atomic_t		dbg_bytecnt[NUM_OPS];
+	atomic_t		dbg_pending[NUM_OPS];
+};
+static struct hsic_sysmon *hsic_sysmon_devices[NUM_HSIC_SYSMON_DEVS];
+
+static void hsic_sysmon_delete(struct kref *kref)
+{
+	struct hsic_sysmon *hs = container_of(kref, struct hsic_sysmon, kref);
+
+	usb_put_dev(hs->udev);
+	hsic_sysmon_devices[hs->id] = NULL;
+	kfree(hs);
+}
+
+/**
+ * hsic_sysmon_open() - Opens the system monitor bridge.
+ * @id: the HSIC system monitor device to open
+ *
+ * This should only be called after the platform_device "sys_mon" with id
+ * SYSMON_SS_EXT_MODEM has been added. The simplest way to do that is to
+ * register a platform_driver and its probe will be called when the HSIC
+ * device is ready.
+ */
+int hsic_sysmon_open(enum hsic_sysmon_device_id id)
+{
+	struct hsic_sysmon	*hs;
+
+	if (id >= NUM_HSIC_SYSMON_DEVS) {
+		pr_err("invalid dev id(%d)", id);
+		return -ENODEV;
+	}
+
+	hs = hsic_sysmon_devices[id];
+	if (!hs) {
+		pr_err("dev is null");
+		return -ENODEV;
+	}
+
+	kref_get(&hs->kref);
+
+	return 0;
+}
+EXPORT_SYMBOL(hsic_sysmon_open);
+
+/**
+ * hsic_sysmon_close() - Closes the system monitor bridge.
+ * @id: the HSIC system monitor device to close
+ */
+void hsic_sysmon_close(enum hsic_sysmon_device_id id)
+{
+	struct hsic_sysmon	*hs;
+
+	if (id >= NUM_HSIC_SYSMON_DEVS) {
+		pr_err("invalid dev id(%d)", id);
+		return;
+	}
+
+	hs = hsic_sysmon_devices[id];
+	kref_put(&hs->kref, hsic_sysmon_delete);
+}
+EXPORT_SYMBOL(hsic_sysmon_close);
+
+/**
+ * hsic_sysmon_readwrite() - Common function to send read/write over HSIC
+ */
+static int hsic_sysmon_readwrite(enum hsic_sysmon_device_id id, void *data,
+				 size_t len, size_t *actual_len, int timeout,
+				 enum hsic_sysmon_op op)
+{
+	struct hsic_sysmon	*hs;
+	int			ret;
+	const char		*opstr = (op == HSIC_SYSMON_OP_READ) ?
+						"read" : "write";
+
+	pr_debug("%s: id:%d, data len:%d, timeout:%d", opstr, id, len, timeout);
+
+	if (id >= NUM_HSIC_SYSMON_DEVS) {
+		pr_err("invalid dev id(%d)", id);
+		return -ENODEV;
+	}
+
+	if (!len) {
+		pr_err("length(%d) must be greater than 0", len);
+		return -EINVAL;
+	}
+
+	hs = hsic_sysmon_devices[id];
+	if (!hs) {
+		pr_err("device was not opened");
+		return -ENODEV;
+	}
+
+	if (!hs->ifc) {
+		dev_err(&hs->udev->dev, "can't %s, device disconnected\n",
+				opstr);
+		return -ENODEV;
+	}
+
+	ret = usb_autopm_get_interface(hs->ifc);
+	if (ret < 0) {
+		dev_err(&hs->udev->dev, "can't %s, autopm_get failed:%d\n",
+			opstr, ret);
+		return ret;
+	}
+
+	atomic_inc(&hs->dbg_pending[op]);
+
+	ret = usb_bulk_msg(hs->udev, hs->pipe[op], data, len, actual_len,
+				timeout);
+
+	atomic_dec(&hs->dbg_pending[op]);
+
+	if (ret)
+		dev_err(&hs->udev->dev,
+			"can't %s, usb_bulk_msg failed, err:%d\n", opstr, ret);
+	else
+		atomic_add(*actual_len, &hs->dbg_bytecnt[op]);
+
+	usb_autopm_put_interface(hs->ifc);
+	return ret;
+}
+
+/**
+ * hsic_sysmon_read() - Read data from the HSIC sysmon interface.
+ * @id: the HSIC system monitor device to open
+ * @data: pointer to caller-allocated buffer to fill in
+ * @len: length in bytes of the buffer
+ * @actual_len: pointer to a location to put the actual length read
+ *	in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ *	timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * Synchronously reads data from the HSIC interface. The call will return
+ * after the read has completed, encountered an error, or timed out. Upon
+ * successful return actual_len will reflect the number of bytes read.
+ *
+ * If successful, it returns 0, otherwise a negative error number.  The number
+ * of actual bytes transferred will be stored in the actual_len paramater.
+ */
+int hsic_sysmon_read(enum hsic_sysmon_device_id id, char *data, size_t len,
+		     size_t *actual_len, int timeout)
+{
+	return hsic_sysmon_readwrite(id, data, len, actual_len,
+					timeout, HSIC_SYSMON_OP_READ);
+}
+EXPORT_SYMBOL(hsic_sysmon_read);
+
+/**
+ * hsic_sysmon_write() - Write data to the HSIC sysmon interface.
+ * @id: the HSIC system monitor device to open
+ * @data: pointer to caller-allocated buffer to write
+ * @len: length in bytes of the data in buffer to write
+ * @actual_len: pointer to a location to put the actual length written
+ *	in bytes
+ * @timeout: time in msecs to wait for the message to complete before
+ *	timing out (if 0 the wait is forever)
+ *
+ * Context: !in_interrupt ()
+ *
+ * Synchronously writes data to the HSIC interface. The call will return
+ * after the write has completed, encountered an error, or timed out. Upon
+ * successful return actual_len will reflect the number of bytes written.
+ *
+ * If successful, it returns 0, otherwise a negative error number.  The number
+ * of actual bytes transferred will be stored in the actual_len paramater.
+ */
+int hsic_sysmon_write(enum hsic_sysmon_device_id id, const char *data,
+		      size_t len, int timeout)
+{
+	size_t actual_len;
+	return hsic_sysmon_readwrite(id, (void *)data, len, &actual_len,
+					timeout, HSIC_SYSMON_OP_WRITE);
+}
+EXPORT_SYMBOL(hsic_sysmon_write);
+
+#if defined(CONFIG_DEBUG_FS)
+#define DEBUG_BUF_SIZE	512
+static ssize_t sysmon_debug_read_stats(struct file *file, char __user *ubuf,
+					size_t count, loff_t *ppos)
+{
+	char	*buf;
+	int	i, ret = 0;
+
+	buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = 0; i < NUM_HSIC_SYSMON_DEVS; i++) {
+		struct hsic_sysmon *hs = hsic_sysmon_devices[i];
+		if (!hs)
+			continue;
+
+		ret += scnprintf(buf, DEBUG_BUF_SIZE,
+				"---HSIC Sysmon #%d---\n"
+				"epin:%d, epout:%d\n"
+				"bytes to host: %d\n"
+				"bytes to mdm: %d\n"
+				"pending reads: %d\n"
+				"pending writes: %d\n",
+				i, hs->in_epaddr & ~0x80, hs->out_epaddr,
+				atomic_read(
+				    &hs->dbg_bytecnt[HSIC_SYSMON_OP_READ]),
+				atomic_read(
+				    &hs->dbg_bytecnt[HSIC_SYSMON_OP_WRITE]),
+				atomic_read(
+				    &hs->dbg_pending[HSIC_SYSMON_OP_READ]),
+				atomic_read(
+				    &hs->dbg_pending[HSIC_SYSMON_OP_WRITE])
+				);
+	}
+
+	ret = simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+	kfree(buf);
+	return ret;
+}
+
+static ssize_t sysmon_debug_reset_stats(struct file *file,
+					const char __user *buf,
+					size_t count, loff_t *ppos)
+{
+	int	i;
+
+	for (i = 0; i < NUM_HSIC_SYSMON_DEVS; i++) {
+		struct hsic_sysmon *hs = hsic_sysmon_devices[i];
+		if (hs) {
+			atomic_set(&hs->dbg_bytecnt[HSIC_SYSMON_OP_READ], 0);
+			atomic_set(&hs->dbg_bytecnt[HSIC_SYSMON_OP_WRITE], 0);
+			atomic_set(&hs->dbg_pending[HSIC_SYSMON_OP_READ], 0);
+			atomic_set(&hs->dbg_pending[HSIC_SYSMON_OP_WRITE], 0);
+		}
+	}
+
+	return count;
+}
+
+const struct file_operations sysmon_stats_ops = {
+	.read = sysmon_debug_read_stats,
+	.write = sysmon_debug_reset_stats,
+};
+
+static struct dentry *dent;
+
+static void hsic_sysmon_debugfs_init(void)
+{
+	struct dentry *dfile;
+
+	dent = debugfs_create_dir("hsic_sysmon", 0);
+	if (IS_ERR(dent))
+		return;
+
+	dfile = debugfs_create_file("status", 0444, dent, 0, &sysmon_stats_ops);
+	if (!dfile || IS_ERR(dfile))
+		debugfs_remove(dent);
+}
+
+static void hsic_sysmon_debugfs_cleanup(void)
+{
+	if (dent) {
+		debugfs_remove_recursive(dent);
+		dent = NULL;
+	}
+}
+#else
+static inline void hsic_sysmon_debugfs_init(void) { }
+static inline void hsic_sysmon_debugfs_cleanup(void) { }
+#endif
+
+static int
+hsic_sysmon_probe(struct usb_interface *ifc, const struct usb_device_id *id)
+{
+	struct hsic_sysmon		*hs;
+	struct usb_host_interface	*ifc_desc;
+	struct usb_endpoint_descriptor	*ep_desc;
+	int				i;
+	int				ret = -ENOMEM;
+	__u8				ifc_num;
+
+	pr_debug("id:%lu", id->driver_info);
+
+	ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
+
+	/* is this the interface we're looking for? */
+	if (ifc_num != id->driver_info)
+		return -ENODEV;
+
+	hs = kzalloc(sizeof(*hs), GFP_KERNEL);
+	if (!hs) {
+		pr_err("unable to allocate hsic_sysmon");
+		return -ENOMEM;
+	}
+
+	hs->udev = usb_get_dev(interface_to_usbdev(ifc));
+	hs->ifc = ifc;
+	kref_init(&hs->kref);
+
+	ifc_desc = ifc->cur_altsetting;
+	for (i = 0; i < ifc_desc->desc.bNumEndpoints; i++) {
+		ep_desc = &ifc_desc->endpoint[i].desc;
+
+		if (!hs->in_epaddr && usb_endpoint_is_bulk_in(ep_desc)) {
+			hs->in_epaddr = ep_desc->bEndpointAddress;
+			hs->pipe[HSIC_SYSMON_OP_READ] =
+				usb_rcvbulkpipe(hs->udev, hs->in_epaddr);
+		}
+
+		if (!hs->out_epaddr && usb_endpoint_is_bulk_out(ep_desc)) {
+			hs->out_epaddr = ep_desc->bEndpointAddress;
+			hs->pipe[HSIC_SYSMON_OP_WRITE] =
+				usb_sndbulkpipe(hs->udev, hs->out_epaddr);
+		}
+	}
+
+	if (!(hs->in_epaddr && hs->out_epaddr)) {
+		pr_err("could not find bulk in and bulk out endpoints");
+		ret = -ENODEV;
+		goto error;
+	}
+
+	hs->id = HSIC_SYSMON_DEV_EXT_MODEM;
+	hsic_sysmon_devices[HSIC_SYSMON_DEV_EXT_MODEM] = hs;
+	usb_set_intfdata(ifc, hs);
+
+	hs->pdev.name = "sys_mon";
+	hs->pdev.id = SYSMON_SS_EXT_MODEM;
+	platform_device_register(&hs->pdev);
+
+	pr_debug("complete");
+
+	return 0;
+
+error:
+	if (hs)
+		kref_put(&hs->kref, hsic_sysmon_delete);
+
+	return ret;
+}
+
+static void hsic_sysmon_disconnect(struct usb_interface *ifc)
+{
+	struct hsic_sysmon	*hs = usb_get_intfdata(ifc);
+
+	platform_device_unregister(&hs->pdev);
+	kref_put(&hs->kref, hsic_sysmon_delete);
+	usb_set_intfdata(ifc, NULL);
+}
+
+static int hsic_sysmon_suspend(struct usb_interface *ifc, pm_message_t message)
+{
+	return 0;
+}
+
+static int hsic_sysmon_resume(struct usb_interface *ifc)
+{
+	return 0;
+}
+
+/* driver_info maps to the interface number corresponding to sysmon */
+static const struct usb_device_id hsic_sysmon_ids[] = {
+	{ USB_DEVICE(0x5c6, 0x9048), .driver_info = 1, },
+	{ USB_DEVICE(0x5c6, 0x904C), .driver_info = 1, },
+	{} /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, hsic_sysmon_ids);
+
+static struct usb_driver hsic_sysmon_driver = {
+	.name =		"hsic_sysmon",
+	.probe =	hsic_sysmon_probe,
+	.disconnect =	hsic_sysmon_disconnect,
+	.suspend =	hsic_sysmon_suspend,
+	.resume =	hsic_sysmon_resume,
+	.id_table =	hsic_sysmon_ids,
+	.supports_autosuspend = 1,
+};
+
+static int __init hsic_sysmon_init(void)
+{
+	int ret;
+
+	ret = usb_register(&hsic_sysmon_driver);
+	if (ret) {
+		pr_err("unable to register " DRIVER_DESC);
+		return ret;
+	}
+
+	hsic_sysmon_debugfs_init();
+	return 0;
+}
+
+static void __exit hsic_sysmon_exit(void)
+{
+	hsic_sysmon_debugfs_cleanup();
+	usb_deregister(&hsic_sysmon_driver);
+}
+
+module_init(hsic_sysmon_init);
+module_exit(hsic_sysmon_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/hsic_sysmon.h b/arch/arm/mach-msm/hsic_sysmon.h
new file mode 100644
index 0000000..aa57b93
--- /dev/null
+++ b/arch/arm/mach-msm/hsic_sysmon.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2012, 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 __HSIC_SYSMON_H__
+#define __HSIC_SYSMON_H__
+
+/**
+ * enum hsic_sysmon_device_id - Supported HSIC subsystem devices
+ */
+enum hsic_sysmon_device_id {
+	HSIC_SYSMON_DEV_EXT_MODEM,
+	NUM_HSIC_SYSMON_DEVS
+};
+
+#if defined(CONFIG_MSM_HSIC_SYSMON) || defined(CONFIG_MSM_HSIC_SYSMON_MODULE)
+
+extern int hsic_sysmon_open(enum hsic_sysmon_device_id id);
+extern void hsic_sysmon_close(enum hsic_sysmon_device_id id);
+extern int hsic_sysmon_read(enum hsic_sysmon_device_id id, char *data,
+			    size_t len, size_t *actual_len, int timeout);
+extern int hsic_sysmon_write(enum hsic_sysmon_device_id id, const char *data,
+			     size_t len, int timeout);
+
+#else /* CONFIG_MSM_HSIC_SYSMON || CONFIG_MSM_HSIC_SYSMON_MODULE */
+
+static inline int hsic_sysmon_open(enum hsic_sysmon_device_id id)
+{
+	return -ENODEV;
+}
+
+static inline void hsic_sysmon_close(enum hsic_sysmon_device_id id) { }
+
+static inline int hsic_sysmon_read(enum hsic_sysmon_device_id id, char *data,
+				   size_t len, size_t *actual_len, int timeout)
+{
+	return -ENODEV;
+}
+
+static inline int hsic_sysmon_write(enum hsic_sysmon_device_id id,
+				    const char *data, size_t len, int timeout)
+{
+	return -ENODEV;
+}
+
+#endif /* CONFIG_MSM_HSIC_SYSMON || CONFIG_MSM_HSIC_SYSMON_MODULE */
+
+#endif /* __HSIC_SYSMON_H__ */
diff --git a/arch/arm/mach-msm/hsic_sysmon_test.c b/arch/arm/mach-msm/hsic_sysmon_test.c
new file mode 100644
index 0000000..9929cb7
--- /dev/null
+++ b/arch/arm/mach-msm/hsic_sysmon_test.c
@@ -0,0 +1,118 @@
+/* Copyright (c) 2012, 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.
+ */
+
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include "hsic_sysmon.h"
+#include "sysmon.h"
+
+#define DRIVER_DESC	"HSIC System monitor driver test"
+
+#define RD_BUF_SIZE	4096
+
+struct sysmon_test_dev {
+	int			buflen;
+	char			buf[RD_BUF_SIZE];
+};
+static struct sysmon_test_dev *sysmon_dev;
+
+static ssize_t sysmon_test_read(struct file *file, char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct sysmon_test_dev *dev = sysmon_dev;
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	ret = hsic_sysmon_read(HSIC_SYSMON_DEV_EXT_MODEM, dev->buf, RD_BUF_SIZE,
+				&dev->buflen, 3000);
+	if (!ret)
+		return simple_read_from_buffer(ubuf, count, ppos,
+					dev->buf, dev->buflen);
+
+	return 0;
+}
+
+static ssize_t sysmon_test_write(struct file *file, const char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct sysmon_test_dev	*dev = sysmon_dev;
+	int ret;
+
+	if (!dev)
+		return -ENODEV;
+
+	if (copy_from_user(dev->buf, ubuf, count)) {
+		pr_err("error copying for writing");
+		return 0;
+	}
+
+	ret = hsic_sysmon_write(HSIC_SYSMON_DEV_EXT_MODEM,
+				dev->buf, count, 1000);
+	if (ret < 0) {
+		pr_err("error writing to hsic_sysmon");
+		return ret;
+	}
+
+	return count;
+}
+
+static int sysmon_test_open(struct inode *inode, struct file *file)
+{
+	return hsic_sysmon_open(HSIC_SYSMON_DEV_EXT_MODEM);
+}
+
+static int sysmon_test_release(struct inode *inode, struct file *file)
+{
+	hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
+	return 0;
+}
+
+static struct dentry *dfile;
+const struct file_operations sysmon_test_ops = {
+	.read = sysmon_test_read,
+	.write = sysmon_test_write,
+	.open = sysmon_test_open,
+	.release = sysmon_test_release
+};
+
+static int __init sysmon_test_init(void)
+{
+	sysmon_dev = kzalloc(sizeof(*sysmon_dev), GFP_KERNEL);
+	if (!sysmon_dev)
+		return -ENOMEM;
+
+	dfile = debugfs_create_file("hsic_sysmon_test", 0666, NULL,
+			0, &sysmon_test_ops);
+	return 0;
+}
+
+static void __exit sysmon_test_exit(void)
+{
+	if (dfile)
+		debugfs_remove(dfile);
+	kfree(sysmon_dev);
+}
+
+module_init(sysmon_test_init);
+module_exit(sysmon_test_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 3d3824a..ddb8502 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, 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
@@ -24,20 +24,34 @@
 #include <mach/msm_smd.h>
 #include <mach/subsystem_notif.h>
 
+#include "hsic_sysmon.h"
 #include "sysmon.h"
 
 #define MAX_MSG_LENGTH	50
 #define TIMEOUT_MS	5000
 
+enum transports {
+	TRANSPORT_SMD,
+	TRANSPORT_HSIC,
+};
+
 struct sysmon_subsys {
 	struct mutex		lock;
 	struct smd_channel	*chan;
 	bool			chan_open;
 	struct completion	resp_ready;
 	char			rx_buf[MAX_MSG_LENGTH];
+	enum transports		transport;
 };
 
-static struct sysmon_subsys subsys[SYSMON_NUM_SS];
+static struct sysmon_subsys subsys[SYSMON_NUM_SS] = {
+	[SYSMON_SS_MODEM].transport     = TRANSPORT_SMD,
+	[SYSMON_SS_LPASS].transport     = TRANSPORT_SMD,
+	[SYSMON_SS_WCNSS].transport     = TRANSPORT_SMD,
+	[SYSMON_SS_DSPS].transport      = TRANSPORT_SMD,
+	[SYSMON_SS_Q6FW].transport      = TRANSPORT_SMD,
+	[SYSMON_SS_EXT_MODEM].transport = TRANSPORT_HSIC,
+};
 
 static const char *notif_name[SUBSYS_NOTIF_TYPE_COUNT] = {
 	[SUBSYS_BEFORE_SHUTDOWN] = "before_shutdown",
@@ -46,6 +60,39 @@
 	[SUBSYS_AFTER_POWERUP]   = "after_powerup",
 };
 
+static int sysmon_send_smd(struct sysmon_subsys *ss, char *tx_buf, size_t len)
+{
+	int ret;
+
+	if (!ss->chan_open)
+		return -ENODEV;
+
+	init_completion(&ss->resp_ready);
+	pr_debug("Sending SMD message: %s\n", tx_buf);
+	smd_write(ss->chan, tx_buf, len);
+	ret = wait_for_completion_timeout(&ss->resp_ready,
+				  msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+
+static int sysmon_send_hsic(struct sysmon_subsys *ss, char *tx_buf, size_t len)
+{
+	int ret;
+	size_t actual_len;
+
+	pr_debug("Sending HSIC message: %s\n", tx_buf);
+	ret = hsic_sysmon_write(HSIC_SYSMON_DEV_EXT_MODEM,
+				tx_buf, len, TIMEOUT_MS);
+	if (ret)
+		return ret;
+	ret = hsic_sysmon_read(HSIC_SYSMON_DEV_EXT_MODEM, ss->rx_buf,
+			       ARRAY_SIZE(ss->rx_buf), &actual_len, TIMEOUT_MS);
+	return ret;
+}
+
 int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
 		      enum subsys_notif_type notif)
 {
@@ -58,31 +105,34 @@
 	    event_ss == NULL)
 		return -EINVAL;
 
-	if (!ss->chan_open)
-		return -ENODEV;
-
-	mutex_lock(&ss->lock);
-	init_completion(&ss->resp_ready);
 	snprintf(tx_buf, ARRAY_SIZE(tx_buf), "ssr:%s:%s", event_ss,
 		 notif_name[notif]);
-	pr_debug("Sending message: %s\n", tx_buf);
-	smd_write(ss->chan, tx_buf, ARRAY_SIZE(tx_buf));
-	ret = wait_for_completion_timeout(&ss->resp_ready,
-					  msecs_to_jiffies(TIMEOUT_MS));
-	if (!ret) {
-		ret = -ETIMEDOUT;
-	} else if (strncmp(ss->rx_buf, "ssr:ack", ARRAY_SIZE(ss->rx_buf))) {
-		pr_debug("Received response: %s\n", ss->rx_buf);
-		ret = -ENOSYS;
-	} else {
-		ret = 0;
-	}
-	mutex_unlock(&ss->lock);
 
+	mutex_lock(&ss->lock);
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		ret = sysmon_send_smd(ss, tx_buf, ARRAY_SIZE(tx_buf));
+		break;
+	case TRANSPORT_HSIC:
+		ret = sysmon_send_hsic(ss, tx_buf, ARRAY_SIZE(tx_buf));
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	if (ret)
+		goto out;
+
+	pr_debug("Received response: %s\n", ss->rx_buf);
+	if (strncmp(ss->rx_buf, "ssr:ack", ARRAY_SIZE(ss->rx_buf)))
+		ret = -ENOSYS;
+	else
+		ret = 0;
+out:
+	mutex_unlock(&ss->lock);
 	return ret;
 }
 
-static void sysmon_notify(void *priv, unsigned int smd_event)
+static void sysmon_smd_notify(void *priv, unsigned int smd_event)
 {
 	struct sysmon_subsys *ss = priv;
 
@@ -104,44 +154,61 @@
 	}
 }
 
-static const uint32_t ss_map[SMD_NUM_TYPE] = {
-	[SMD_APPS_MODEM]	= SYSMON_SS_MODEM,
-	[SMD_APPS_QDSP]		= SYSMON_SS_LPASS,
-	[SMD_APPS_WCNSS]	= SYSMON_SS_WCNSS,
-	[SMD_APPS_DSPS]		= SYSMON_SS_DSPS,
-	[SMD_APPS_Q6FW]		= SYSMON_SS_Q6FW,
-};
-
 static int sysmon_probe(struct platform_device *pdev)
 {
 	struct sysmon_subsys *ss;
 	int ret;
 
-	if (pdev == NULL)
-		return -EINVAL;
-
-	if (pdev->id < 0 || pdev->id >= SMD_NUM_TYPE ||
-	    ss_map[pdev->id] < 0 || ss_map[pdev->id] >= SYSMON_NUM_SS)
+	if (pdev->id < 0 || pdev->id >= SYSMON_NUM_SS)
 		return -ENODEV;
 
-	ss = &subsys[ss_map[pdev->id]];
+	ss = &subsys[pdev->id];
 	mutex_init(&ss->lock);
 
-	/* Open and configure the SMD channel */
-	ret = smd_named_open_on_edge("sys_mon", pdev->id, &ss->chan,
-				     ss, sysmon_notify);
-	if (ret) {
-		pr_err("SMD open failed\n");
-		return -ENOSYS;
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		if (pdev->id >= SMD_NUM_TYPE)
+			return -EINVAL;
+
+		ret = smd_named_open_on_edge("sys_mon", pdev->id, &ss->chan, ss,
+					     sysmon_smd_notify);
+		if (ret) {
+			pr_err("SMD open failed\n");
+			return ret;
+		}
+
+		smd_disable_read_intr(ss->chan);
+		break;
+	case TRANSPORT_HSIC:
+		if (pdev->id < SMD_NUM_TYPE)
+			return -EINVAL;
+
+		ret = hsic_sysmon_open(HSIC_SYSMON_DEV_EXT_MODEM);
+		if (ret) {
+			pr_err("HSIC open failed\n");
+			return ret;
+		}
+		break;
+	default:
+		return -EINVAL;
 	}
-	smd_disable_read_intr(ss->chan);
 
 	return 0;
 }
 
 static int __devexit sysmon_remove(struct platform_device *pdev)
 {
-	smd_close(subsys[ss_map[pdev->id]].chan);
+	struct sysmon_subsys *ss = &subsys[pdev->id];
+
+	switch (ss->transport) {
+	case TRANSPORT_SMD:
+		smd_close(ss->chan);
+		break;
+	case TRANSPORT_HSIC:
+		hsic_sysmon_close(HSIC_SYSMON_DEV_EXT_MODEM);
+		break;
+	}
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
index 429a155..d014187 100644
--- a/arch/arm/mach-msm/sysmon.h
+++ b/arch/arm/mach-msm/sysmon.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, 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
@@ -15,21 +15,25 @@
 #ifndef __MSM_SYSMON_H
 #define __MSM_SYSMON_H
 
+#include <mach/msm_smd.h>
 #include <mach/subsystem_notif.h>
 
 /**
  * enum subsys_id - Destination subsystems for events.
  */
 enum subsys_id {
-	SYSMON_SS_MODEM,
-	SYSMON_SS_LPASS,
-	SYSMON_SS_WCNSS,
-	SYSMON_SS_DSPS,
-	SYSMON_SS_Q6FW,
+	/* SMD subsystems */
+	SYSMON_SS_MODEM     = SMD_APPS_MODEM,
+	SYSMON_SS_LPASS     = SMD_APPS_QDSP,
+	SYSMON_SS_WCNSS     = SMD_APPS_WCNSS,
+	SYSMON_SS_DSPS      = SMD_APPS_DSPS,
+	SYSMON_SS_Q6FW      = SMD_APPS_Q6FW,
+
+	/* Non-SMD subsystems */
+	SYSMON_SS_EXT_MODEM = SMD_NUM_TYPE,
 	SYSMON_NUM_SS
 };
 
-
 /**
  * sysmon_send_event() - Notify a subsystem of another's state change.
  * @dest_ss:	ID of subsystem the notification should be sent to.
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index c76bfd0..83f402b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -988,17 +988,47 @@
 	return status;
 }
 
+/* Find a memory structure attached to an adreno context */
+
+struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
+	unsigned int pt_base, unsigned int gpuaddr, unsigned int size)
+{
+	struct kgsl_context *context;
+	struct adreno_context *adreno_context = NULL;
+	int next = 0;
+
+	while (1) {
+		context = idr_get_next(&device->context_idr, &next);
+		if (context == NULL)
+			break;
+
+		adreno_context = (struct adreno_context *)context->devctxt;
+
+		if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
+			struct kgsl_memdesc *desc;
+
+			desc = &adreno_context->gpustate;
+			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
+				return desc;
+
+			desc = &adreno_context->context_gmem_shadow.gmemshadow;
+			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size))
+				return desc;
+		}
+		next = next + 1;
+	}
+
+	return NULL;
+}
+
 struct kgsl_memdesc *adreno_find_region(struct kgsl_device *device,
 						unsigned int pt_base,
 						unsigned int gpuaddr,
 						unsigned int size)
 {
-	struct kgsl_memdesc *result = NULL;
 	struct kgsl_mem_entry *entry;
 	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
 	struct adreno_ringbuffer *ringbuffer = &adreno_dev->ringbuffer;
-	struct kgsl_context *context;
-	int next = 0;
 
 	if (kgsl_gpuaddr_in_memdesc(&ringbuffer->buffer_desc, gpuaddr, size))
 		return &ringbuffer->buffer_desc;
@@ -1018,34 +1048,7 @@
 	if (entry)
 		return &entry->memdesc;
 
-	while (1) {
-		struct adreno_context *adreno_context = NULL;
-		context = idr_get_next(&device->context_idr, &next);
-		if (context == NULL)
-			break;
-
-		adreno_context = (struct adreno_context *)context->devctxt;
-
-		if (kgsl_mmu_pt_equal(adreno_context->pagetable, pt_base)) {
-			struct kgsl_memdesc *desc;
-
-			desc = &adreno_context->gpustate;
-			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
-				result = desc;
-				return result;
-			}
-
-			desc = &adreno_context->context_gmem_shadow.gmemshadow;
-			if (kgsl_gpuaddr_in_memdesc(desc, gpuaddr, size)) {
-				result = desc;
-				return result;
-			}
-		}
-		next = next + 1;
-	}
-
-	return NULL;
-
+	return adreno_find_ctxtmem(device, pt_base, gpuaddr, size);
 }
 
 uint8_t *adreno_convertaddr(struct kgsl_device *device, unsigned int pt_base,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4885312..48e70c8 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -128,6 +128,9 @@
 uint8_t *adreno_convertaddr(struct kgsl_device *device,
 	unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
 
+struct kgsl_memdesc *adreno_find_ctxtmem(struct kgsl_device *device,
+	unsigned int pt_base, unsigned int gpuaddr, unsigned int size);
+
 void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
 		int hang);
 
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index bca7040..e8cb734 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -657,17 +657,31 @@
 			parse_ibs = 0;
 
 		if (parse_ibs && adreno_cmd_is_ib(rbptr[index])) {
+			unsigned int ibaddr = rbptr[index + 1];
+			unsigned int ibsize = rbptr[index + 2];
+
 			/*
-			 * The IB from CP_IB1_BASE goes into the snapshot, all
+			 * This will return non NULL if the IB happens to be
+			 * part of the context memory (i.e - context switch
+			 * command buffers)
+			 */
+
+			struct kgsl_memdesc *memdesc =
+				adreno_find_ctxtmem(device, ptbase, ibaddr,
+					ibsize);
+
+			/*
+			 * The IB from CP_IB1_BASE and the IBs for legacy
+			 * context switch go into the snapshot all
 			 * others get marked at GPU objects
 			 */
-			if (rbptr[index + 1] == ibbase)
+
+			if (ibaddr == ibbase || memdesc != NULL)
 				push_object(device, SNAPSHOT_OBJ_TYPE_IB,
-					ptbase, rbptr[index + 1],
-					rbptr[index + 2]);
+					ptbase, ibaddr, ibsize);
 			else
-				ib_add_gpu_object(device, ptbase,
-					rbptr[index + 1], rbptr[index + 2]);
+				ib_add_gpu_object(device, ptbase, ibaddr,
+					ibsize);
 		}
 
 		index = index + 1;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index a908a3f..a93529a 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -617,7 +617,6 @@
 	mutex_lock(&device->mutex);
 	device->pwrctrl.restore_slumber = 0;
 	kgsl_pwrctrl_wake(device);
-	kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
 	mutex_unlock(&device->mutex);
 	kgsl_check_idle(device);
 	KGSL_PWR_WARN(device, "late resume end\n");
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 17f978e..6fa7da2 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -505,6 +505,7 @@
 	}
 	pwr->num_pwrlevels = pdata->num_levels;
 	pwr->active_pwrlevel = pdata->init_level;
+	pwr->default_pwrlevel = pdata->init_level;
 	for (i = 0; i < pdata->num_levels; i++) {
 		pwr->pwrlevels[i].gpu_freq =
 		(pdata->pwrlevel[i].gpu_freq > 0) ?
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 7dd429f..a677fec 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -46,6 +46,7 @@
 	struct kgsl_pwrlevel pwrlevels[KGSL_MAX_PWRLEVELS];
 	unsigned int active_pwrlevel;
 	int thermal_pwrlevel;
+	unsigned int default_pwrlevel;
 	unsigned int num_pwrlevels;
 	unsigned int interval_timeout;
 	bool strtstp_sleepwake;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index 4b8c938..e0825c3 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, 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
@@ -116,7 +116,7 @@
 		priv->governor == TZ_GOVERNOR_ONDEMAND &&
 		device->pwrctrl.restore_slumber == 0)
 		kgsl_pwrctrl_pwrlevel_change(device,
-					     device->pwrctrl.thermal_pwrlevel);
+					device->pwrctrl.default_pwrlevel);
 }
 
 static void tz_idle(struct kgsl_device *device, struct kgsl_pwrscale *pwrscale)
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index c24576d..553dc60 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -28,6 +28,7 @@
 	unsigned int gpuaddr;
 	unsigned int ptbase;
 	unsigned int size;
+	unsigned int offset;
 	int type;
 	struct kgsl_mem_entry *entry;
 	struct list_head node;
@@ -229,7 +230,7 @@
 		 * then offset the source pointer
 		 */
 
-		offset = obj->gpuaddr - obj->entry->memdesc.gpuaddr;
+		offset = obj->offset;
 
 		/*
 		 * Then  adjust it to account for the offset for the output
@@ -348,6 +349,7 @@
 	obj->gpuaddr = gpuaddr;
 	obj->ptbase = ptbase;
 	obj->size = size;
+	obj->offset = offset;
 
 	list_add(&obj->node, &device->snapshot_obj_list);
 
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 212e5d5..741c3a1 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -1465,6 +1465,7 @@
 	xfr_buf[1] = GET_ABS_VAL(band_low);
 	xfr_buf[2] = RSH_DATA(band_high, 8);
 	xfr_buf[3] = GET_ABS_VAL(band_high);
+	xfr_buf[4] = 0; /* Active LOW */
 	retval = sync_write_xfr(radio, RADIO_CONFIG, xfr_buf);
 	if (retval < 0) {
 		FMDERR("Could not set regional settings\n");
@@ -3037,8 +3038,8 @@
 		} else if (ctrl->value == FM_ANALOG_PATH) {
 			FMDBG("Analog audio path enabled ...\n");
 			retval = tavarua_set_audio_path(
-				TAVARUA_AUDIO_OUT_ANALOG_ON,
-				TAVARUA_AUDIO_OUT_DIGITAL_OFF);
+				TAVARUA_AUDIO_OUT_DIGITAL_OFF,
+				TAVARUA_AUDIO_OUT_ANALOG_ON);
 			if (retval < 0) {
 				FMDERR("Error in tavarua_set_audio_path"
 					" %d\n", retval);
@@ -3891,10 +3892,27 @@
 {
 	struct tavarua_device *radio = private_data;
 	int rx_on = radio->registers[RDCTRL] & FM_RECV;
+	int retval = 0;
 	if (!radio)
 		return -ENOMEM;
 	/* RX */
 	FMDBG("%s: digital: %d analog: %d\n", __func__, digital_on, analog_on);
+	if ((radio->pdata != NULL) && (radio->pdata->config_i2s_gpio != NULL)) {
+		if (digital_on) {
+			retval = radio->pdata->config_i2s_gpio(FM_I2S_ON);
+			if (retval) {
+				pr_err("%s: config_i2s_gpio failed\n",
+								__func__);
+			}
+		} else {
+			retval = radio->pdata->config_i2s_gpio(FM_I2S_OFF);
+			if (retval) {
+				pr_err("%s: config_i2s_gpio failed\n",
+								__func__);
+			}
+		}
+	}
+
 	SET_REG_FIELD(radio->registers[AUDIOCTRL],
 		((rx_on && analog_on) ? 1 : 0),
 		AUDIORX_ANALOG_OFFSET,
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index e6e2d52..7f0fbc3 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -271,6 +271,8 @@
 	ARRAY_SIZE(mt9e013_prev_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
 	{&mt9e013_hfr60_settings[0],
 	ARRAY_SIZE(mt9e013_hfr60_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
+	{&mt9e013_hfr60_settings[0],
+	ARRAY_SIZE(mt9e013_hfr60_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
 	{&mt9e013_hfr90_settings[0],
 	ARRAY_SIZE(mt9e013_hfr90_settings), 0, MSM_CAMERA_I2C_WORD_DATA},
 	{&mt9e013_hfr120_settings[0],
@@ -310,6 +312,15 @@
 		.y_output = 0x212,
 		.line_length_pclk = 0x970,
 		.frame_length_lines = 0x2A1,
+		.vt_pixel_clk = 98400000,
+		.op_pixel_clk = 98400000,
+		.binning_factor = 1,
+	},
+	{
+		.x_output = 0x340,
+		.y_output = 0x212,
+		.line_length_pclk = 0x970,
+		.frame_length_lines = 0x2A1,
 		.vt_pixel_clk = 146400000,
 		.op_pixel_clk = 146400000,
 		.binning_factor = 1,
@@ -339,6 +350,7 @@
 	&mt9e013_csi_params,
 	&mt9e013_csi_params,
 	&mt9e013_csi_params,
+	&mt9e013_csi_params,
 };
 
 static struct msm_sensor_output_reg_addr_t mt9e013_reg_addr = {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 50c115a..e1a6ffd 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -54,6 +54,7 @@
 #include <mach/clk.h>
 #include <mach/dma.h>
 #include <mach/sdio_al.h>
+#include <mach/mpm.h>
 
 #include "msm_sdcc.h"
 #include "msm_sdcc_dml.h"
@@ -2395,6 +2396,37 @@
 	return rc;
 }
 
+static int msmsdcc_cfg_mpm_sdiowakeup(struct msmsdcc_host *host,
+				      unsigned mode)
+{
+	int ret = 0;
+	unsigned int pin = host->plat->mpm_sdiowakeup_int;
+
+	if (!pin)
+		return 0;
+
+	switch (mode) {
+	case SDC_DAT1_DISABLE:
+		ret = msm_mpm_enable_pin(pin, 0);
+		break;
+	case SDC_DAT1_ENABLE:
+		ret = msm_mpm_set_pin_type(pin, IRQ_TYPE_LEVEL_LOW);
+		ret = msm_mpm_enable_pin(pin, 1);
+		break;
+	case SDC_DAT1_ENWAKE:
+		ret = msm_mpm_set_pin_wake(pin, 1);
+		break;
+	case SDC_DAT1_DISWAKE:
+		ret = msm_mpm_set_pin_wake(pin, 0);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
 static u32 msmsdcc_setup_pwr(struct msmsdcc_host *host, struct mmc_ios *ios)
 {
 	u32 pwr = 0;
@@ -2415,9 +2447,7 @@
 	switch (ios->power_mode) {
 	case MMC_POWER_OFF:
 		pwr = MCI_PWR_OFF;
-		if (host->plat->cfg_mpm_sdiowakeup)
-			host->plat->cfg_mpm_sdiowakeup(
-				mmc_dev(mmc), SDC_DAT1_DISABLE);
+		msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
 		/*
 		 * As VDD pad rail is always on, set low voltage for VDD
 		 * pad rail when slot is unused (when card is not present
@@ -2429,9 +2459,7 @@
 	case MMC_POWER_UP:
 		/* writing PWR_UP bit is redundant */
 		pwr = MCI_PWR_UP;
-		if (host->plat->cfg_mpm_sdiowakeup)
-			host->plat->cfg_mpm_sdiowakeup(
-				mmc_dev(mmc), SDC_DAT1_ENABLE);
+		msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
 
 		msmsdcc_set_vddp_high_vol(host);
 		msmsdcc_setup_pins(host, true);
@@ -2519,9 +2547,7 @@
 			writel_relaxed(MCI_SDIOINTMASK,
 					host->base + MMCIMASK0);
 			mb();
-			if (host->plat->cfg_mpm_sdiowakeup)
-				host->plat->cfg_mpm_sdiowakeup(
-					mmc_dev(mmc), SDC_DAT1_ENWAKE);
+			msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENWAKE);
 			/* configure sdcc core interrupt as wakeup interrupt */
 			msmsdcc_enable_irq_wake(host);
 		} else {
@@ -2543,9 +2569,7 @@
 			 */
 			writel_relaxed(MCI_SDIOINTMASK, host->base + MMCICLEAR);
 			msmsdcc_sync_reg_wr(host);
-			if (host->plat->cfg_mpm_sdiowakeup)
-				host->plat->cfg_mpm_sdiowakeup(
-					mmc_dev(mmc), SDC_DAT1_DISWAKE);
+			msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISWAKE);
 			msmsdcc_disable_irq_wake(host);
 		} else if (!host->sdio_wakeupirq_disabled) {
 			disable_irq_nosync(host->plat->sdiowakeup_irq);
@@ -4571,7 +4595,7 @@
 		mmc->caps |= (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
 				MMC_CAP_SET_XPC_180);
 
-	mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
+	mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC | MMC_CAP2_DETECT_ON_ERR);
 	if (pdev->dev.of_node) {
 		if (of_get_property((&pdev->dev)->of_node,
 					"qcom,sdcc-hs200", NULL))
@@ -4642,7 +4666,7 @@
 		}
 	}
 
-	if (plat->cfg_mpm_sdiowakeup) {
+	if (host->plat->mpm_sdiowakeup_int) {
 		wake_lock_init(&host->sdio_wlock, WAKE_LOCK_SUSPEND,
 				mmc_hostname(mmc));
 	}
@@ -5088,7 +5112,7 @@
 		 * the SDIO work will be processed.
 		 */
 		if (mmc->card && mmc_card_sdio(mmc->card)) {
-			if ((host->plat->cfg_mpm_sdiowakeup ||
+			if ((host->plat->mpm_sdiowakeup_int ||
 					host->plat->sdiowakeup_irq) &&
 					wake_lock_active(&host->sdio_wlock))
 				wake_lock_timeout(&host->sdio_wlock, 1);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 6b6b75c..41eeee1 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2111,9 +2111,9 @@
 		} else {
 			pr_debug("chg_work cancel");
 			cancel_delayed_work_sync(&motg->chg_work);
-			msm_otg_notify_charger(motg, 0);
 			motg->chg_state = USB_CHG_STATE_UNDEFINED;
 			motg->chg_type = USB_INVALID_CHARGER;
+			msm_otg_notify_charger(motg, 0);
 			msm_otg_reset(otg);
 			pm_runtime_put_noidle(otg->dev);
 			pm_runtime_suspend(otg->dev);
@@ -2152,11 +2152,11 @@
 				test_bit(ID_B, &motg->inputs) ||
 				!test_bit(B_SESS_VLD, &motg->inputs)) {
 			pr_debug("!id  || id_a/b || !b_sess_vld\n");
+			motg->chg_state = USB_CHG_STATE_UNDEFINED;
+			motg->chg_type = USB_INVALID_CHARGER;
 			msm_otg_notify_charger(motg, 0);
 			srp_reqd = otg->gadget->otg_srp_reqd;
 			msm_otg_start_peripheral(otg, 0);
-			motg->chg_state = USB_CHG_STATE_UNDEFINED;
-			motg->chg_type = USB_INVALID_CHARGER;
 			if (test_bit(ID_B, &motg->inputs))
 				clear_bit(ID_B, &motg->inputs);
 			clear_bit(B_BUS_REQ, &motg->inputs);
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 562c0c8..b768784 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -467,6 +467,14 @@
 {
     /* empty */
 }
+static inline void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
+{
+	return;
+}
+static inline void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+	return;
+}
 #endif
 
 void mdp4_dtv_set_black_screen(void);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 04d4ca4..0068c2a 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -67,7 +67,7 @@
  * It can be used to eliminate pops between different playback streams, e.g.
  * between two audio tracks.
  */
-static int pmdown_time = 5000;
+static int pmdown_time;
 module_param(pmdown_time, int, 0);
 MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");