Merge "platform-drivers: msm: sps: migrate to new clock API" into msm-3.0
diff --git a/Documentation/arm/msm/tspp.txt b/Documentation/arm/msm/tspp.txt
new file mode 100644
index 0000000..a56f014
--- /dev/null
+++ b/Documentation/arm/msm/tspp.txt
@@ -0,0 +1,250 @@
+Introduction
+============
+The TSPP (Transport stream packet processor) is a hardware accelerator
+designed to process MPEG2 TS (transport stream) data. It is mainly used for
+broadcast terrestrial services to off-load the host CPU from real-time
+sensitive TS processing for high bandwidth streams (~20Mbps). Data is received
+either via TSIF (Transport stream interface) or system memory.
+The TSPP driver manages the TSIF 12Seg HW core, which consists of a TSPP, a
+BAM (Bus access manager, used for DMA) and two TSIF inputs.
+It is applicable to the TSIF 12Seg core found on select Qualcomm MSM chips.
+
+For more information on the TSIF interface, please refer to TSIF documentation
+(Documentation/arm/msm/tsif.txt).
+For more information on the BAM interface, please refer to SPS documentation
+(Documentation/dma/sps/sps_architecture.txt).
+
+Hardware description
+====================
+The TSPP unit expands the capabilities of the TSIF interface by adding MPEG2
+stream processing such as:
+	- Elementary Stream PID filtering and de-multiplexing
+	- Several TSP processing operation modes:
+		- TSP Raw processing (with or w/o suffix)
+		- TSP PES assembly
+	- Error handling
+	- Multi2 decryption
+
+    +-------------+  +------+
+  +>|ARM subsystem|  |Memory|
+  | +-------------+  +------+
+  |        |            |
+ I|        |            |
+ R|  ========================== System bus
+ Q|             |
+ s|             |  TSIF 12Seg
+  | +-----------------------+
+  | |  +---+                |
+  | |  |BAM|                |
+  | |  +---+                |  GPIOs
+  | |    |        +------+--|-------- TSIF 0 clk
+  | |  +----+     |TSIF 0|--|-------- TSIF 0 data
+  +-|  |    |-----+------+--|-------- TSIF 0 en
+    |  |TSPP|               |
+    |  |    |-----+------+--|-------- TSIF 1 clk
+    |  +----+     |TSIF 1|--|-------- TSIF 1 data
+    |             +------+--|-------- TSIF 1 en
+    +-----------------------+
+
+   The TSPP unit receives an MPEG2 transport stream either via the two TSIF
+	interfaces, or via system memory.
+   It uses the BAM interface to transfer data to and from system memory.
+   The ARM subsystem receives interrupts on various error conditions from TSPP
+   and TSIF units, and on data transfer events from the BAM.
+
+Software Description
+====================
+The TSPP driver is responsible for:
+ - TSPP/TSIF hardware configuration (using SPS driver to configure BAM
+   hardware)
+ - TSIF GPIO/Clocks configuration
+ - Memory resource management
+ - Handling TSIF/TSPP interrupts and BAM events
+ - TSPP Power management
+
+TSPP Terminology
+----------------
+Device - the TSPP hardware instance
+  - the device contains many streams
+Stream: All data that is received from a particular TS packet source
+  - For example, MPEG2 Transport Stream from TSIF0
+  - A stream can consist of many channels
+Channel: A channel routes part of a stream to a specified memory location
+  - For example, video and audio can be routed to different memory locations
+    using different channels
+  - Channel contents are defined by filters
+Filter: Enables TS packet filtering and routing according to PID (packet ID)
+  - The decision regarding which PIDs in the stream will be routed to a
+    channel is done via filters
+  - Several filters can be registered to the same channel
+  - Filters can pass TS packets as-is (Raw mode) or assemble them into PES
+    packets (PES mode)
+  - Groups of contiguous PIDs can be filtered together (i.e. PSI/SI 0x0-0x2F,
+    1Seg PMTs 0x1FC8-0x1FCF)
+  - Filters can be used to discard packets (e.g. eliminate processing of
+    unwanted channels)
+
+Init flow:
+----------
+Driver registers BAM (via SPS driver) and initializes TSIF/TSPP hardware.
+
+Control path:
+-------------
+1. Client opens a TSPP stream and channel
+2. Client notifies the driver of the source stream (TSIF0/TSIF1/Memory)
+  - TSPP driver allocates memory for the channel (circular buffer)
+  - As the amount of memory varies according to stream bandwidth (which the
+    driver doesn't know), a client can hint to the driver about the required
+	 memory or stream bandwidth
+  - TSPP driver configures TSIF/BAM hardware according to selected stream
+3. Client notifies the driver to filter a set of PIDs for the selected channel
+  - TSPP driver configures TSPP hardware filters accordingly
+4. Client can now read data received from the selected channel
+
+Optional: Scrambling keys can be configured for a filter to decrypt Multi2
+encrypted streams.  The scrambling keys are received encrypted in-stream every
+~2 seconds. The client uses a smart card and master key to decrypt the
+received scrambling keys.  The master key remains inside the smart card and is
+never revealed to software.
+
+Conceptual flow:
+Client                  TSPP Driver                 SPS Driver         Hardware
+ |                           |                           |                   |
+ |                           | Init TSIF/TSPP            |                   |
+ |                           |---------------------------|------------------>|
+ |                           | Register BAM              |                   |
+ |                           |-------------------------->|                   |
+ |                           |                           |                   |
+ | open(tspp.5)              |                           |                   |
+ |-------------------------->|                           |                   |
+ | ioctl(tspp.5,SOURCE,TSIF0)|                           |                   |
+ |-------------------------->|                           |                   |
+ |                           | buff[0..N] = alloc()      |                   |
+ |                           |---------->                |                   |
+ |                           | Connect(TSPP,MEM)         |                   |
+ |                           |-------------------------->|                   |
+ |                           | Transfer(buff[0..N])      |                   |
+ |                           |-------------------------->|                   |
+ |                           |                           |                   |
+ |                           | Configure TSIF0           |                   |
+ |                           |---------------------------|------------------>|
+ |                           |                           |                   |
+ | ioctl(tspp.5,FILTER,pid)  |                           |                   |
+ |-------------------------->|                           |                   |
+ |                           | Configure TSPP filters    |                   |
+ |                           |---------------------------|------------------>|
+ |                           |                           |                   |
+ |                           |                           |               INT |
+ |                           |                           |<------------------|
+ |                           |       notify(EOT,buff[x]) |                   |
+ |                           |<--------------------------|                   |
+ |                           | Transfer(buff[y])         |                   |
+ |                           |-------------------------->|                   |
+ |                           |                           |                   |
+ | read(tspp.5)              |                           |                   |
+ |-------------------------->|                           |                   |
+ |                           |                           |                   |
+
+
+Data path:
+----------
+The TSPP driver is not involved in data transfer, other than managing the
+circular buffer pointers when a transfer is complete.  Data loss can occur if
+a client cannot keep up with stream bandwidth.
+The driver does not notify the application if there is data loss.  It is
+assumed that the application will read data when the data is ready, and when
+the application is able.
+
+API
+===
+int tspp_open_stream(tspp_device *dev, void *stream, void *channel, tspp_mode
+	mode);
+int tspp_close_stream(tspp_device *dev, void *stream);
+int tspp_open_channel(tspp_device *dev, int dest, int bufsize, void *channel);
+int tspp_close_channel(tspp_device *dev, void *channel);
+int tspp_register_filter(tspp_device *dev, void *channel, tspp_filter *filter);
+int tspp_unregister_filter(tspp_device *dev, void *channel, int pid);
+
+Refer to chrdev implementation in kernel/drivers/misc/tspp.c for an example of
+how to use this api.
+
+Each stream is represented by a chrdev device
+16 available devices: /dev/tspp00 - /dev/tspp15
+Each device implements these functions:
+open()
+close()
+read()
+ioctl()
+
+ioctl() contains several sub-functions:
+0: select source
+1: add filter
+2: remove filter
+3: set decryption keys
+4: set initial cbc values (IV)
+5: set system keys
+6: set buffer size
+
+You can refer to include/linux/tspp.h for the details on the structures
+associated with these IOCTL calls.
+
+Design
+======
+Design is based on the existing TSIF driver, with added control functionality
+for the extra hardware features.
+
+Power Management
+===============
+TSPP driver prevents MSM from sleeping while TSPP hardware is active.
+To achieve this, the driver holds the wake lock.  When no channels are
+configured to receive data, the driver stops the clocks to save power.
+It will register for suspend/resume in the future.
+
+SMP/multi-core
+==============
+Driver is fully SMP aware.
+
+Performance
+===========
+Control flows are rare.
+Data path only involves maintaining the circular buffer pointers.
+
+Interface
+=========
+Driver exposes a char device interface to user-space for each channel.
+Control transactions are performed via ioctl on the channel. Data is read as
+any regular char device (blocking and non-blocking).  Please see sequence
+under software description for more info.
+
+Debugfs may be used for debug purposes.  Through debugfs, all of the TSIF
+registers can be accessed under /sys/kernel/debug/tsif0 and tsif1.  The
+TSPP registers are found under /sys/kernel/debug/tspp0.  If you cannot
+see these devices, then either the driver has been built without debugfs
+support (check the define TSPP_USE_DEBUGFS in tspp.c) or the debugfs has
+not been mounted correctly (or mounted in a different location).
+
+Driver Parameters
+=================
+TSPP driver has target-specific parameters:
+- Memory base addresses for TSIF/TSPP/BAM
+- TSIF/TSPP/BAM IRQ numbers
+- TSIF GPIO numbers
+
+Config Options
+==============
+To enable the driver, set CONFIG_TSPP (=y or =m) in the appropriate
+config file for the platform.
+
+Dependencies
+============
+The TSPP driver depends on the SPS driver to configure BAM hardware.
+
+User space utilities
+====================
+The TSPP test suite can be found in:
+vendor/qcom/proprietary/kernel-tests/tspp
+
+Known Issues
+============
+Currently PES processing mode cannot be configured for streams in which the PES
+length is 0. This is a HW limitation.
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 00ff580..fc1d81a 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -295,6 +295,7 @@
 CONFIG_MMC_MSM_CARD_HW_DETECTION=y
 CONFIG_MMC_MSM_SDC3_SUPPORT=y
 CONFIG_MMC_MSM_SDC3_8_BIT_SUPPORT=y
+CONFIG_LEDS_GPIO=y
 CONFIG_LEDS_MSM_PDM=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index da8b9df..a872cdc 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -254,6 +254,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_PMIC8XXX=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
@@ -291,6 +292,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
+CONFIG_THERMAL_MONITOR=y
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 10b55dc..3337d06 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -255,6 +255,7 @@
 CONFIG_MSM_RMNET_BAM=y
 CONFIG_INPUT_EVDEV=y
 CONFIG_INPUT_EVBUG=m
+CONFIG_KEYBOARD_GPIO=y
 CONFIG_KEYBOARD_PMIC8XXX=y
 CONFIG_INPUT_JOYSTICK=y
 CONFIG_INPUT_TOUCHSCREEN=y
@@ -292,6 +293,7 @@
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
+CONFIG_THERMAL_MONITOR=y
 CONFIG_MFD_PM8921_CORE=y
 CONFIG_MFD_PM8821_CORE=y
 CONFIG_MFD_PM8038_CORE=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 69675e1..a3ed7ab 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -242,7 +242,7 @@
 obj-$(CONFIG_ARCH_APQ8064) += devices-8960.o devices-8064.o
 board-8960-all-objs += board-8960.o board-8960-camera.o board-8960-display.o board-8960-pmic.o board-8960-storage.o board-8960-gpiomux.o
 board-8930-all-objs += board-8930.o board-8930-camera.o board-8930-display.o board-8930-pmic.o board-8930-storage.o board-8930-gpiomux.o devices-8930.o
-board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o
+board-8064-all-objs += board-8064.o board-8064-pmic.o board-8064-storage.o board-8064-gpiomux.o board-8064-camera.o board-8064-display.o
 obj-$(CONFIG_MACH_MSM8960_SIM) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_RUMI3) += board-8960-all.o board-8960-regulator.o
 obj-$(CONFIG_MACH_MSM8960_CDP) += board-8960-all.o board-8960-regulator.o
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
new file mode 100644
index 0000000..73758d0
--- /dev/null
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -0,0 +1,144 @@
+/* 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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <asm/mach-types.h>
+#include <mach/msm_memtypes.h>
+#include <mach/board.h>
+#include <mach/gpio.h>
+#include <mach/gpiomux.h>
+#include <linux/ion.h>
+#include <mach/ion.h>
+
+#include "devices.h"
+#include "board-8064.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+/* prim = 1366 x 768 x 3(bpp) x 3(pages) */
+#define MSM_FB_PRIM_BUF_SIZE roundup(1366 * 768 * 3 * 3, 0x10000)
+#else
+/* prim = 1366 x 768 x 3(bpp) x 2(pages) */
+#define MSM_FB_PRIM_BUF_SIZE roundup(1366 * 768 * 3 * 2, 0x10000)
+#endif
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
+/* hdmi = 1920 x 1088 x 2(bpp) x 1(page) */
+#define MSM_FB_EXT_BUF_SIZE 0x3FC000
+#elif defined(CONFIG_FB_MSM_TVOUT)
+/* tvout = 720 x 576 x 2(bpp) x 2(pages) */
+#define MSM_FB_EXT_BUF_SIZE 0x195000
+#else /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+#define MSM_FB_EXT_BUF_SIZE 0
+#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
+
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY0_WRITEBACK */
+
+#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE roundup((1920 * 1088 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY1_WRITEBACK_SIZE (0)
+#endif  /* CONFIG_FB_MSM_OVERLAY1_WRITEBACK */
+
+static struct resource msm_fb_resources[] = {
+	{
+		.flags = IORESOURCE_DMA,
+	}
+};
+
+#define SIMULATOR_PANAL_NAME "mipi_video_simulator"
+#define SIMULATOR_PANAL_NAME_LEN 20
+#define LVDS_CHIMEI_PANEL_NAME "lvds_chimei_wxga"
+#define LVDS_CHIMEI_PANEL_NAME_LEN 16
+
+static int msm_fb_detect_panel(const char *name)
+{
+	if (!strncmp(name, LVDS_CHIMEI_PANEL_NAME,
+		LVDS_CHIMEI_PANEL_NAME_LEN))
+		return 0;
+	return -ENODEV;
+}
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+	.detect_client = msm_fb_detect_panel,
+};
+
+static struct platform_device msm_fb_device = {
+	.name              = "msm_fb",
+	.id                = 0,
+	.num_resources     = ARRAY_SIZE(msm_fb_resources),
+	.resource          = msm_fb_resources,
+	.dev.platform_data = &msm_fb_pdata,
+};
+
+void __init apq8064_allocate_fb_region(void)
+{
+	void *addr;
+	unsigned long size;
+
+	size = MSM_FB_SIZE;
+	addr = alloc_bootmem_align(size, 0x1000);
+	msm_fb_resources[0].start = __pa(addr);
+	msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+	pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
+			size, addr, __pa(addr));
+}
+
+#define MDP_VSYNC_GPIO 0
+
+static int mdp_core_clk_rate_table[] = {
+	266667000,
+	266667000,
+	266667000,
+	266667000,
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+	.gpio = MDP_VSYNC_GPIO,
+	.mdp_core_clk_rate = 266667000,
+	.mdp_core_clk_table = mdp_core_clk_rate_table,
+	.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
+	.mdp_rev = MDP_REV_44,
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	.mem_hid = ION_CP_MM_HEAP_ID,
+#else
+	.mem_hid = MEMTYPE_EBI1,
+#endif
+};
+
+void __init apq8064_mdp_writeback(struct memtype_reserve* reserve_table)
+{
+	mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+	mdp_pdata.ov1_wb_size = MSM_FB_OVERLAY1_WRITEBACK_SIZE;
+#if defined(CONFIG_ANDROID_PMEM) && !defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	reserve_table[mdp_pdata.mem_hid].size +=
+		mdp_pdata.ov0_wb_size;
+	reserve_table[mdp_pdata.mem_hid].size +=
+		mdp_pdata.ov1_wb_size;
+#endif
+}
+
+void __init apq8064_init_fb(void)
+{
+	platform_device_register(&msm_fb_device);
+	msm_fb_register_device("mdp", &mdp_pdata);
+	msm_fb_register_device("lvds", NULL);
+}
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 0808a54..6e3612a 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -27,6 +27,8 @@
 };
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8921_l2",		NULL),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-001a"),
+	REGULATOR_SUPPLY("mipi_csi_vdd",	"4-006c"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8921_l3",		NULL),
@@ -55,6 +57,8 @@
 };
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8921_l8",		NULL),
+	REGULATOR_SUPPLY("cam_vana",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vana",		"4-006c"),
 };
 VREG_CONSUMERS(L9) = {
 	REGULATOR_SUPPLY("8921_l9",		NULL),
@@ -67,6 +71,8 @@
 	REGULATOR_SUPPLY("8921_l11",		NULL),
 };
 VREG_CONSUMERS(L12) = {
+	REGULATOR_SUPPLY("cam_vdig",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vdig",		"4-006c"),
 	REGULATOR_SUPPLY("8921_l12",		NULL),
 };
 VREG_CONSUMERS(L14) = {
@@ -77,6 +83,8 @@
 };
 VREG_CONSUMERS(L16) = {
 	REGULATOR_SUPPLY("8921_l16",		NULL),
+	REGULATOR_SUPPLY("cam_vaf",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vaf",		"4-006c"),
 };
 VREG_CONSUMERS(L17) = {
 	REGULATOR_SUPPLY("8921_l17",		NULL),
@@ -158,6 +166,8 @@
 };
 VREG_CONSUMERS(LVS5) = {
 	REGULATOR_SUPPLY("8921_lvs5",		NULL),
+	REGULATOR_SUPPLY("cam_vio",		"4-001a"),
+	REGULATOR_SUPPLY("cam_vio",		"4-006c"),
 };
 VREG_CONSUMERS(LVS6) = {
 	REGULATOR_SUPPLY("8921_lvs6",		NULL),
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 924a67d..ec2b879 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -70,7 +70,7 @@
 #endif
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
@@ -314,11 +314,17 @@
 #endif
 }
 
+static void __init reserve_mdp_memory(void)
+{
+	apq8064_mdp_writeback(apq8064_reserve_table);
+}
+
 static void __init apq8064_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
 	reserve_ion_memory();
+	reserve_mdp_memory();
 }
 
 static struct reserve_info apq8064_reserve_info __initdata = {
@@ -1080,6 +1086,9 @@
 static struct platform_device *rumi3_devices[] __initdata = {
 	&apq8064_device_uart_gsbi1,
 	&msm_device_sps_apq8064,
+#ifdef CONFIG_MSM_ROTATOR
+	&msm_rotator_device,
+#endif
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -1185,6 +1194,11 @@
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 }
 
+static void __init apq8064_allocate_memory_regions(void)
+{
+	apq8064_allocate_fb_region();
+}
+
 static void __init apq8064_sim_init(void)
 {
 	struct msm_watchdog_pdata *wdog_pdata = (struct msm_watchdog_pdata *)
@@ -1201,6 +1215,7 @@
 	ethernet_init();
 	platform_add_devices(rumi3_devices, ARRAY_SIZE(rumi3_devices));
 	spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+	apq8064_init_fb();
 }
 
 static void __init apq8064_cdp_init(void)
@@ -1227,6 +1242,7 @@
 	.handle_irq = gic_handle_irq,
 	.timer = &msm_timer,
 	.init_machine = apq8064_rumi3_init,
+	.init_early = apq8064_allocate_memory_regions,
 MACHINE_END
 
 MACHINE_START(APQ8064_CDP, "QCT APQ8064 CDP")
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 1634b05..916e569 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -15,7 +15,7 @@
 
 #include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/mfd/pm8xxx/pm8821.h>
-
+#include <mach/msm_memtypes.h>
 /* Macros assume PMIC GPIOs and MPPs start at 1 */
 #define PM8921_GPIO_BASE		NR_GPIO_IRQS
 #define PM8921_GPIO_PM_TO_SYS(pm_gpio)	(pm_gpio - 1 + PM8921_GPIO_BASE)
@@ -47,4 +47,8 @@
 extern struct msm_camera_board_info apq8064_camera_board_info;
 void apq8064_init_cam(void);
 #define APQ_8064_GSBI4_QUP_I2C_BUS_ID 4
+
+void apq8064_init_fb(void);
+void apq8064_allocate_fb_region(void);
+void apq8064_mdp_writeback(struct memtype_reserve *reserve_table);
 #endif
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index b7400d1..f55125c 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -148,7 +148,7 @@
 	static struct regulator *reg_l8, *reg_l23, *reg_l2;
 	int rc;
 
-	pr_info("%s: state : %d\n", __func__, on);
+	pr_debug("%s: state : %d\n", __func__, on);
 
 	if (!dsi_power_on) {
 
@@ -269,7 +269,7 @@
 
 static int mipi_dsi_panel_power(int on)
 {
-	pr_info("%s: on=%d\n", __func__, on);
+	pr_debug("%s: on=%d\n", __func__, on);
 
 	return mipi_dsi_cdp_panel_power(on);
 }
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 989fde3..c652238 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -110,6 +110,9 @@
 	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
 	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8038_l24",		NULL),
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 75d0fb2..fc91337 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -126,7 +126,7 @@
 
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
@@ -1554,9 +1554,20 @@
 	return;
 }
 
+static struct mxt_config_info mxt_config_array[] = {
+	{
+		.config			= mxt_config_data_8930,
+		.config_length		= ARRAY_SIZE(mxt_config_data_8930),
+		.family_id		= 0x81,
+		.variant_id		= 0x01,
+		.version		= 0x10,
+		.build			= 0xAA,
+	},
+};
+
 static struct mxt_platform_data mxt_platform_data_8930 = {
-	.config			= mxt_config_data_8930,
-	.config_length		= ARRAY_SIZE(mxt_config_data_8930),
+	.config_array		= mxt_config_array,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array),
 	.x_size			= 1067,
 	.y_size			= 566,
 	.irqflags		= IRQF_TRIGGER_FALLING,
@@ -1701,14 +1712,6 @@
 	.tsens_num_sensor	= 5,
 };
 
-static struct platform_device msm_tsens_device = {
-	.name	= "tsens8960-tm",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &msm_tsens_pdata,
-	},
-};
-
 #ifdef CONFIG_MSM_FAKE_BATTERY
 static struct platform_device fish_battery_device = {
 	.name = "fish_battery",
@@ -1891,7 +1894,6 @@
 	&msm_bus_mm_fabric,
 	&msm_bus_sys_fpb,
 	&msm_bus_cpss_fpb,
-	&msm_tsens_device,
 };
 
 static void __init msm8930_i2c_init(void)
@@ -2213,6 +2215,7 @@
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
+	msm_tsens_early_init(&msm_tsens_pdata);
 	BUG_ON(msm_rpm_init(&msm8930_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 3c7878d..bc45cdf 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -15,13 +15,13 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/bootmem.h>
+#include <linux/ion.h>
 #include <asm/mach-types.h>
 #include <mach/msm_bus_board.h>
 #include <mach/msm_memtypes.h>
 #include <mach/board.h>
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
-#include <linux/ion.h>
 #include <mach/ion.h>
 
 #include "devices.h"
@@ -156,7 +156,7 @@
 	static int gpio21, gpio24, gpio43;
 	int rc;
 
-	pr_info("%s: on=%d\n", __func__, on);
+	pr_debug("%s: on=%d\n", __func__, on);
 
 	gpio21 = PM8921_GPIO_PM_TO_SYS(21); /* disp power enable_n */
 	gpio43 = PM8921_GPIO_PM_TO_SYS(43); /* Displays Enable (rst_n)*/
@@ -266,7 +266,7 @@
 	static int gpio43;
 	int rc;
 
-	pr_info("%s: state : %d\n", __func__, on);
+	pr_debug("%s: state : %d\n", __func__, on);
 
 	if (!dsi_power_on) {
 
@@ -386,7 +386,7 @@
 {
 	int ret;
 
-	pr_info("%s: on=%d\n", __func__, on);
+	pr_debug("%s: on=%d\n", __func__, on);
 
 	if (machine_is_msm8960_liquid())
 		ret = mipi_dsi_liquid_panel_power(on);
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 0dfa1c6..5b632bd 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -210,7 +210,7 @@
 static struct gpiomux_setting ap2mdm_kpdpwr_n_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
 	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_NONE,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting mdp_vsync_suspend_cfg = {
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index f36c3a1..5520bf9 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -110,6 +110,9 @@
 	REGULATOR_SUPPLY("8921_l23",		NULL),
 	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
 	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_riva"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.1"),
+	REGULATOR_SUPPLY("pll_vdd",		"pil_qdsp6v4.2"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8921_l24",		NULL),
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index a0a540f..a3380c6 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -139,7 +139,7 @@
 #define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x280000
 #define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
 #define MSM_ION_MM_FW_SIZE	0x200000 /* (2MB) */
 #define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
@@ -1397,8 +1397,8 @@
 	},
 };
 
-/* configuration data */
-static const u8 mxt_config_data[] = {
+/* configuration data for mxt1386 */
+static const u8 mxt1386_config_data[] = {
 	/* T6 Object */
 	0, 0, 0, 0, 0, 0,
 	/* T38 Object */
@@ -1444,6 +1444,118 @@
 	0, 0, 0, 0, 0, 0,
 };
 
+/* configuration data for mxt1386e using V1.0 firmware */
+static const u8 mxt1386e_config_data_v1_0[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	12, 1, 0, 17, 1, 12, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T7 Object */
+	100, 16, 50,
+	/* T8 Object */
+	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+	/* T9 Object */
+	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
+	85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
+	10, 5, 0, 0, 0,
+	/* T18 Object */
+	0, 0,
+	/* T24 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T25 Object */
+	3, 0, 60, 115, 156, 99,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	2, 0, 255, 0, 255, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T46 Object */
+	64, 0, 20, 20, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
+	/* T48 Object */
+	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
+	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T56 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	2, 99, 33,
+};
+
+/* configuration data for mxt1386e using V2.1 firmware */
+static const u8 mxt1386e_config_data_v2_1[] = {
+	/* T6 Object */
+	0, 0, 0, 0, 0, 0,
+	/* T38 Object */
+	12, 2, 0, 17, 1, 12, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T7 Object */
+	100, 16, 50,
+	/* T8 Object */
+	25, 0, 20, 20, 0, 0, 20, 50, 0, 0,
+	/* T9 Object */
+	131, 0, 0, 26, 42, 0, 32, 80, 2, 5,
+	0, 5, 5, 0, 10, 30, 10, 10, 255, 2,
+	85, 5, 10, 10, 10, 10, 135, 55, 70, 40,
+	10, 5, 0, 0, 0,
+	/* T18 Object */
+	0, 0,
+	/* T24 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0,
+	/* T25 Object */
+	3, 0, 60, 115, 156, 99,
+	/* T27 Object */
+	0, 0, 0, 0, 0, 0, 0,
+	/* T40 Object */
+	0, 0, 0, 0, 0,
+	/* T42 Object */
+	2, 0, 255, 0, 255, 0, 0, 0, 0, 0,
+	/* T43 Object */
+	0, 0, 0, 0, 0, 0, 0, 64, 0, 8,
+	16,
+	/* T46 Object */
+	64, 0, 20, 20, 0, 0, 0, 0, 0,
+	/* T47 Object */
+	0, 0, 0, 0, 0, 0, 3, 64, 66, 0,
+	/* T48 Object */
+	31, 64, 64, 0, 0, 0, 0, 0, 0, 0,
+	48, 40, 0, 10, 10, 0, 0, 100, 10, 80,
+	0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+	52, 0, 12, 0, 17, 0, 1, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0,
+	/* T56 Object */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	2, 99, 33, 0, 149, 24, 193, 255, 255, 255,
+	255,
+};
+
 #define MXT_TS_GPIO_IRQ			11
 #define MXT_TS_LDO_EN_GPIO		50
 #define MXT_TS_RESET_GPIO		52
@@ -1472,9 +1584,36 @@
 	gpio_free(MXT_TS_LDO_EN_GPIO);
 }
 
+static struct mxt_config_info mxt_config_array[] = {
+	{
+		.config		= mxt1386_config_data,
+		.config_length	= ARRAY_SIZE(mxt1386_config_data),
+		.family_id	= 0xA0,
+		.variant_id	= 0x0,
+		.version	= 0x10,
+		.build		= 0xAA,
+	},
+	{
+		.config		= mxt1386e_config_data_v1_0,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_v1_0),
+		.family_id	= 0xA0,
+		.variant_id	= 0x2,
+		.version	= 0x10,
+		.build		= 0xAA,
+	},
+	{
+		.config		= mxt1386e_config_data_v2_1,
+		.config_length	= ARRAY_SIZE(mxt1386e_config_data_v2_1),
+		.family_id	= 0xA0,
+		.variant_id	= 0x7,
+		.version	= 0x21,
+		.build		= 0xAA,
+	},
+};
+
 static struct mxt_platform_data mxt_platform_data = {
-	.config			= mxt_config_data,
-	.config_length		= ARRAY_SIZE(mxt_config_data),
+	.config_array		= mxt_config_array,
+	.config_array_size	= ARRAY_SIZE(mxt_config_array),
 	.x_size			= 1365,
 	.y_size			= 767,
 	.irqflags		= IRQF_TRIGGER_FALLING,
@@ -1572,14 +1711,6 @@
 		.tsens_num_sensor	= 5,
 };
 
-static struct platform_device msm_tsens_device = {
-	.name	= "tsens8960-tm",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &msm_tsens_pdata,
-	},
-};
-
 #ifdef CONFIG_MSM_FAKE_BATTERY
 static struct platform_device fish_battery_device = {
 	.name = "fish_battery",
@@ -1797,7 +1928,6 @@
 	&msm_bus_mm_fabric,
 	&msm_bus_sys_fpb,
 	&msm_bus_cpss_fpb,
-	&msm_tsens_device,
 };
 
 static void __init msm8960_i2c_init(void)
@@ -2177,6 +2307,7 @@
 		&msm8960_device_watchdog.dev.platform_data;
 
 	wdog_pdata->bark_time = 15000;
+	msm_tsens_early_init(&msm_tsens_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	regulator_suppress_info_printing();
@@ -2213,6 +2344,7 @@
 
 static void __init msm8960_rumi3_init(void)
 {
+	msm_tsens_early_init(&msm_tsens_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 	regulator_suppress_info_printing();
@@ -2247,6 +2379,7 @@
 	if (meminfo_init(SYS_MEMORY, SZ_256M) < 0)
 		pr_err("meminfo_init() failed!\n");
 
+	msm_tsens_early_init(&msm_tsens_pdata);
 	BUG_ON(msm_rpm_init(&msm8960_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
 
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index a21abb8..1f2a5ec 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -793,10 +793,75 @@
 				__func__, rc);
 }
 
+/* 8625 keypad device information */
+static unsigned int kp_row_gpios_8625[] = {31};
+static unsigned int kp_col_gpios_8625[] = {36, 37};
+
+static const unsigned short keymap_8625[] = {
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+};
+
+static struct gpio_event_matrix_info kp_matrix_info_8625 = {
+	.info.func      = gpio_event_matrix_func,
+	.keymap         = keymap_8625,
+	.output_gpios   = kp_row_gpios_8625,
+	.input_gpios    = kp_col_gpios_8625,
+	.noutputs       = ARRAY_SIZE(kp_row_gpios_8625),
+	.ninputs        = ARRAY_SIZE(kp_col_gpios_8625),
+	.settle_time.tv_nsec = 40 * NSEC_PER_USEC,
+	.poll_time.tv_nsec = 20 * NSEC_PER_MSEC,
+	.flags          = GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_DRIVE_INACTIVE |
+			  GPIOKPF_PRINT_UNMAPPED_KEYS,
+};
+
+static struct gpio_event_info *kp_info_8625[] = {
+	&kp_matrix_info_8625.info,
+};
+static struct gpio_event_platform_data kp_pdata_8625 = {
+	.name           = "8625_kp",
+	.info           = kp_info_8625,
+	.info_count     = ARRAY_SIZE(kp_info_8625)
+};
+
+static struct platform_device kp_pdev_8625 = {
+	.name   = GPIO_EVENT_DEV_NAME,
+	.id     = -1,
+	.dev    = {
+		.platform_data  = &kp_pdata_8625,
+	},
+};
+
+#define LED_RED_GPIO_8625 49
+#define LED_GREEN_GPIO_8625 34
+
+static struct gpio_led gpio_leds_config_8625[] = {
+	{
+		.name = "green",
+		.gpio = LED_GREEN_GPIO_8625,
+	},
+	{
+		.name = "red",
+		.gpio = LED_RED_GPIO_8625,
+	},
+};
+
+static struct gpio_led_platform_data gpio_leds_pdata_8625 = {
+	.num_leds = ARRAY_SIZE(gpio_leds_config_8625),
+	.leds = gpio_leds_config_8625,
+};
+
+static struct platform_device gpio_leds_8625 = {
+	.name          = "leds-gpio",
+	.id            = -1,
+	.dev           = {
+		.platform_data = &gpio_leds_pdata_8625,
+	},
+};
+
 static void msm7627a_add_io_devices(void)
 {
-	if (machine_is_msm7627a_evb())
-		return;
+	int rc;
 
 #if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
 	defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
@@ -810,6 +875,30 @@
 	msm_init_pmic_vibrator();
 #endif
 
+	/* keypad */
+	if (machine_is_msm7627a_evb())
+		platform_device_register(&kp_pdev_8625);
+
+	/* leds */
+	if (machine_is_msm7627a_evb()) {
+		rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, LED_RED_GPIO_8625);
+		}
+
+		rc = gpio_tlmm_config(GPIO_CFG(LED_GREEN_GPIO_8625, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_16MA), GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s: gpio_tlmm_config for %d failed\n",
+				__func__, LED_GREEN_GPIO_8625);
+		}
+
+		platform_device_register(&gpio_leds_8625);
+	}
 }
 
 #define UART1DM_RX_GPIO		45
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index d9e1724..e16cac5 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -1293,10 +1293,10 @@
 	}
 static struct clk_freq_tbl clk_tbl_gsbi_uart[] = {
 	F_GSBI_UART(       0, gnd,  1,  0,   0),
-	F_GSBI_UART( 1843200, pll8, 1,  3, 625),
-	F_GSBI_UART( 3686400, pll8, 1,  6, 625),
-	F_GSBI_UART( 7372800, pll8, 1, 12, 625),
-	F_GSBI_UART(14745600, pll8, 1, 24, 625),
+	F_GSBI_UART( 1843200, pll8, 2,  6, 625),
+	F_GSBI_UART( 3686400, pll8, 2, 12, 625),
+	F_GSBI_UART( 7372800, pll8, 2, 24, 625),
+	F_GSBI_UART(14745600, pll8, 2, 48, 625),
 	F_GSBI_UART(16000000, pll8, 4,  1,   6),
 	F_GSBI_UART(24000000, pll8, 4,  1,   4),
 	F_GSBI_UART(32000000, pll8, 4,  1,   3),
@@ -4813,6 +4813,8 @@
 
 static struct clk_lookup msm_clocks_8064[] = {
 	CLK_LOOKUP("cxo",		cxo_clk.c,		NULL),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"pil_riva"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,		NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,		NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,		NULL),
@@ -5050,6 +5052,8 @@
 
 static struct clk_lookup msm_clocks_8960_v1[] __initdata = {
 	CLK_LOOKUP("cxo",		cxo_clk.c,		NULL),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"wcnss_wlan.0"),
+	CLK_LOOKUP("cxo",		cxo_clk.c,		"pil_riva"),
 	CLK_LOOKUP("pll2",		pll2_clk.c,		NULL),
 	CLK_LOOKUP("pll8",		pll8_clk.c,		NULL),
 	CLK_LOOKUP("pll4",		pll4_clk.c,		NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 5ddeef9..3592c43 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -483,9 +483,9 @@
 	}
 static struct clk_freq_tbl clk_tbl_gsbi_uart[] = {
 	F_GSBI_UART(       0, gnd,  1,  0,   0),
-	F_GSBI_UART( 3686400, pll8, 1,  6, 625),
-	F_GSBI_UART( 7372800, pll8, 1, 12, 625),
-	F_GSBI_UART(14745600, pll8, 1, 24, 625),
+	F_GSBI_UART( 3686400, pll8, 2, 12, 625),
+	F_GSBI_UART( 7372800, pll8, 2, 24, 625),
+	F_GSBI_UART(14745600, pll8, 2, 48, 625),
 	F_GSBI_UART(16000000, pll8, 4,  1,   6),
 	F_GSBI_UART(24000000, pll8, 4,  1,   4),
 	F_GSBI_UART(32000000, pll8, 4,  1,   3),
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 050ec41..2d5ae78 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-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
@@ -454,12 +454,20 @@
  * Frequency-related functions
  */
 
-/* Set a clock's frequency. */
-static int _rcg_clk_set_rate(struct rcg_clk *clk, struct clk_freq_tbl *nf)
+/* Set a clock to an exact rate. */
+int rcg_clk_set_rate(struct clk *c, unsigned long rate)
 {
-	struct clk_freq_tbl *cf;
-	int rc = 0;
+	struct rcg_clk *clk = to_rcg_clk(c);
+	struct clk_freq_tbl *nf, *cf;
 	struct clk *chld;
+	int rc = 0;
+
+	for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END
+			&& nf->freq_hz != rate; nf++)
+		;
+
+	if (nf->freq_hz == FREQ_END)
+		return -EINVAL;
 
 	/* Check if frequency is actually changed. */
 	cf = clk->current_freq;
@@ -523,22 +531,6 @@
 	return rc;
 }
 
-/* Set a clock to an exact rate. */
-int rcg_clk_set_rate(struct clk *c, unsigned long rate)
-{
-	struct rcg_clk *clk = to_rcg_clk(c);
-	struct clk_freq_tbl *nf;
-
-	for (nf = clk->freq_tbl; nf->freq_hz != FREQ_END
-			&& nf->freq_hz != rate; nf++)
-		;
-
-	if (nf->freq_hz == FREQ_END)
-		return -EINVAL;
-
-	return _rcg_clk_set_rate(clk, nf);
-}
-
 /* Get the currently-set rate of a clock in Hz. */
 unsigned long rcg_clk_get_rate(struct clk *c)
 {
diff --git a/arch/arm/mach-msm/clock-local.h b/arch/arm/mach-msm/clock-local.h
index 9195fea..9292e5d 100644
--- a/arch/arm/mach-msm/clock-local.h
+++ b/arch/arm/mach-msm/clock-local.h
@@ -34,12 +34,12 @@
 
 /* NS Registers */
 #define NS(n_msb, n_lsb, n, m, mde_lsb, d_msb, d_lsb, d, s_msb, s_lsb, s) \
-		(BVAL(n_msb, n_lsb, ~(n-m)) \
+		(BVAL(n_msb, n_lsb, ~(n-m) * !!(n)) \
 		| (BVAL((mde_lsb+1), mde_lsb, MN_MODE_DUAL_EDGE) * !!(n)) \
 		| BVAL(d_msb, d_lsb, (d-1)) | BVAL(s_msb, s_lsb, s))
 
 #define NS_MM(n_msb, n_lsb, n, m, d_msb, d_lsb, d, s_msb, s_lsb, s) \
-		(BVAL(n_msb, n_lsb, ~(n-m)) | BVAL(d_msb, d_lsb, (d-1)) \
+		(BVAL(n_msb, n_lsb, ~(n-m) * !!(n))|BVAL(d_msb, d_lsb, (d-1)) \
 		| BVAL(s_msb, s_lsb, s))
 
 #define NS_DIVSRC(d_msb, d_lsb, d, s_msb, s_lsb, s) \
@@ -52,14 +52,14 @@
 		BVAL(s_msb, s_lsb, s)
 
 #define NS_MND_BANKED4(n0_lsb, n1_lsb, n, m, s0_lsb, s1_lsb, s) \
-		 (BVAL((n0_lsb+3), n0_lsb, ~(n-m)) \
-		| BVAL((n1_lsb+3), n1_lsb, ~(n-m)) \
+		 (BVAL((n0_lsb+3), n0_lsb, ~(n-m) * !!(n)) \
+		| BVAL((n1_lsb+3), n1_lsb, ~(n-m) * !!(n)) \
 		| BVAL((s0_lsb+2), s0_lsb, s) \
 		| BVAL((s1_lsb+2), s1_lsb, s))
 
 #define NS_MND_BANKED8(n0_lsb, n1_lsb, n, m, s0_lsb, s1_lsb, s) \
-		 (BVAL((n0_lsb+7), n0_lsb, ~(n-m)) \
-		| BVAL((n1_lsb+7), n1_lsb, ~(n-m)) \
+		 (BVAL((n0_lsb+7), n0_lsb, ~(n-m) * !!(n)) \
+		| BVAL((n1_lsb+7), n1_lsb, ~(n-m) * !!(n)) \
 		| BVAL((s0_lsb+2), s0_lsb, s) \
 		| BVAL((s1_lsb+2), s1_lsb, s))
 
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index d463c41..0ced722 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -1662,12 +1662,19 @@
 };
 #endif
 
+static struct platform_device msm_lvds_device = {
+	.name   = "lvds",
+	.id     = 0,
+};
+
 void __init msm_fb_register_device(char *name, void *data)
 {
 	if (!strncmp(name, "mdp", 3))
 		msm_register_device(&msm_mdp_device, data);
 	else if (!strncmp(name, "mipi_dsi", 8))
 		msm_register_device(&msm_mipi_dsi1_device, data);
+	else if (!strncmp(name, "lvds", 4))
+		msm_register_device(&msm_lvds_device, data);
 #ifdef CONFIG_MSM_BUS_SCALING
 	else if (!strncmp(name, "dtv", 3))
 		msm_register_device(&msm_dtv_device, data);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index d9bc654..d11c13f 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -303,6 +303,8 @@
 	MDP_REV_40,
 	MDP_REV_41,
 	MDP_REV_42,
+	MDP_REV_43,
+	MDP_REV_44,
 };
 
 struct msm_panel_common_pdata {
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 802ee2a..af272af 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.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
@@ -149,7 +149,14 @@
 			    (msm_xo_sources[MSM_XO_TCXO_A0].mode << 16) |
 			    (msm_xo_sources[MSM_XO_TCXO_A1].mode << 24) |
 			    (msm_xo_sources[MSM_XO_TCXO_A2].mode << 28) |
-			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20);
+			    /*
+			     * 8660 RPM has XO_CORE at bit 18 and 8960 RPM has
+			     * XO_CORE at bit 20. Since the opposite bit is
+			     * reserved in both cases, just set both and be
+			     * done with it.
+			     */
+			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 20) |
+			    ((msm_xo_sources[MSM_XO_CORE].mode ? 1 : 0) << 18);
 		ret = msm_rpm_set_noirq(MSM_RPM_CTX_SET_0, &cmd, 1);
 	}
 
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index d8ebab5..cdbfc48 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -1,4 +1,4 @@
-/* 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
@@ -19,6 +19,7 @@
 #include <linux/elf.h>
 #include <linux/delay.h>
 #include <linux/err.h>
+#include <linux/workqueue.h>
 
 #include <mach/msm_bus.h>
 #include <mach/msm_iomap.h>
@@ -68,9 +69,10 @@
 	void __iomem *modem_base;
 	unsigned long start_addr;
 	struct regulator *vreg;
+	struct regulator *pll_supply;
 	bool vreg_enabled;
 	struct msm_xo_voter *xo;
-	struct timer_list xo_timer;
+	struct delayed_work work;
 };
 
 static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -87,27 +89,32 @@
 	return 0;
 }
 
-static void pil_q6v4_make_xo_proxy_votes(struct device *dev)
+static void pil_q6v4_make_proxy_votes(struct device *dev)
 {
 	struct q6v4_data *drv = dev_get_drvdata(dev);
+	int ret;
 
 	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
-	mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+	if (drv->pll_supply) {
+		ret = regulator_enable(drv->pll_supply);
+		if (ret)
+			dev_err(dev, "failed to enable pll supply\n");
+	}
+	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 }
 
-static void pil_q6v4_remove_xo_proxy_votes(unsigned long data)
+static void pil_q6v4_remove_proxy_votes(struct work_struct *work)
 {
-	struct q6v4_data *drv = (struct q6v4_data *)data;
-
+	struct q6v4_data *drv = container_of(work, struct q6v4_data, work.work);
+	if (drv->pll_supply)
+		regulator_disable(drv->pll_supply);
 	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
 }
 
-static void pil_q6v4_remove_xo_proxy_votes_now(struct device *dev)
+static void pil_q6v4_remove_proxy_votes_now(struct device *dev)
 {
 	struct q6v4_data *drv = dev_get_drvdata(dev);
-
-	if (del_timer(&drv->xo_timer))
-		pil_q6v4_remove_xo_proxy_votes((unsigned long)drv);
+	flush_delayed_work(&drv->work);
 }
 
 static int pil_q6v4_power_up(struct device *dev)
@@ -184,7 +191,7 @@
 	const struct q6v4_data *drv = dev_get_drvdata(pil->dev);
 	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
 
-	pil_q6v4_make_xo_proxy_votes(pil->dev);
+	pil_q6v4_make_proxy_votes(pil->dev);
 
 	err = pil_q6v4_power_up(pil->dev);
 	if (err)
@@ -300,7 +307,7 @@
 		drv->vreg_enabled = false;
 	}
 
-	pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+	pil_q6v4_remove_proxy_votes_now(pil->dev);
 
 	return 0;
 }
@@ -324,7 +331,7 @@
 	const struct pil_q6v4_pdata *pdata = pil->dev->platform_data;
 	int err;
 
-	pil_q6v4_make_xo_proxy_votes(pil->dev);
+	pil_q6v4_make_proxy_votes(pil->dev);
 
 	err = pil_q6v4_power_up(pil->dev);
 	if (err)
@@ -355,7 +362,7 @@
 		drv->vreg_enabled = false;
 	}
 
-	pil_q6v4_remove_xo_proxy_votes_now(pil->dev);
+	pil_q6v4_remove_proxy_votes_now(pil->dev);
 
 	return ret;
 }
@@ -373,6 +380,7 @@
 	struct q6v4_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -396,9 +404,26 @@
 	}
 
 	desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
-	if (!drv)
+	if (!desc)
 		return -ENOMEM;
 
+	drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+	if (IS_ERR(drv->pll_supply)) {
+		drv->pll_supply = NULL;
+	} else {
+		ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to set pll voltage\n");
+			goto err;
+		}
+
+		ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "failed to set pll optimum mode\n");
+			goto err;
+		}
+	}
+
 	desc->name = pdata->name;
 	desc->depends_on = pdata->depends;
 	desc->dev = &pdev->dev;
@@ -412,26 +437,39 @@
 	}
 
 	drv->vreg = regulator_get(&pdev->dev, "core_vdd");
-	if (IS_ERR(drv->vreg))
-		return PTR_ERR(drv->vreg);
-
-	setup_timer(&drv->xo_timer, pil_q6v4_remove_xo_proxy_votes,
-		    (unsigned long)drv);
-	drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
-	if (IS_ERR(drv->xo))
-		return PTR_ERR(drv->xo);
-
-	if (msm_pil_register(desc)) {
-		regulator_put(drv->vreg);
-		return -EINVAL;
+	if (IS_ERR(drv->vreg)) {
+		ret = PTR_ERR(drv->vreg);
+		goto err;
 	}
+
+	drv->xo = msm_xo_get(pdata->xo_id, pdata->name);
+	if (IS_ERR(drv->xo)) {
+		ret = PTR_ERR(drv->xo);
+		goto err_xo;
+	}
+	INIT_DELAYED_WORK(&drv->work, pil_q6v4_remove_proxy_votes);
+
+	ret = msm_pil_register(desc);
+	if (ret)
+		goto err_pil;
 	return 0;
+err_pil:
+	cancel_delayed_work_sync(&drv->work);
+	msm_xo_put(drv->xo);
+err_xo:
+	regulator_put(drv->vreg);
+err:
+	regulator_put(drv->pll_supply);
+	return ret;
 }
 
 static int __devexit pil_q6v4_driver_exit(struct platform_device *pdev)
 {
 	struct q6v4_data *drv = platform_get_drvdata(pdev);
+	cancel_delayed_work_sync(&drv->work);
+	msm_xo_put(drv->xo);
 	regulator_put(drv->vreg);
+	regulator_put(drv->pll_supply);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index 6848c59..7e78a15 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -18,9 +18,11 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
 
 #include <mach/msm_iomap.h>
-#include <mach/msm_xo.h>
 
 #include "peripheral-loader.h"
 #include "scm-pas.h"
@@ -80,38 +82,40 @@
 struct riva_data {
 	void __iomem *base;
 	unsigned long start_addr;
-	struct msm_xo_voter *xo;
-	struct timer_list xo_timer;
+	struct clk *xo;
+	bool use_cxo;
+	struct delayed_work work;
+	struct regulator *pll_supply;
 };
 
-static void pil_riva_make_xo_proxy_votes(struct device *dev)
+static void pil_riva_make_proxy_votes(struct device *dev)
 {
 	struct riva_data *drv = dev_get_drvdata(dev);
+	int ret;
 
-	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_ON);
-	mod_timer(&drv->xo_timer, jiffies+msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
+	if (drv->use_cxo) {
+		ret = clk_prepare_enable(drv->xo);
+		if (ret)
+			dev_err(dev, "failed to enable xo\n");
+	}
+	ret = regulator_enable(drv->pll_supply);
+	if (ret)
+		dev_err(dev, "failed to enable pll supply\n");
+	schedule_delayed_work(&drv->work, msecs_to_jiffies(PROXY_VOTE_TIMEOUT));
 }
 
-static void pil_riva_remove_xo_proxy_votes(unsigned long data)
+static void pil_riva_remove_proxy_votes(struct work_struct *work)
 {
-	struct riva_data *drv = (struct riva_data *)data;
-
-	msm_xo_mode_vote(drv->xo, MSM_XO_MODE_OFF);
+	struct riva_data *drv = container_of(work, struct riva_data, work.work);
+	regulator_disable(drv->pll_supply);
+	if (drv->use_cxo)
+		clk_disable_unprepare(drv->xo);
 }
 
-static void pil_riva_remove_xo_proxy_votes_now(struct device *dev)
+static void pil_riva_remove_proxy_votes_now(struct device *dev)
 {
 	struct riva_data *drv = dev_get_drvdata(dev);
-
-	if (del_timer(&drv->xo_timer))
-		pil_riva_remove_xo_proxy_votes((unsigned long)drv);
-}
-
-static bool cxo_is_needed(struct riva_data *drv)
-{
-	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
-	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
-		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
+	flush_delayed_work(&drv->work);
 }
 
 static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
@@ -128,30 +132,38 @@
 	return 0;
 }
 
+static bool cxo_is_needed(struct riva_data *drv)
+{
+	u32 reg = readl_relaxed(drv->base + RIVA_PMU_CFG);
+	return (reg & RIVA_PMU_CFG_IRIS_XO_MODE)
+		!= RIVA_PMU_CFG_IRIS_XO_MODE_48;
+}
+
 static int pil_riva_reset(struct pil_desc *pil)
 {
 	u32 reg, sel;
-	bool use_cxo;
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	void __iomem *base = drv->base;
 	unsigned long start_addr = drv->start_addr;
+	int ret;
 
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
 	/* Enable A2XB bridge */
 	reg = readl_relaxed(base + RIVA_PMU_A2XB_CFG);
 	reg |= RIVA_PMU_A2XB_CFG_EN;
 	writel_relaxed(reg, base + RIVA_PMU_A2XB_CFG);
 
-	/* Proxy-vote for CXO if it's needed */
-	use_cxo = cxo_is_needed(drv);
-	if (use_cxo)
-		pil_riva_make_xo_proxy_votes(pil->dev);
+	drv->use_cxo = cxo_is_needed(drv);
+	pil_riva_make_proxy_votes(pil->dev);
 
 	/* Program PLL 13 to 960 MHz */
 	reg = readl_relaxed(RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_BYPASSNL | PLL_MODE_OUTCTRL | PLL_MODE_RESET_N);
 	writel_relaxed(reg, RIVA_PLL_MODE);
 
-	if (use_cxo)
+	if (drv->use_cxo)
 		writel_relaxed(0x40000C00 | 50, RIVA_PLL_L_VAL);
 	else
 		writel_relaxed(0x40000C00 | 40, RIVA_PLL_L_VAL);
@@ -161,7 +173,7 @@
 
 	reg = readl_relaxed(RIVA_PLL_MODE);
 	reg &= ~(PLL_MODE_REF_XO_SEL);
-	reg |= use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
+	reg |= drv->use_cxo ? PLL_MODE_REF_XO_SEL_CXO : PLL_MODE_REF_XO_SEL_RF;
 	writel_relaxed(reg, RIVA_PLL_MODE);
 
 	/* Enable PLL 13 */
@@ -226,6 +238,7 @@
 	/* Take cCPU out of reset */
 	reg |= RIVA_PMU_OVRD_VAL_CCPU_RESET;
 	writel_relaxed(reg, base + RIVA_PMU_OVRD_VAL);
+	clk_disable_unprepare(drv->xo);
 
 	return 0;
 }
@@ -234,7 +247,11 @@
 {
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	u32 reg;
+	int ret;
 
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
 	/* Put cCPU and cCPU clock into reset */
 	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
 	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
@@ -253,7 +270,8 @@
 	writel_relaxed(0, RIVA_RESET);
 	mb();
 
-	pil_riva_remove_xo_proxy_votes_now(pil->dev);
+	clk_disable_unprepare(drv->xo);
+	pil_riva_remove_proxy_votes_now(pil->dev);
 
 	return 0;
 }
@@ -274,19 +292,29 @@
 static int pil_riva_reset_trusted(struct pil_desc *pil)
 {
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
+	int ret;
 
-	/* Proxy-vote for CXO if it's needed */
-	if (cxo_is_needed(drv))
-		pil_riva_make_xo_proxy_votes(pil->dev);
-
-	return pas_auth_and_reset(PAS_RIVA);
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
+	/* Proxy-vote for resources RIVA needs */
+	pil_riva_make_proxy_votes(pil->dev);
+	ret = pas_auth_and_reset(PAS_RIVA);
+	clk_disable_unprepare(drv->xo);
+	return ret;
 }
 
 static int pil_riva_shutdown_trusted(struct pil_desc *pil)
 {
-	int ret = pas_shutdown(PAS_RIVA);
+	int ret;
+	struct riva_data *drv = dev_get_drvdata(pil->dev);
 
-	pil_riva_remove_xo_proxy_votes_now(pil->dev);
+	ret = clk_prepare_enable(drv->xo);
+	if (ret)
+		return ret;
+	ret = pas_shutdown(PAS_RIVA);
+	pil_riva_remove_proxy_votes_now(pil->dev);
+	clk_disable_unprepare(drv->xo);
 
 	return ret;
 }
@@ -303,6 +331,7 @@
 	struct riva_data *drv;
 	struct resource *res;
 	struct pil_desc *desc;
+	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -321,6 +350,23 @@
 	if (!desc)
 		return -ENOMEM;
 
+	drv->pll_supply = regulator_get(&pdev->dev, "pll_vdd");
+	if (IS_ERR(drv->pll_supply)) {
+		dev_err(&pdev->dev, "failed to get pll supply\n");
+		return PTR_ERR(drv->pll_supply);
+	}
+	ret = regulator_set_voltage(drv->pll_supply, 1800000, 1800000);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to set pll supply voltage\n");
+		goto err;
+	}
+
+	ret = regulator_set_optimum_mode(drv->pll_supply, 100000);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to set pll supply optimum mode\n");
+		goto err;
+	}
+
 	desc->name = "wcnss";
 	desc->dev = &pdev->dev;
 
@@ -332,17 +378,31 @@
 		dev_info(&pdev->dev, "using non-secure boot\n");
 	}
 
-	setup_timer(&drv->xo_timer, pil_riva_remove_xo_proxy_votes,
-		    (unsigned long)drv);
-	drv->xo = msm_xo_get(MSM_XO_CXO, desc->name);
-	if (IS_ERR(drv->xo))
-		return PTR_ERR(drv->xo);
+	drv->xo = clk_get(&pdev->dev, "cxo");
+	if (IS_ERR(drv->xo)) {
+		ret = PTR_ERR(drv->xo);
+		goto err;
+	}
+	INIT_DELAYED_WORK(&drv->work, pil_riva_remove_proxy_votes);
 
-	return msm_pil_register(desc);
+	ret = msm_pil_register(desc);
+	if (ret)
+		goto err_register;
+	return 0;
+err_register:
+	cancel_delayed_work_sync(&drv->work);
+	clk_put(drv->xo);
+err:
+	regulator_put(drv->pll_supply);
+	return ret;
 }
 
 static int __devexit pil_riva_remove(struct platform_device *pdev)
 {
+	struct riva_data *drv = platform_get_drvdata(pdev);
+	cancel_delayed_work_sync(&drv->work);
+	clk_put(drv->xo);
+	regulator_put(drv->pll_supply);
 	return 0;
 }
 
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 754d76f..9bdc2b3 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.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
@@ -63,6 +63,7 @@
 	MSM_PM_DEBUG_SUSPEND_LIMITS = BIT(2),
 	MSM_PM_DEBUG_CLOCK = BIT(3),
 	MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
+	MSM_PM_DEBUG_IDLE_CLK = BIT(5),
 	MSM_PM_DEBUG_IDLE = BIT(6),
 	MSM_PM_DEBUG_IDLE_LIMITS = BIT(7),
 	MSM_PM_DEBUG_HOTPLUG = BIT(8),
@@ -921,6 +922,9 @@
 		if (sleep_delay == 0) /* 0 would mean infinite time */
 			sleep_delay = 1;
 
+		if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
+			clock_debug_print_enabled();
+
 		ret = msm_rpmrs_enter_sleep(
 			sleep_delay, msm_pm_idle_rs_limits, true, notify_rpm);
 		if (!ret) {
diff --git a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
index 997fdf8..0181cb5 100644
--- a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
+++ b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
@@ -2229,7 +2229,7 @@
 };
 
 static struct adie_codec_action_unit ftm_spkr_r_adie_lp_rx_actions[] =
-	FTM_SPKR_RX_LB;
+	SPKR_R_RX;
 
 static struct adie_codec_hwsetting_entry ftm_spkr_r_adie_lp_rx_settings[] = {
 	{
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 6853654..e147b0e 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -80,11 +80,14 @@
 	case MSM8660_MACHINE_ID:
 		return APQ8060_TOOLS_ID;
 	case AO8960_MACHINE_ID:
+	case MSM8260A_MACHINE_ID:
 		return AO8960_TOOLS_ID;
 	case APQ8064_MACHINE_ID:
 		return APQ8064_TOOLS_ID;
 	case MSM8930_MACHINE_ID:
 		return MSM8930_TOOLS_ID;
+	case MSM8974_MACHINE_ID:
+		return MSM8974_TOOLS_ID;
 	default:
 		return 0;
 	}
@@ -105,12 +108,28 @@
 	case APQ8030_MACHINE_ID:
 	case MSM8627_MACHINE_ID:
 	case MSM8227_MACHINE_ID:
+	case MSM8974_MACHINE_ID:
+	case MDM9615_MACHINE_ID:
+	case MSM8260A_MACHINE_ID:
 		return 1;
 	default:
 		return 0;
 	}
 }
 
+/*
+ * This will return TRUE for targets which support apps as master.
+ * Thus, SW DLOAD and Mode Reset are supported on apps processor.
+ * This applies to 8960 and newer targets.
+ */
+int chk_apps_master(void)
+{
+	if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615())
+		return 1;
+	else
+		return 0;
+}
+
 void __diag_smd_send_req(void)
 {
 	void *buf = NULL;
@@ -532,8 +551,7 @@
 	} else {
 		if (len > 0) {
 			if (entry.client_id == MODEM_PROC && driver->ch) {
-				if ((cpu_is_msm8960() || cpu_is_msm8930() ||
-					cpu_is_msm9615()) &&
+				if (chk_apps_master() &&
 					 (int)(*(char *)buf) == MODE_CMD)
 					if ((int)(*(char *)(buf+1)) ==
 						RESET_ID)
@@ -573,8 +591,7 @@
 	temp += 2;
 	data_type = APPS_DATA;
 	/* Dont send any command other than mode reset */
-	if ((cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615()) &&
-		cmd_code == MODE_CMD) {
+	if (chk_apps_master() && cmd_code == MODE_CMD) {
 		if (subsys_id != RESET_ID)
 			data_type = MODEM_DATA;
 	}
@@ -858,8 +875,7 @@
 		return 0;
 	}
 	/* Check for download command */
-	else if ((cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_msm8930()
-		|| cpu_is_msm9615()) && (*buf == 0x3A)) {
+	else if ((cpu_is_msm8x60() || chk_apps_master()) && (*buf == 0x3A)) {
 		/* send response back */
 		driver->apps_rsp_buf[0] = *buf;
 		ENCODE_RSP_AND_SEND(0);
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 9730d4f..f2a2210 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -1,4 +1,4 @@
-/* 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
@@ -135,7 +135,7 @@
 {
 	int r = 0;
 
-	/* open control ports only on 8960 */
+	/* open control ports only on 8960 & newer targets */
 	if (chk_apps_only()) {
 		if (pdev->id == SMD_APPS_MODEM)
 			r = smd_open("DIAG_CNTL", &driver->ch_cntl, driver,
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 5e325e9..6bb0739 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -438,6 +438,7 @@
 	ion_buffer_put(buffer);
 	return handle;
 }
+EXPORT_SYMBOL(ion_alloc);
 
 void ion_free(struct ion_client *client, struct ion_handle *handle)
 {
@@ -455,6 +456,7 @@
 	}
 	ion_handle_put(handle);
 }
+EXPORT_SYMBOL(ion_free);
 
 static void ion_client_get(struct ion_client *client);
 static int ion_client_put(struct ion_client *client);
@@ -512,6 +514,7 @@
 	ret = buffer->heap->ops->phys(buffer->heap, buffer, addr, len);
 	return ret;
 }
+EXPORT_SYMBOL(ion_phys);
 
 void *ion_map_kernel(struct ion_client *client, struct ion_handle *handle,
 			unsigned long flags)
@@ -558,6 +561,7 @@
 	mutex_unlock(&client->lock);
 	return vaddr;
 }
+EXPORT_SYMBOL(ion_map_kernel);
 
 int __ion_iommu_map(struct ion_buffer *buffer,
 		int domain_num, int partition_num, unsigned long align,
@@ -776,6 +780,7 @@
 	mutex_unlock(&client->lock);
 	return sglist;
 }
+EXPORT_SYMBOL(ion_map_dma);
 
 void ion_unmap_kernel(struct ion_client *client, struct ion_handle *handle)
 {
@@ -791,6 +796,7 @@
 	mutex_unlock(&buffer->lock);
 	mutex_unlock(&client->lock);
 }
+EXPORT_SYMBOL(ion_unmap_kernel);
 
 void ion_unmap_dma(struct ion_client *client, struct ion_handle *handle)
 {
@@ -806,7 +812,7 @@
 	mutex_unlock(&buffer->lock);
 	mutex_unlock(&client->lock);
 }
-
+EXPORT_SYMBOL(ion_unmap_dma);
 
 struct ion_buffer *ion_share(struct ion_client *client,
 				 struct ion_handle *handle)
@@ -828,6 +834,7 @@
 	 */
 	return handle->buffer;
 }
+EXPORT_SYMBOL(ion_share);
 
 struct ion_handle *ion_import(struct ion_client *client,
 			      struct ion_buffer *buffer)
@@ -849,6 +856,7 @@
 	mutex_unlock(&client->lock);
 	return handle;
 }
+EXPORT_SYMBOL(ion_import);
 
 static int check_vaddr_bounds(unsigned long start, unsigned long end)
 {
@@ -937,6 +945,7 @@
 	fput(file);
 	return handle;
 }
+EXPORT_SYMBOL(ion_import_fd);
 
 static int ion_debug_client_show(struct seq_file *s, void *unused)
 {
@@ -1137,6 +1146,7 @@
 	if (client)
 		ion_client_put(client);
 }
+EXPORT_SYMBOL(ion_client_destroy);
 
 int ion_handle_get_flags(struct ion_client *client, struct ion_handle *handle,
 			unsigned long *flags)
diff --git a/drivers/gpu/msm/Makefile b/drivers/gpu/msm/Makefile
index 908b63d..7b8f3e6 100644
--- a/drivers/gpu/msm/Makefile
+++ b/drivers/gpu/msm/Makefile
@@ -8,7 +8,8 @@
 	kgsl_pwrscale.o \
 	kgsl_mmu.o \
 	kgsl_gpummu.o \
-	kgsl_iommu.o
+	kgsl_iommu.o \
+	kgsl_snapshot.o
 
 msm_kgsl_core-$(CONFIG_DEBUG_FS) += kgsl_debugfs.o
 msm_kgsl_core-$(CONFIG_MSM_KGSL_CFF_DUMP) += kgsl_cffdump.o
@@ -20,8 +21,10 @@
 	adreno_ringbuffer.o \
 	adreno_drawctxt.o \
 	adreno_postmortem.o \
+	adreno_snapshot.o \
 	adreno_a2xx.o \
 	adreno_a2xx_trace.o \
+	adreno_a2xx_snapshot.o \
 	adreno.o
 
 msm_adreno-$(CONFIG_DEBUG_FS) += adreno_debugfs.o
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index 5ffdea1..50b2745 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -416,4 +416,37 @@
 #define REG_A225_GRAS_UCP5W              0x2357
 #define REG_A225_GRAS_UCP_ENABLED        0x2360
 
+/* Debug registers used by snapshot */
+#define REG_PA_SU_DEBUG_CNTL            0x0C80
+#define REG_PA_SU_DEBUG_DATA            0x0C81
+#define REG_RB_DEBUG_CNTL               0x0F26
+#define REG_RB_DEBUG_DATA               0x0F27
+#define REG_PC_DEBUG_CNTL               0x0C38
+#define REG_PC_DEBUG_DATA               0x0C39
+#define REG_GRAS_DEBUG_CNTL             0x0C80
+#define REG_GRAS_DEBUG_DATA             0x0C81
+#define REG_SQ_DEBUG_MISC               0x0D05
+#define REG_SQ_DEBUG_INPUT_FSM          0x0DAE
+#define REG_SQ_DEBUG_CONST_MGR_FSM      0x0DAF
+#define REG_SQ_DEBUG_EXP_ALLOC          0x0DB3
+#define REG_SQ_DEBUG_FSM_ALU_0          0x0DB1
+#define REG_SQ_DEBUG_FSM_ALU_1          0x0DB2
+#define REG_SQ_DEBUG_PTR_BUFF           0x0DB4
+#define REG_SQ_DEBUG_GPR_VTX            0x0DB5
+#define REG_SQ_DEBUG_GPR_PIX            0x0DB6
+#define REG_SQ_DEBUG_TB_STATUS_SEL      0x0DB7
+#define REG_SQ_DEBUG_VTX_TB_0           0x0DB8
+#define REG_SQ_DEBUG_VTX_TB_1           0x0DB9
+#define REG_SQ_DEBUG_VTX_TB_STATE_MEM   0x0DBB
+#define REG_SQ_DEBUG_TP_FSM             0x0DB0
+#define REG_SQ_DEBUG_VTX_TB_STATUS_REG  0x0DBA
+#define REG_SQ_DEBUG_PIX_TB_0           0x0DBC
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_0 0x0DBD
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_1 0x0DBE
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_2 0x0DBF
+#define REG_SQ_DEBUG_PIX_TB_STATUS_REG_3 0x0DC0
+#define REG_SQ_DEBUG_PIX_TB_STATE_MEM   0x0DC1
+#define REG_SQ_DEBUG_MISC_0             0x2309
+#define REG_SQ_DEBUG_MISC_1             0x230A
+
 #endif /* __A200_REG_H */
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 03e447b..ce76a8f 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -728,8 +728,21 @@
 	} else {
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_DUMP_AND_RECOVER);
 		INIT_COMPLETION(device->recovery_gate);
-		/* Detected a hang - trigger an automatic dump */
+		/* Detected a hang */
+
+
+		/*
+		 * Trigger an automatic dump of the state to
+		 * the console
+		 */
 		adreno_postmortem_dump(device, 0);
+
+		/*
+		 * Make a GPU snapshot.  For now, do it after the PM dump so we
+		 * can at least be sure the PM dump will work as it always has
+		 */
+		kgsl_device_snapshot(device, 1);
+
 		result = adreno_recover_hang(device);
 		if (result)
 			kgsl_pwrctrl_set_state(device, KGSL_STATE_HUNG);
@@ -1094,7 +1107,8 @@
 			* get an interrupt */
 			cmds[0] = cp_type3_packet(CP_NOP, 1);
 			cmds[1] = 0;
-			adreno_ringbuffer_issuecmds(device, 0, &cmds[0], 2);
+			adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+				&cmds[0], 2);
 		}
 		mutex_unlock(&device->mutex);
 	}
@@ -1341,6 +1355,7 @@
 	.power_stats = adreno_power_stats,
 	.irqctrl = adreno_irqctrl,
 	.gpuid = adreno_gpuid,
+	.snapshot = adreno_snapshot,
 	/* Optional functions */
 	.setstate = adreno_setstate,
 	.drawctxt_create = adreno_drawctxt_create,
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index a3d2c00..bdba624 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -24,6 +24,7 @@
 		KGSL_CONTAINER_OF(device, struct adreno_device, dev)
 
 /* Flags to control command packet settings */
+#define KGSL_CMD_FLAGS_NONE             0x00000000
 #define KGSL_CMD_FLAGS_PMODE		0x00000001
 #define KGSL_CMD_FLAGS_NO_TS_CMP	0x00000002
 #define KGSL_CMD_FLAGS_NOT_KERNEL_CMD	0x00000004
@@ -84,6 +85,7 @@
 	void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
 	irqreturn_t (*irq_handler)(struct adreno_device *);
 	void (*irq_control)(struct adreno_device *, int);
+	void * (*snapshot)(struct adreno_device *, void *, int *, int);
 };
 
 extern struct adreno_gpudev adreno_a2xx_gpudev;
@@ -108,6 +110,9 @@
 uint8_t *adreno_convertaddr(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);
+
 static inline int adreno_is_a200(struct adreno_device *adreno_dev)
 {
 	return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 16402c3..cf9a60a 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1405,7 +1405,8 @@
 		"active context flags %08x\n", context->flags);
 
 	/* save registers and constants. */
-	adreno_ringbuffer_issuecmds(device, 0, context->reg_save, 3);
+	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+		context->reg_save, 3);
 
 	if (context->flags & CTXT_FLAGS_SHADER_SAVE) {
 		/* save shader partitioning and instructions. */
@@ -1415,7 +1416,7 @@
 		/* fixup shader partitioning parameter for
 		 *  SET_SHADER_BASES.
 		 */
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->shader_fixup, 3);
 
 		context->flags |= CTXT_FLAGS_SHADER_RESTORE;
@@ -1430,7 +1431,7 @@
 			context->context_gmem_shadow.gmem_save, 3);
 
 		/* Restore TP0_CHICKEN */
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->chicken_restore, 3);
 
 		context->flags |= CTXT_FLAGS_GMEM_RESTORE;
@@ -1481,7 +1482,7 @@
 	cmds[3] = device->memstore.gpuaddr +
 		KGSL_DEVICE_MEMSTORE_OFFSET(current_context);
 	cmds[4] = (unsigned int) context;
-	adreno_ringbuffer_issuecmds(device, 0, cmds, 5);
+	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE, cmds, 5);
 	kgsl_mmu_setstate(device, context->pagetable);
 
 #ifndef CONFIG_MSM_KGSL_CFF_DUMP_NO_CONTEXT_MEM_DUMP
@@ -1498,26 +1499,27 @@
 			context->context_gmem_shadow.gmem_restore, 3);
 
 		/* Restore TP0_CHICKEN */
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->chicken_restore, 3);
 
 		context->flags &= ~CTXT_FLAGS_GMEM_RESTORE;
 	}
 
 	/* restore registers and constants. */
-	adreno_ringbuffer_issuecmds(device, 0,
+	adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 		context->reg_restore, 3);
 
 	/* restore shader instructions & partitioning. */
 	if (context->flags & CTXT_FLAGS_SHADER_RESTORE) {
-		adreno_ringbuffer_issuecmds(device, 0,
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
 			context->shader_restore, 3);
 	}
 
 	if (adreno_is_a20x(adreno_dev)) {
 		cmds[0] = cp_type3_packet(CP_SET_BIN_BASE_OFFSET, 1);
 		cmds[1] = context->bin_base_offset;
-		adreno_ringbuffer_issuecmds(device, 0, cmds, 2);
+		adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
+			cmds, 2);
 	}
 }
 
@@ -1704,6 +1706,10 @@
 	wmb();
 }
 
+/* Defined in adreno_a2xx_snapshot.c */
+void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+	int *remain, int hang);
+
 struct adreno_gpudev adreno_a2xx_gpudev = {
 	.ctxt_gpustate_shadow = a2xx_ctxt_gpustate_shadow,
 	.ctxt_gmem_shadow = a2xx_ctxt_gmem_shadow,
@@ -1711,4 +1717,5 @@
 	.ctxt_restore = a2xx_ctxt_restore,
 	.irq_handler = a2xx_irq_handler,
 	.irq_control = a2xx_irq_control,
+	.snapshot = a2xx_snapshot,
 };
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
new file mode 100644
index 0000000..30d692b
--- /dev/null
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -0,0 +1,356 @@
+/* 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.
+ *
+ */
+
+#include "kgsl.h"
+#include "adreno.h"
+#include "kgsl_snapshot.h"
+
+#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+		+ sizeof(struct kgsl_snapshot_debug))
+
+/* Dump the SX debug registers into a GPU snapshot debug section */
+
+#define SXDEBUG_COUNT 0x1B
+
+static int a2xx_snapshot_sxdebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(SXDEBUG_COUNT)) {
+		SNAPSHOT_ERR_NOMEM(device, "SX DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SX;
+	header->size = SXDEBUG_COUNT;
+
+	for (i = 0; i < SXDEBUG_COUNT; i++) {
+		adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1B00 | i);
+		adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+	}
+
+	adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+	return DEBUG_SECTION_SZ(SXDEBUG_COUNT);
+}
+
+#define CPDEBUG_COUNT 0x20
+
+static int a2xx_snapshot_cpdebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(CPDEBUG_COUNT)) {
+		SNAPSHOT_ERR_NOMEM(device, "CP DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_CP;
+	header->size = CPDEBUG_COUNT;
+
+	for (i = 0; i < CPDEBUG_COUNT; i++) {
+		adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1628);
+		adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+	}
+
+	adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+	return DEBUG_SECTION_SZ(CPDEBUG_COUNT);
+}
+
+/*
+ * The contents of the SQ debug sections are dword pairs:
+ * [register offset]:[value]
+ * This macro writes both dwords for the given register
+ */
+
+#define SQ_DEBUG_WRITE(_device, _reg, _data, _offset) \
+	do { _data[(_offset)++] = (_reg); \
+	adreno_regread(_device, (_reg), &_data[(_offset)++]); } while (0)
+
+#define SQ_DEBUG_BANK_SIZE 23
+
+static int a2xx_snapshot_sqdebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, offset = 0;
+	int size = SQ_DEBUG_BANK_SIZE * 2 * 2;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "SQ Debug");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SQ;
+	header->size = size;
+
+	for (i = 0; i < 2; i++) {
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_CONST_MGR_FSM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_EXP_ALLOC+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_FSM_ALU_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_PIX+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_GPR_VTX+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_INPUT_FSM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_MISC_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_2+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device,
+			REG_SQ_DEBUG_PIX_TB_STATUS_REG_3+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PTR_BUFF+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TB_STATUS_SEL+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_TP_FSM+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_0+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_1+i*0x1000,
+			data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM+i*0x1000,
+			data, offset);
+	}
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define SQ_DEBUG_THREAD_SIZE 7
+
+static int a2xx_snapshot_sqthreaddebug(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i, offset = 0;
+	int size = SQ_DEBUG_THREAD_SIZE * 2 * 16;
+
+	if (remain < DEBUG_SECTION_SZ(size)) {
+		SNAPSHOT_ERR_NOMEM(device, "SQ THREAD DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_SQTHREAD;
+	header->size = size;
+
+	for (i = 0; i < 16; i++) {
+		adreno_regwrite(device, REG_SQ_DEBUG_TB_STATUS_SEL,
+				i | (6<<4) | (i<<7) | (1<<11) | (1<<12)
+				| (i<<16) | (6<<20) | (i<<23));
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATE_MEM,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_VTX_TB_STATUS_REG,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATE_MEM,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_0,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_1,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_2,
+			 data, offset);
+		SQ_DEBUG_WRITE(device, REG_SQ_DEBUG_PIX_TB_STATUS_REG_3,
+			 data, offset);
+	}
+
+	return DEBUG_SECTION_SZ(size);
+}
+
+#define MIUDEBUG_COUNT 0x10
+
+static int a2xx_snapshot_miudebug(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_debug *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < DEBUG_SECTION_SZ(MIUDEBUG_COUNT)) {
+		SNAPSHOT_ERR_NOMEM(device, "MIU DEBUG");
+		return 0;
+	}
+
+	header->type = SNAPSHOT_DEBUG_MIU;
+	header->size = MIUDEBUG_COUNT;
+
+	for (i = 0; i < MIUDEBUG_COUNT; i++) {
+		adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0x1600 | i);
+		adreno_regread(device, REG_RBBM_DEBUG_OUT, &data[i]);
+	}
+
+	adreno_regwrite(device, REG_RBBM_DEBUG_CNTL, 0);
+
+	return DEBUG_SECTION_SZ(MIUDEBUG_COUNT);
+}
+
+/* Helper function to snapshot a section of indexed registers */
+
+static void *a2xx_snapshot_indexed_registers(struct kgsl_device *device,
+		void *snapshot, int *remain,
+		unsigned int index, unsigned int data, unsigned int start,
+		unsigned int count)
+{
+	struct kgsl_snapshot_indexed_registers iregs;
+	iregs.index = index;
+	iregs.data = data;
+	iregs.start = start;
+	iregs.count = count;
+
+	return kgsl_snapshot_add_section(device,
+		 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
+		 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
+}
+
+/* A2XX GPU snapshot function - this is where all of the A2XX specific
+ * bits and pieces are grabbed into the snapshot memory
+ */
+
+void *a2xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
+	int *remain, int hang)
+{
+	struct kgsl_device *device = &adreno_dev->dev;
+	struct kgsl_snapshot_registers regs;
+	unsigned int pmoverride;
+
+	/* Choose the register set to dump */
+
+	if (adreno_is_a20x(adreno_dev)) {
+		regs.regs = (unsigned int *) a200_registers;
+		regs.count = a200_registers_count;
+	} else {
+		regs.regs = (unsigned int *) a220_registers;
+		regs.count = a220_registers_count;
+	}
+
+	/* Master set of (non debug) registers */
+	snapshot = kgsl_snapshot_add_section(device,
+		KGSL_SNAPSHOT_SECTION_REGS, snapshot, remain,
+		kgsl_snapshot_dump_regs, &regs);
+
+	/* CP_STATE_DEBUG indexed registers */
+	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_CP_STATE_DEBUG_INDEX,
+			REG_CP_STATE_DEBUG_DATA, 0x0, 0x14);
+
+	/* CP_ME indexed registers */
+	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_CP_ME_CNTL, REG_CP_ME_STATUS,
+			64, 44);
+
+	/*
+	 * Need to temporarily turn off clock gating for the debug bus to
+	 * work
+	 */
+
+	adreno_regread(device, REG_RBBM_PM_OVERRIDE2, &pmoverride);
+	adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, 0xFF);
+
+	/* SX debug registers */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_sxdebug, NULL);
+
+	/* SU debug indexed registers (only for < 470) */
+	if (!adreno_is_a22x(adreno_dev))
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+				remain, REG_PA_SU_DEBUG_CNTL,
+				REG_PA_SU_DEBUG_DATA,
+				0, 0x1B);
+
+	/* CP debug registers */
+	snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_cpdebug, NULL);
+
+	/* MH debug indexed registers */
+	snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, MH_DEBUG_CTRL, MH_DEBUG_DATA, 0x0, 0x40);
+
+	/* Leia only register sets */
+	if (adreno_is_a22x(adreno_dev)) {
+		/* RB DEBUG indexed regisers */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA, 0, 8);
+
+		/* RB DEBUG indexed registers bank 2 */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_RB_DEBUG_CNTL, REG_RB_DEBUG_DATA + 0x1000,
+			0, 8);
+
+		/* PC_DEBUG indexed registers */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_PC_DEBUG_CNTL, REG_PC_DEBUG_DATA, 0, 8);
+
+		/* GRAS_DEBUG indexed registers */
+		snapshot = a2xx_snapshot_indexed_registers(device, snapshot,
+			remain, REG_GRAS_DEBUG_CNTL, REG_GRAS_DEBUG_DATA, 0, 4);
+
+		/* MIU debug registers */
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_miudebug, NULL);
+
+		/* SQ DEBUG debug registers */
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+			a2xx_snapshot_sqdebug, NULL);
+
+		/*
+		 * Reading SQ THREAD causes bad things to happen on a running
+		 * system, so only read it if the GPU is already hung
+		 */
+
+		if (hang) {
+			/* SQ THREAD debug registers */
+			snapshot = kgsl_snapshot_add_section(device,
+				KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+				a2xx_snapshot_sqthreaddebug, NULL);
+		}
+	}
+
+	/* Reset the clock gating */
+	adreno_regwrite(device, REG_RBBM_PM_OVERRIDE2, pmoverride);
+
+	return snapshot;
+}
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
new file mode 100644
index 0000000..fb88a72
--- /dev/null
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -0,0 +1,332 @@
+/* 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.
+ */
+
+#include "kgsl.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_snapshot.h"
+
+#include "adreno.h"
+#include "adreno_pm4types.h"
+#include "a2xx_reg.h"
+
+/* Number of dwords of ringbuffer history to record */
+#define NUM_DWORDS_OF_RINGBUFFER_HISTORY 100
+
+/* Maintain a list of the objects we see during parsing */
+
+#define SNAPSHOT_OBJ_BUFSIZE 64
+
+#define SNAPSHOT_OBJ_TYPE_IB 0
+
+static struct kgsl_snapshot_obj {
+	int type;
+	uint32_t gpuaddr;
+	uint32_t ptbase;
+	void *ptr;
+	int dwords;
+} objbuf[SNAPSHOT_OBJ_BUFSIZE];
+
+/* Pointer to the next open entry in the object list */
+static int objbufptr;
+
+/* Push a new buffer object onto the list */
+static void push_object(struct kgsl_device *device, int type, uint32_t ptbase,
+	uint32_t gpuaddr, int dwords)
+{
+	int index;
+	void *ptr;
+
+	/* Go through the list and see that object has already been seen */
+	for (index = 0; index < objbufptr; index++) {
+		if (objbuf[index].gpuaddr == gpuaddr &&
+			objbuf[index].ptbase == ptbase)
+			return;
+	}
+
+	if (objbufptr == SNAPSHOT_OBJ_BUFSIZE) {
+		KGSL_DRV_ERR(device, "snapshot: too many snapshot objects\n");
+		return;
+	}
+
+	/*
+	 * adreno_convertaddr verifies that the IB size is valid - at least in
+	 * the context of it being smaller then the allocated memory space
+	 */
+	ptr = adreno_convertaddr(device, ptbase, gpuaddr, dwords << 2);
+
+	if (ptr == NULL) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Can't find GPU address for %x\n", gpuaddr);
+		return;
+	}
+
+	/* Put it on the list of things to parse */
+	objbuf[objbufptr].type = type;
+	objbuf[objbufptr].gpuaddr = gpuaddr;
+	objbuf[objbufptr].ptbase = ptbase;
+	objbuf[objbufptr].dwords = dwords;
+	objbuf[objbufptr++].ptr = ptr;
+}
+
+/* Snapshot the istore memory */
+static int snapshot_istore(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_istore *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	int count, i;
+
+	count = adreno_dev->istore_size * ADRENO_ISTORE_WORDS;
+
+	if (remain < (count * 4) + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the istore section");
+		return 0;
+	}
+
+	header->count = adreno_dev->istore_size;
+
+	for (i = 0; i < count; i++)
+		kgsl_regread(device, ADRENO_ISTORE_START + i, &data[i]);
+
+	return (count * 4) + sizeof(*header);
+}
+
+/* Snapshot the ringbuffer memory */
+static int snapshot_rb(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_rb *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+	struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+	unsigned int rbbase, ptbase, rptr, *rbptr;
+	int start, stop, index;
+	int numitems, size;
+
+	/* Get the GPU address of the ringbuffer */
+	kgsl_regread(device, REG_CP_RB_BASE, &rbbase);
+
+	/* Get the physical address of the MMU pagetable */
+	ptbase = kgsl_mmu_get_current_ptbase(device);
+
+	/* Get the current read pointers for the RB */
+	kgsl_regread(device, REG_CP_RB_RPTR, &rptr);
+
+	/* start the dump at the rptr minus some history */
+	start = (int) rptr - NUM_DWORDS_OF_RINGBUFFER_HISTORY;
+	if (start < 0)
+		start += rb->sizedwords;
+
+	/*
+	 * Stop the dump at the point where the software last wrote.  Don't use
+	 * the hardware value here on the chance that it didn't get properly
+	 * updated
+	 */
+
+	stop = (int) rb->wptr + 16;
+	if (stop > rb->sizedwords)
+		stop -= rb->sizedwords;
+
+	/* Set up the header for the section */
+
+	numitems = (stop > start) ? stop - start :
+		(rb->sizedwords - start) + stop;
+
+	size = (numitems << 2);
+
+	if (remain < size + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the rb section");
+		return 0;
+	}
+
+	/* Write the sub-header for the section */
+	header->start = start;
+	header->end = stop;
+	header->wptr = rb->wptr;
+	header->rbsize = rb->sizedwords;
+	header->count = numitems;
+
+	index = start;
+	rbptr = rb->buffer_desc.hostptr;
+
+	/*
+	 * Loop through the RB, copying the data and looking for indirect
+	 * buffers and MMU pagetable changes
+	 */
+
+	while (index != rb->wptr) {
+		*data = rbptr[index];
+
+		if (rbptr[index] == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2))
+			push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+				rbptr[index + 1], rbptr[index + 2]);
+
+		/*
+		 * FIXME: Handle upcoming MMU pagetable changes, but only
+		 * between the rptr and the wptr
+		 */
+
+		index = index + 1;
+
+		if (index == rb->sizedwords)
+			index = 0;
+
+		data++;
+	}
+
+	/* Dump 16 dwords past the wptr, but don't  bother interpeting it */
+
+	while (index != stop) {
+		*data = rbptr[index];
+		index = index + 1;
+
+		if (index == rb->sizedwords)
+			index = 0;
+
+		data++;
+	}
+
+	/* Return the size of the section */
+	return size + sizeof(*header);
+}
+
+/* Snapshot the memory for an indirect buffer */
+static int snapshot_ib(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_ib *header = snapshot;
+	struct kgsl_snapshot_obj *obj = priv;
+	unsigned int *src = obj->ptr;
+	unsigned int *dst = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < (obj->dwords << 2) + sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the ib section");
+		return 0;
+	}
+
+	/* Write the sub-header for the section */
+	header->gpuaddr = obj->gpuaddr;
+	header->ptbase = obj->ptbase;
+	header->size = obj->dwords;
+
+	/* Write the contents of the ib */
+	for (i = 0; i < obj->dwords; i++) {
+		*dst = *src;
+		/* If another IB is discovered, then push it on the list too */
+
+		if (*src == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+			push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
+				*(src + 1), *(src + 2));
+		}
+
+		src++;
+		dst++;
+	}
+
+	return (obj->dwords << 2) + sizeof(*header);
+}
+
+/* Dump another item on the current pending list */
+static void *dump_object(struct kgsl_device *device, int obj, void *snapshot,
+	int *remain)
+{
+	switch (objbuf[obj].type) {
+	case SNAPSHOT_OBJ_TYPE_IB:
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_IB, snapshot, remain,
+			snapshot_ib, &objbuf[obj]);
+		break;
+	default:
+		KGSL_DRV_ERR(device,
+			"snapshot: Invalid snapshot object type: %d\n",
+			objbuf[obj].type);
+		break;
+	}
+
+	return snapshot;
+}
+
+/* adreno_snapshot - Snapshot the Adreno GPU state
+ * @device - KGSL device to snapshot
+ * @snapshot - Pointer to the start of memory to write into
+ * @remain - A pointer to how many bytes of memory are remaining in the snapshot
+ * @hang - set if this snapshot was automatically triggered by a GPU hang
+ * This is a hook function called by kgsl_snapshot to snapshot the
+ * Adreno specific information for the GPU snapshot.  In turn, this function
+ * calls the GPU specific snapshot function to get core specific information.
+ */
+
+void *adreno_snapshot(struct kgsl_device *device, void *snapshot, int *remain,
+		int hang)
+{
+	int i;
+	uint32_t ptbase, ibbase, ibsize;
+	struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+	/* Reset the list of objects */
+	objbufptr = 0;
+
+	/* Get the physical address of the MMU pagetable */
+	ptbase = kgsl_mmu_get_current_ptbase(device);
+
+	/* Dump the ringbuffer */
+	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_RB,
+		snapshot, remain, snapshot_rb, NULL);
+
+	/*
+	 * Make sure that the IBs described in the CP registers are on the
+	 * list of objects
+	 */
+	kgsl_regread(device, REG_CP_IB1_BASE, &ibbase);
+	kgsl_regread(device, REG_CP_IB1_BUFSZ, &ibsize);
+
+	if (ibsize)
+		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+			ibbase, ibsize);
+
+	kgsl_regread(device, REG_CP_IB2_BASE, &ibbase);
+	kgsl_regread(device, REG_CP_IB2_BUFSZ, &ibsize);
+
+	if (ibsize)
+		push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
+			ibbase, ibsize);
+
+	/*
+	 * Go through the list of found objects and dump each one.  As the IBs
+	 * are parsed, more objects might be found, and objbufptr will increase
+	 */
+	for (i = 0; i < objbufptr; i++)
+		snapshot = dump_object(device, i, snapshot, remain);
+
+	/*
+	 * Only dump the istore on a hang - reading it on a running system
+	 * has a non 0 chance of hanging the GPU
+	 */
+
+	if (hang) {
+		snapshot = kgsl_snapshot_add_section(device,
+			KGSL_SNAPSHOT_SECTION_ISTORE, snapshot, remain,
+			snapshot_istore, NULL);
+	}
+
+	/* Add GPU specific sections - registers mainly, but other stuff too */
+	if (adreno_dev->gpudev->snapshot)
+		snapshot = adreno_dev->gpudev->snapshot(adreno_dev, snapshot,
+			remain, hang);
+
+	return snapshot;
+}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index c6e78dd..1b6696b 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2097,6 +2097,8 @@
 	if (minor == KGSL_DEVICE_MAX)
 		return;
 
+	kgsl_device_snapshot_close(device);
+
 	kgsl_cffdump_close(device->id);
 	kgsl_pwrctrl_uninit_sysfs(device);
 
@@ -2199,6 +2201,9 @@
 
 	idr_init(&device->context_idr);
 
+	/* Initalize the snapshot engine */
+	kgsl_device_snapshot_init(device);
+
 	/* sysfs and debugfs initalization - failure here is non fatal */
 
 	/* Initialize logging */
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index f82b038..8ea5279 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -90,6 +90,8 @@
 		struct kgsl_power_stats *stats);
 	void (*irqctrl)(struct kgsl_device *device, int state);
 	unsigned int (*gpuid)(struct kgsl_device *device);
+	void * (*snapshot)(struct kgsl_device *device, void *snapshot,
+		int *remain, int hang);
 	/* Optional functions - these functions are not mandatory.  The
 	   driver will check that the function pointer is not NULL before
 	   calling the hook */
@@ -164,6 +166,15 @@
 	struct idr context_idr;
 	struct early_suspend display_off;
 
+	void *snapshot;		/* Pointer to the snapshot memory region */
+	int snapshot_maxsize;   /* Max size of the snapshot region */
+	int snapshot_size;      /* Current size of the snapshot region */
+	u32 snapshot_timestamp;	/* Timestamp of the last valid snapshot */
+	int snapshot_frozen;	/* 1 if the snapshot output is frozen until
+				   it gets read by the user.  This avoids
+				   losing the output on multiple hangs  */
+	struct kobject snapshot_kobj;
+
 	/* Logging levels */
 	int cmd_log;
 	int ctxt_log;
@@ -320,4 +331,8 @@
 
 const char *kgsl_pwrstate_to_str(unsigned int state);
 
+int kgsl_device_snapshot_init(struct kgsl_device *device);
+int kgsl_device_snapshot(struct kgsl_device *device, int hang);
+void kgsl_device_snapshot_close(struct kgsl_device *device);
+
 #endif  /* __KGSL_DEVICE_H */
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
new file mode 100644
index 0000000..72df148b
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -0,0 +1,484 @@
+/* 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.
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/time.h>
+#include <linux/sysfs.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <linux/idr.h>
+
+#include "kgsl.h"
+#include "kgsl_log.h"
+#include "kgsl_device.h"
+#include "kgsl_sharedmem.h"
+#include "kgsl_snapshot.h"
+
+/* idr_for_each function to count the number of contexts */
+
+static int snapshot_context_count(int id, void *ptr, void *data)
+{
+	int *count = data;
+	*count = *count + 1;
+
+	return 0;
+}
+
+/*
+ * To simplify the iterator loop use a global pointer instead of trying
+ * to pass around double star references to the snapshot data
+ */
+
+static void *_ctxtptr;
+
+static int snapshot_context_info(int id, void *ptr, void *data)
+{
+	struct kgsl_snapshot_linux_context *header = _ctxtptr;
+	struct kgsl_context *context = ptr;
+	struct kgsl_device *device = context->dev_priv->device;
+
+	header->id = id;
+
+	/* Future-proof for per-context timestamps - for now, just
+	 * return the global timestamp for all contexts
+	 */
+
+	header->timestamp_queued = -1;
+	header->timestamp_retired = device->ftbl->readtimestamp(device,
+		KGSL_TIMESTAMP_RETIRED);
+
+	_ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
+
+	return 0;
+}
+
+/* Snapshot the Linux specific information */
+static int snapshot_os(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_linux *header = snapshot;
+	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
+	struct task_struct *task;
+	pid_t pid;
+	int hang = (int) priv;
+	int ctxtcount = 0;
+	int size = sizeof(*header);
+
+	/* Figure out how many active contexts there are - these will
+	 * be appended on the end of the structure */
+
+	idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
+
+	size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
+
+	/* Make sure there is enough room for the data */
+	if (remain < size) {
+		SNAPSHOT_ERR_NOMEM(device, "OS");
+		return 0;
+	}
+
+	memset(header, 0, sizeof(*header));
+
+	header->osid = KGSL_SNAPSHOT_OS_LINUX;
+
+	header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
+
+	/* Get the kernel build information */
+	strlcpy(header->release, utsname()->release, sizeof(header->release));
+	strlcpy(header->version, utsname()->version, sizeof(header->version));
+
+	/* Get the Unix time for the timestamp */
+	header->seconds = get_seconds();
+
+	/* Remember the power information */
+	header->power_flags = pwr->power_flags;
+	header->power_level = pwr->active_pwrlevel;
+	header->power_interval_timeout = pwr->interval_timeout;
+	header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
+	header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
+
+	/* Future proof for per-context timestamps */
+	header->current_context = -1;
+
+	/* Get the current PT base */
+	header->ptbase = kgsl_mmu_get_current_ptbase(device);
+	/* And the PID for the task leader */
+	pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
+
+	task = find_task_by_vpid(pid);
+
+	if (task)
+		get_task_comm(header->comm, task);
+
+	header->ctxtcount = ctxtcount;
+
+	/* append information for each context */
+	_ctxtptr = snapshot + sizeof(*header);
+	idr_for_each(&device->context_idr, snapshot_context_info, NULL);
+
+	/* Return the size of the data segment */
+	return size;
+}
+/*
+ * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
+ * @device - the device to dump registers from
+ * @snapshot - pointer to the start of the region of memory for the snapshot
+ * @remain - a pointer to the number of bytes remaining in the snapshot
+ * @priv - A pointer to the kgsl_snapshot_indexed_registers data
+ *
+ * Given a indexed register cmd/data pair and a count, dump each indexed
+ * register
+ */
+
+int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv)
+{
+	struct kgsl_snapshot_indexed_registers *iregs = priv;
+	struct kgsl_snapshot_indexed_regs *header = snapshot;
+	unsigned int *data = snapshot + sizeof(*header);
+	int i;
+
+	if (remain < (iregs->count * 4) + sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
+		return 0;
+	}
+
+	header->index_reg = iregs->index;
+	header->data_reg = iregs->data;
+	header->count = iregs->count;
+	header->start = iregs->start;
+
+	for (i = 0; i < iregs->count; i++) {
+		kgsl_regwrite(device, iregs->index, iregs->start + i);
+		kgsl_regread(device, iregs->data, &data[i]);
+	}
+
+	return (iregs->count * 4) + sizeof(*header);
+}
+EXPORT_SYMBOL(kgsl_snapshot_dump_indexed_regs);
+
+/*
+ * kgsl_snapshot_dump_regs - helper function to dump device registers
+ * @device - the device to dump registers from
+ * @snapshot - pointer to the start of the region of memory for the snapshot
+ * @remain - a pointer to the number of bytes remaining in the snapshot
+ * @priv - A pointer to the kgsl_snapshot_registers data
+ *
+ * Given an array of register ranges pairs (start,end [inclusive]), dump the
+ * registers into a snapshot register section.  The snapshot region stores a
+ * part of dwords for each register - the word address of the register, and
+ * the value.
+ */
+int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv)
+{
+	struct kgsl_snapshot_regs *header = snapshot;
+	struct kgsl_snapshot_registers *regs = priv;
+	unsigned int *data = snapshot + sizeof(*header);
+	int count = 0, i, j;
+
+	/* Figure out how many registers we are going to dump */
+
+	for (i = 0; i < regs->count; i++) {
+		int start = regs->regs[i * 2];
+		int end = regs->regs[i * 2 + 1];
+
+		count += (end - start + 1);
+	}
+
+	if (remain < (count * 8) + sizeof(*header)) {
+		SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
+		return 0;
+	}
+
+	for (i = 0; i < regs->count; i++) {
+		unsigned int start = regs->regs[i * 2];
+		unsigned int end = regs->regs[i * 2 + 1];
+
+		for (j = start; j <= end; j++) {
+			unsigned int val;
+
+			kgsl_regread(device, j, &val);
+			*data++ = j;
+			*data++ = val;
+		}
+	}
+
+	header->count = count;
+
+	/* Return the size of the section */
+	return (count * 8) + sizeof(*header);
+}
+EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
+
+/*
+ * kgsl_snapshot - construct a device snapshot
+ * @device - device to snapshot
+ * @hang - set to 1 if the snapshot was triggered following a hnag
+ * Given a device, construct a binary snapshot dump of the current device state
+ * and store it in the device snapshot memory.
+ */
+int kgsl_device_snapshot(struct kgsl_device *device, int hang)
+{
+	struct kgsl_snapshot_header *header = device->snapshot;
+	int remain = device->snapshot_maxsize - sizeof(*header);
+	void *snapshot;
+
+	/*
+	 * The first hang is always the one we are interested in. To
+	 * avoid a subsequent hang blowing away the first, the snapshot
+	 * is frozen until it is dumped via sysfs.
+	 *
+	 * Note that triggered snapshots are always taken regardless
+	 * of the state and never frozen.
+	 */
+
+	if (hang && device->snapshot_frozen == 1)
+		return 0;
+
+	if (device->snapshot == NULL) {
+		KGSL_DRV_ERR(device,
+			"snapshot: No snapshot memory available\n");
+		return -ENOMEM;
+	}
+
+	if (remain < sizeof(*header)) {
+		KGSL_DRV_ERR(device,
+			"snapshot: Not enough memory for the header\n");
+		return -ENOMEM;
+	}
+
+	header->magic = SNAPSHOT_MAGIC;
+
+	header->gpuid = kgsl_gpuid(device);
+
+	/* Get a pointer to the first section (right after the header) */
+	snapshot = ((void *) device->snapshot) + sizeof(*header);
+
+	/* Build the Linux specific header */
+	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
+		snapshot, &remain, snapshot_os, (void *) hang);
+
+	/* Get the device specific sections */
+	if (device->ftbl->snapshot)
+		snapshot = device->ftbl->snapshot(device, snapshot, &remain,
+			hang);
+
+	/* Add the empty end section to let the parser know we are done */
+	snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_END,
+		snapshot, &remain, NULL, NULL);
+
+	device->snapshot_timestamp = get_seconds();
+	device->snapshot_size = (int) (snapshot - device->snapshot);
+
+	/* Freeze the snapshot on a hang until it gets read */
+	device->snapshot_frozen = (hang) ? 1 : 0;
+
+	return 0;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot);
+
+/* An attribute for showing snapshot details */
+struct kgsl_snapshot_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct kgsl_device *device, char *buf);
+	ssize_t (*store)(struct kgsl_device *device, const char *buf,
+		size_t count);
+};
+
+#define to_snapshot_attr(a) \
+container_of(a, struct kgsl_snapshot_attribute, attr)
+
+#define kobj_to_device(a) \
+container_of(a, struct kgsl_device, snapshot_kobj)
+
+/* Dump the sysfs binary data to the user */
+static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t off,
+	size_t count)
+{
+	struct kgsl_device *device = kobj_to_device(kobj);
+
+	if (device == NULL)
+		return 0;
+
+	/* Return nothing if we haven't taken a snapshot yet */
+	if (device->snapshot_timestamp == 0)
+		return 0;
+
+	/* Get the mutex to keep things from changing while we are dumping */
+	mutex_lock(&device->mutex);
+
+	/*
+	 * Release the freeze on the snapshot the first time the buffer is read
+	 */
+
+	device->snapshot_frozen = 0;
+
+	if (off >= device->snapshot_size) {
+		count = 0;
+		goto exit;
+	}
+
+	if (off + count > device->snapshot_size)
+		count = device->snapshot_size - off;
+
+	memcpy(buf, device->snapshot + off, count);
+
+exit:
+	mutex_unlock(&device->mutex);
+	return count;
+}
+
+/* Show the timestamp of the last collected snapshot */
+static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
+}
+
+/* manually trigger a new snapshot to be collected */
+static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
+	size_t count)
+{
+	if (device && count > 0) {
+		mutex_lock(&device->mutex);
+		kgsl_device_snapshot(device, 0);
+		mutex_unlock(&device->mutex);
+	}
+
+	return count;
+}
+
+static struct bin_attribute snapshot_attr = {
+	.attr.name = "dump",
+	.attr.mode = 0444,
+	.size = 0,
+	.read = snapshot_show
+};
+
+#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
+struct kgsl_snapshot_attribute attr_##_name = { \
+	.attr = { .name = __stringify(_name), .mode = _mode }, \
+	.show = _show, \
+	.store = _store, \
+}
+
+SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
+SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
+
+static void snapshot_sysfs_release(struct kobject *kobj)
+{
+}
+
+static ssize_t snapshot_sysfs_show(struct kobject *kobj,
+	struct attribute *attr, char *buf)
+{
+	struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
+	struct kgsl_device *device = kobj_to_device(kobj);
+	ssize_t ret;
+
+	if (device && pattr->show)
+		ret = pattr->show(device, buf);
+	else
+		ret = -EIO;
+
+	return ret;
+}
+
+static ssize_t snapshot_sysfs_store(struct kobject *kobj,
+	struct attribute *attr, const char *buf, size_t count)
+{
+	struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
+	struct kgsl_device *device = kobj_to_device(kobj);
+	ssize_t ret;
+
+	if (device && pattr->store)
+		ret = pattr->store(device, buf, count);
+	else
+		ret = -EIO;
+
+	return ret;
+}
+
+static const struct sysfs_ops snapshot_sysfs_ops = {
+	.show = snapshot_sysfs_show,
+	.store = snapshot_sysfs_store,
+};
+
+static struct kobj_type ktype_snapshot = {
+	.sysfs_ops = &snapshot_sysfs_ops,
+	.default_attrs = NULL,
+	.release = snapshot_sysfs_release,
+};
+
+/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
+ * @device - The device to initalize
+ *
+ * Allocate memory for a GPU snapshot for the specified device,
+ * and create the sysfs files to manage it
+ */
+
+int kgsl_device_snapshot_init(struct kgsl_device *device)
+{
+	int ret;
+
+	if (device->snapshot == NULL)
+		device->snapshot = vmalloc(KGSL_SNAPSHOT_MEMSIZE);
+
+	if (device->snapshot == NULL)
+		return -ENOMEM;
+
+	device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
+	device->snapshot_timestamp = 0;
+
+	ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
+		&device->dev->kobj, "snapshot");
+	if (ret)
+		goto done;
+
+	ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
+	if (ret)
+		goto done;
+
+	ret  = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
+	if (ret)
+		goto done;
+
+	ret  = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
+
+done:
+	return ret;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot_init);
+
+/* kgsl_device_snapshot_close - Take down snapshot memory for a device
+ * @device - Pointer to the kgsl_device
+ *
+ * Remove the sysfs files and free the memory allocated for the GPU
+ * snapshot
+ */
+
+void kgsl_device_snapshot_close(struct kgsl_device *device)
+{
+	sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
+	sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
+	sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
+
+	kobject_put(&device->snapshot_kobj);
+
+	vfree(device->snapshot);
+
+	device->snapshot = NULL;
+	device->snapshot_maxsize = 0;
+	device->snapshot_timestamp = 0;
+}
+EXPORT_SYMBOL(kgsl_device_snapshot_close);
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
new file mode 100644
index 0000000..4fdc8a1
--- /dev/null
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -0,0 +1,259 @@
+/* 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 _KGSL_SNAPSHOT_H_
+#define _KGSL_SNAPSHOT_H_
+
+#include <linux/types.h>
+
+/* Snapshot header */
+
+#define SNAPSHOT_MAGIC 0x504D0001
+
+/* GPU ID scheme:
+ * [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D)
+ * [00:16] - GPU specific identifier
+ */
+
+struct kgsl_snapshot_header {
+	__u32 magic; /* Magic identifier */
+	__u32 gpuid; /* GPU ID - see above */
+} __packed;
+
+/* Section header */
+#define SNAPSHOT_SECTION_MAGIC 0xABCD
+
+struct kgsl_snapshot_section_header {
+	__u16 magic; /* Magic identifier */
+	__u16 id;    /* Type of section */
+	__u32 size;  /* Size of the section including this header */
+} __packed;
+
+/* Section identifiers */
+#define KGSL_SNAPSHOT_SECTION_OS           0x0101
+#define KGSL_SNAPSHOT_SECTION_REGS         0x0201
+#define KGSL_SNAPSHOT_SECTION_RB           0x0301
+#define KGSL_SNAPSHOT_SECTION_IB           0x0401
+#define KGSL_SNAPSHOT_SECTION_INDEXED_REGS 0x0501
+#define KGSL_SNAPSHOT_SECTION_ISTORE       0x0801
+#define KGSL_SNAPSHOT_SECTION_DEBUG        0x0901
+#define KGSL_SNAPSHOT_SECTION_END          0xFFFF
+
+/* OS sub-section header */
+#define KGSL_SNAPSHOT_OS_LINUX             0x0001
+
+/* Linux OS specific information */
+
+#define SNAPSHOT_STATE_HUNG 0
+#define SNAPSHOT_STATE_RUNNING 1
+
+struct kgsl_snapshot_linux {
+	int osid;                   /* subsection OS identifier */
+	int state;		    /* 1 if the thread is running, 0 for hung */
+	__u32 seconds;		    /* Unix timestamp for the snapshot */
+	__u32 power_flags;            /* Current power flags */
+	__u32 power_level;            /* Current power level */
+	__u32 power_interval_timeout; /* Power interval timeout */
+	__u32 grpclk;                 /* Current GP clock value */
+	__u32 busclk;		    /* Current busclk value */
+	__u32 ptbase;		    /* Current ptbase */
+	__u32 pid;		    /* PID of the process that owns the PT */
+	__u32 current_context;	    /* ID of the current context */
+	__u32 ctxtcount;	    /* Number of contexts appended to section */
+	unsigned char release[32];  /* kernel release */
+	unsigned char version[32];  /* kernel version */
+	unsigned char comm[16];	    /* Name of the process that owns the PT */
+} __packed;
+
+/*
+ * This structure contains a record of an active context.
+ * These are appended one after another in the OS section below
+ * the header above
+ */
+
+struct kgsl_snapshot_linux_context {
+	__u32 id;			/* The context ID */
+	__u32 timestamp_queued;		/* The last queued timestamp */
+	__u32 timestamp_retired;	/* The last timestamp retired by HW */
+};
+
+/* Ringbuffer sub-section header */
+struct kgsl_snapshot_rb {
+	int start;  /* dword at the start of the dump */
+	int end;    /* dword at the end of the dump */
+	int rbsize; /* Size (in dwords) of the ringbuffer */
+	int wptr;   /* Current index of the CPU write pointer */
+	int rptr;   /* Current index of the GPU read pointer */
+	int count;  /* Number of dwords in the dump */
+} __packed;
+
+/* Indirect buffer sub-section header */
+struct kgsl_snapshot_ib {
+	__u32 gpuaddr; /* GPU address of the the IB */
+	__u32 ptbase;  /* Base for the pagetable the GPU address is valid in */
+	int size;    /* Size of the IB */
+} __packed;
+
+/* Register sub-section header */
+struct kgsl_snapshot_regs {
+	__u32 count; /* Number of register pairs in the section */
+} __packed;
+
+/* Indexed register sub-section header */
+struct kgsl_snapshot_indexed_regs {
+	__u32 index_reg; /* Offset of the index register for this section */
+	__u32 data_reg;  /* Offset of the data register for this section */
+	int start;     /* Starting index */
+	int count;     /* Number of dwords in the data */
+} __packed;
+
+/* Istore sub-section header */
+struct kgsl_snapshot_istore {
+	int count;   /* Number of instructions in the istore */
+} __packed;
+
+/* Debug data sub-section header */
+
+#define SNAPSHOT_DEBUG_SX         1
+#define SNAPSHOT_DEBUG_CP         2
+#define SNAPSHOT_DEBUG_SQ         3
+#define SNAPSHOT_DEBUG_SQTHREAD   4
+#define SNAPSHOT_DEBUG_MIU        5
+
+struct kgsl_snapshot_debug {
+	int type;    /* Type identifier for the attached tata */
+	int size;   /* Size of the section in bytes */
+} __packed;
+
+#ifdef __KERNEL__
+
+/* Allocate 512K for each device snapshot */
+#define KGSL_SNAPSHOT_MEMSIZE (512 * 1024)
+
+struct kgsl_device;
+/*
+ * A helper macro to print out "not enough memory functions" - this
+ * makes it easy to standardize the messages as well as cut down on
+ * the number of strings in the binary
+ */
+
+#define SNAPSHOT_ERR_NOMEM(_d, _s) \
+	KGSL_DRV_ERR((_d), \
+	"snapshot: not enough snapshot memory for section %s\n", (_s))
+
+/*
+ * kgsl_snapshot_add_section - Add a new section to the GPU snapshot
+ * @device - the KGSL device being snapshotted
+ * @id - the section id
+ * @snapshot - pointer to the memory for the snapshot
+ * @remain - pointer to the number of bytes left in the snapshot region
+ * @func - Function pointer to fill the section
+ * @priv - Priv pointer to pass to the function
+ *
+ * Set up a KGSL snapshot header by filling the memory with the callback
+ * function and adding the standard section header
+ */
+
+static inline void *kgsl_snapshot_add_section(struct kgsl_device *device,
+	u16 id, void *snapshot, int *remain,
+	int (*func)(struct kgsl_device *, void *, int, void *), void *priv)
+{
+	struct kgsl_snapshot_section_header *header = snapshot;
+	void *data = snapshot + sizeof(*header);
+	int ret = 0;
+
+	/*
+	 * Sanity check to make sure there is enough for the header.  The
+	 * callback will check to make sure there is enough for the rest
+	 * of the data.  If there isn't enough room then don't advance the
+	 * pointer.
+	 */
+
+	if (*remain < sizeof(*header))
+		return snapshot;
+
+	/* It is legal to have no function (i.e. - make an empty section) */
+
+	if (func) {
+		ret = func(device, data, *remain, priv);
+
+		/*
+		 * If there wasn't enough room for the data then don't bother
+		 * setting up the header.
+		 */
+
+		if (ret == 0)
+			return snapshot;
+	}
+
+	header->magic = SNAPSHOT_SECTION_MAGIC;
+	header->id = id;
+	header->size = ret + sizeof(*header);
+
+	/* Decrement the room left in the snapshot region */
+	*remain -= header->size;
+	/* Advance the pointer to the end of the next function */
+	return snapshot + header->size;
+}
+
+/* A common helper function to dump a range of registers.  This will be used in
+ * the GPU specific devices like this:
+ *
+ * struct kgsl_snapshot_registers priv;
+ * priv.regs = registers_array;;
+ * priv.count = num_registers;
+ *
+ * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_REGS, snapshot,
+ *	remain, kgsl_snapshot_dump_regs, &priv).
+ *
+ * Pass in an array of register range pairs in the form of:
+ * start reg, stop reg
+ * All the registers between start and stop inclusive will be dumped
+ */
+
+struct kgsl_snapshot_registers {
+	unsigned int *regs;  /* Pointer to the array of register ranges */
+	int count;	     /* Number of entries in the array */
+};
+
+int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
+	int remain, void *priv);
+
+/*
+ * A common helper function to dump a set of indexed registers. Use it
+ * like this:
+ *
+ * struct kgsl_snapshot_indexed_registers priv;
+ * priv.index = REG_INDEX;
+ * priv.data = REG_DATA;
+ * priv.count = num_registers
+ *
+ * kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_INDEXED_REGS,
+ *	snapshot, remain, kgsl_snapshot_dump_indexed_regs, &priv).
+ *
+ * The callback function will write an index from 0 to priv.count to
+ * the index register and read the data from the data register.
+ */
+
+struct kgsl_snapshot_indexed_registers {
+	unsigned int index; /* Offset of the index register */
+	unsigned int data;  /* Offset of the data register */
+	unsigned int start;	/* Index to start with */
+	unsigned int count; /* Number of values to read from the pair */
+};
+
+int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
+	void *snapshot, int remain, void *priv);
+
+#endif
+#endif
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 57d34b9..5f8faee 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.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
@@ -145,7 +145,7 @@
 	struct wake_lock			adc_wakelock;
 	int					msm_suspend_check;
 	struct pm8xxx_adc_amux_properties	*conv;
-	struct pm8xxx_adc_arb_btm_param		batt[0];
+	struct pm8xxx_adc_arb_btm_param		batt;
 	struct sensor_device_attribute		sens_attr[0];
 };
 
@@ -451,8 +451,8 @@
 
 	spin_lock_irqsave(&adc_pmic->btm_lock, flags);
 	warm_status = irq_read_line(adc_pmic->btm_warm_irq);
-	if (adc_pmic->batt->btm_warm_fn != NULL)
-		adc_pmic->batt->btm_warm_fn(warm_status);
+	if (adc_pmic->batt.btm_warm_fn != NULL)
+		adc_pmic->batt.btm_warm_fn(warm_status);
 	spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
 }
 
@@ -465,8 +465,8 @@
 
 	spin_lock_irqsave(&adc_pmic->btm_lock, flags);
 	cool_status = irq_read_line(adc_pmic->btm_cool_irq);
-	if (adc_pmic->batt->btm_cool_fn != NULL)
-		adc_pmic->batt->btm_cool_fn(cool_status);
+	if (adc_pmic->batt.btm_cool_fn != NULL)
+		adc_pmic->batt.btm_cool_fn(cool_status);
 	spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
 }
 
@@ -860,7 +860,7 @@
 		if (rc < 0)
 			goto write_err;
 
-		adc_pmic->batt->btm_cool_fn = btm_param->btm_cool_fn;
+		adc_pmic->batt.btm_cool_fn = btm_param->btm_cool_fn;
 	}
 
 	if (btm_param->btm_warm_fn != NULL) {
@@ -874,7 +874,7 @@
 		if (rc < 0)
 			goto write_err;
 
-		adc_pmic->batt->btm_warm_fn = btm_param->btm_warm_fn;
+		adc_pmic->batt.btm_warm_fn = btm_param->btm_warm_fn;
 	}
 
 	rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, &arb_btm_cntrl1);
@@ -952,10 +952,10 @@
 	if (rc < 0)
 		goto write_err;
 
-	if (pmic_adc->batt->btm_warm_fn != NULL)
+	if (pmic_adc->batt.btm_warm_fn != NULL)
 		enable_irq(adc_pmic->btm_warm_irq);
 
-	if (pmic_adc->batt->btm_cool_fn != NULL)
+	if (pmic_adc->batt.btm_cool_fn != NULL)
 		enable_irq(adc_pmic->btm_cool_irq);
 
 write_err:
@@ -1159,7 +1159,6 @@
 	}
 
 	adc_pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8xxx_adc) +
-			sizeof(struct pm8xxx_adc_arb_btm_param) +
 			(sizeof(struct sensor_device_attribute) *
 			pdata->adc_num_board_channel), GFP_KERNEL);
 	if (!adc_pmic) {
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 2d69256..f99a546 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-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
@@ -308,12 +308,12 @@
 {
 	dev->clk_state = state;
 	if (state != 0) {
-		clk_enable(dev->clk);
-		clk_enable(dev->pclk);
+		clk_prepare_enable(dev->clk);
+		clk_prepare_enable(dev->pclk);
 	} else {
 		qup_update_state(dev, QUP_RESET_STATE);
-		clk_disable(dev->clk);
-		clk_disable(dev->pclk);
+		clk_disable_unprepare(dev->clk);
+		clk_disable_unprepare(dev->pclk);
 	}
 }
 
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 2453b6b..71bdcde 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -22,6 +22,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/regulator/consumer.h>
 
 #if defined(CONFIG_HAS_EARLYSUSPEND)
@@ -80,6 +82,7 @@
 #define MXT_PROCI_PALM_T41		41
 #define MXT_PROCI_TOUCHSUPPRESSION_T42	42
 #define MXT_PROCI_STYLUS_T47		47
+#define MXT_PROCI_SHIELDLESS_T56	56
 #define MXT_PROCG_NOISESUPPRESSION_T48	48
 #define MXT_SPT_COMMSCONFIG_T18		18
 #define MXT_SPT_GPIOPWM_T19		19
@@ -206,11 +209,11 @@
 #define MXT_BOOT_VALUE		0xa5
 #define MXT_BACKUP_VALUE	0x55
 #define MXT_BACKUP_TIME		25	/* msec */
-#define MXT224_RESET_TIME		65	/* msec */
-#define MXT224E_RESET_TIME		22	/* msec */
-#define MXT1386_RESET_TIME		250	/* msec */
+#define MXT224_RESET_TIME	65	/* msec */
+#define MXT224E_RESET_TIME	22	/* msec */
+#define MXT1386_RESET_TIME	250	/* msec */
 #define MXT_RESET_TIME		250	/* msec */
-#define MXT_RESET_NOCHGREAD		400	/* msec */
+#define MXT_RESET_NOCHGREAD	400	/* msec */
 
 #define MXT_FWRESET_TIME	175	/* msec */
 
@@ -252,6 +255,9 @@
 #define MXT_MAX_RW_TRIES	3
 #define MXT_BLOCK_SIZE		256
 
+#define MXT_DEBUGFS_DIR		"atmel_mxt_ts"
+#define MXT_DEBUGFS_FILE	"object"
+
 struct mxt_info {
 	u8 family_id;
 	u8 variant_id;
@@ -292,6 +298,7 @@
 	struct i2c_client *client;
 	struct input_dev *input_dev;
 	const struct mxt_platform_data *pdata;
+	const struct mxt_config_info *config_info;
 	struct mxt_object *object_table;
 	struct mxt_info info;
 	struct mxt_finger finger[MXT_MAX_FINGER];
@@ -312,8 +319,12 @@
 	u8 t9_min_reportid;
 	u8 t15_max_reportid;
 	u8 t15_min_reportid;
+	u8 curr_cfg_version;
+	int cfg_version_idx;
 };
 
+static struct dentry *debug_base;
+
 static bool mxt_object_readable(unsigned int type)
 {
 	switch (type) {
@@ -334,6 +345,7 @@
 	case MXT_PROCI_PALM_T41:
 	case MXT_PROCI_TOUCHSUPPRESSION_T42:
 	case MXT_PROCI_STYLUS_T47:
+	case MXT_PROCI_SHIELDLESS_T56:
 	case MXT_PROCG_NOISESUPPRESSION_T48:
 	case MXT_SPT_COMMSCONFIG_T18:
 	case MXT_SPT_GPIOPWM_T19:
@@ -366,6 +378,7 @@
 	case MXT_PROCI_PALM_T41:
 	case MXT_PROCI_TOUCHSUPPRESSION_T42:
 	case MXT_PROCI_STYLUS_T47:
+	case MXT_PROCI_SHIELDLESS_T56:
 	case MXT_PROCG_NOISESUPPRESSION_T48:
 	case MXT_SPT_COMMSCONFIG_T18:
 	case MXT_SPT_GPIOPWM_T19:
@@ -750,13 +763,13 @@
 
 static int mxt_check_reg_init(struct mxt_data *data)
 {
-	const struct mxt_platform_data *pdata = data->pdata;
+	const struct mxt_config_info *config_info = data->config_info;
 	struct mxt_object *object;
 	struct device *dev = &data->client->dev;
 	int index = 0;
 	int i, j, config_offset;
 
-	if (!pdata->config) {
+	if (!config_info) {
 		dev_dbg(dev, "No cfg data defined, skipping reg init\n");
 		return 0;
 	}
@@ -769,12 +782,12 @@
 
 		for (j = 0; j < object->size + 1; j++) {
 			config_offset = index + j;
-			if (config_offset > pdata->config_length) {
+			if (config_offset > config_info->config_length) {
 				dev_err(dev, "Not enough config data!\n");
 				return -EINVAL;
 			}
 			mxt_write_object(data, object->type, j,
-					 pdata->config[config_offset]);
+					 config_info->config[config_offset]);
 		}
 		index += object->size + 1;
 	}
@@ -846,6 +859,7 @@
 	u16 reg;
 	u8 reportid = 0;
 	u8 buf[MXT_OBJECT_SIZE];
+	bool found_t38 = false;
 
 	for (i = 0; i < data->info.object_num; i++) {
 		struct mxt_object *object = data->object_table + i;
@@ -866,11 +880,94 @@
 					(object->instances + 1);
 			object->max_reportid = reportid;
 		}
+
+		/* Calculate index for config major version in config array.
+		 * Major version is the first byte in object T38.
+		 */
+		if (object->type == MXT_SPT_USERDATA_T38)
+			found_t38 = true;
+		if (!found_t38 && mxt_object_writable(object->type))
+			data->cfg_version_idx += object->size + 1;
 	}
 
 	return 0;
 }
 
+static int mxt_search_config_array(struct mxt_data *data, bool version_match)
+{
+
+	const struct mxt_platform_data *pdata = data->pdata;
+	const struct mxt_config_info *cfg_info;
+	struct mxt_info *info = &data->info;
+	int i;
+	u8 cfg_version;
+
+	for (i = 0; i < pdata->config_array_size; i++) {
+
+		cfg_info = &pdata->config_array[i];
+
+		if (!cfg_info->config || !cfg_info->config_length)
+			continue;
+
+		if (info->family_id == cfg_info->family_id &&
+			info->variant_id == cfg_info->variant_id &&
+			info->version == cfg_info->version &&
+			info->build == cfg_info->build) {
+
+			cfg_version = cfg_info->config[data->cfg_version_idx];
+			if (data->curr_cfg_version == cfg_version ||
+				!version_match) {
+				data->config_info = cfg_info;
+				return 0;
+			}
+		}
+	}
+
+	dev_info(&data->client->dev,
+		"Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
+		info->family_id, info->variant_id,
+		info->version >> 4, info->version & 0xF, info->build,
+		data->curr_cfg_version);
+	return -EINVAL;
+}
+
+static int mxt_get_config(struct mxt_data *data)
+{
+	const struct mxt_platform_data *pdata = data->pdata;
+	struct device *dev = &data->client->dev;
+	struct mxt_object *object;
+	int error;
+
+	if (!pdata->config_array || !pdata->config_array_size) {
+		dev_dbg(dev, "No cfg data provided by platform data\n");
+		return 0;
+	}
+
+	/* Get current config version */
+	object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
+	if (!object) {
+		dev_err(dev, "Unable to obtain USERDATA object\n");
+		return -EINVAL;
+	}
+
+	error = mxt_read_reg(data->client, object->start_address,
+				&data->curr_cfg_version);
+	if (error) {
+		dev_err(dev, "Unable to read config version\n");
+		return error;
+	}
+
+	/* It is possible that the config data on the controller is not
+	 * versioned and the version number returns 0. In this case,
+	 * find a match without the config version checking.
+	 */
+	error = mxt_search_config_array(data,
+				data->curr_cfg_version != 0 ? true : false);
+	if (error)
+		return error;
+
+	return 0;
+}
 static void mxt_reset_delay(struct mxt_data *data)
 {
 	struct mxt_info *info = &data->info;
@@ -919,6 +1016,11 @@
 	if (error)
 		goto free_object_table;
 
+	/* Get config data from platform data */
+	error = mxt_get_config(data);
+	if (error)
+		dev_dbg(&client->dev, "Config info not found.\n");
+
 	/* Check register init values */
 	error = mxt_check_reg_init(data);
 	if (error)
@@ -1622,6 +1724,72 @@
 };
 #endif
 
+static int mxt_debugfs_object_show(struct seq_file *m, void *v)
+{
+	struct mxt_data *data = m->private;
+	struct mxt_object *object;
+	struct device *dev = &data->client->dev;
+	int i, j, k;
+	int error;
+	int obj_size;
+	u8 val;
+
+	for (i = 0; i < data->info.object_num; i++) {
+		object = data->object_table + i;
+		obj_size = object->size + 1;
+
+		seq_printf(m, "Object[%d] (Type %d)\n", i + 1, object->type);
+
+		for (j = 0; j < object->instances + 1; j++) {
+			seq_printf(m, "[Instance %d]\n", j);
+
+			for (k = 0; k < obj_size; k++) {
+				error = mxt_read_object(data, object->type,
+							j * obj_size + k, &val);
+				if (error) {
+					dev_err(dev,
+						"Failed to read object %d "
+						"instance %d at offset %d\n",
+						object->type, j, k);
+					return error;
+				}
+
+				seq_printf(m, "Byte %d: 0x%02x (%d)\n",
+						k, val, val);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int mxt_debugfs_object_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, mxt_debugfs_object_show, inode->i_private);
+}
+
+static const struct file_operations mxt_object_fops = {
+	.owner		= THIS_MODULE,
+	.open		= mxt_debugfs_object_open,
+	.read		= seq_read,
+	.release	= single_release,
+};
+
+static void __init mxt_debugfs_init(struct mxt_data *data)
+{
+	debug_base = debugfs_create_dir(MXT_DEBUGFS_DIR, NULL);
+	if (IS_ERR_OR_NULL(debug_base))
+		pr_err("atmel_mxt_ts: Failed to create debugfs dir\n");
+	if (IS_ERR_OR_NULL(debugfs_create_file(MXT_DEBUGFS_FILE,
+					       0444,
+					       debug_base,
+					       data,
+					       &mxt_object_fops))) {
+		pr_err("atmel_mxt_ts: Failed to create object file\n");
+		debugfs_remove_recursive(debug_base);
+	}
+}
+
 static int __devinit mxt_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
@@ -1773,6 +1941,8 @@
 	register_early_suspend(&data->early_suspend);
 #endif
 
+	mxt_debugfs_init(data);
+
 	return 0;
 
 err_unregister_device:
@@ -1834,6 +2004,8 @@
 	kfree(data->object_table);
 	kfree(data);
 
+	debugfs_remove_recursive(debug_base);
+
 	return 0;
 }
 
diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
index bb02be6..a60dbf5 100644
--- a/drivers/input/touchscreen/cyttsp-i2c.c
+++ b/drivers/input/touchscreen/cyttsp-i2c.c
@@ -2407,27 +2407,29 @@
 				regulator_put(ts->vdd[i]);
 				goto error_vdd;
 			}
-		}
 
-		rc = regulator_set_optimum_mode(ts->vdd[i],
+			rc = regulator_set_optimum_mode(ts->vdd[i],
 						reg_info[i].hpm_load_uA);
-		if (rc < 0) {
-			pr_err("%s: regulator_set_optimum_mode failed rc=%d\n",
-								__func__, rc);
+			if (rc < 0) {
+				pr_err("%s: regulator_set_optimum_mode failed "
+				       "rc=%d\n", __func__, rc);
 
-			regulator_set_voltage(ts->vdd[i], 0,
-						reg_info[i].max_uV);
-			regulator_put(ts->vdd[i]);
-			goto error_vdd;
+				regulator_set_voltage(ts->vdd[i], 0,
+							reg_info[i].max_uV);
+				regulator_put(ts->vdd[i]);
+				goto error_vdd;
+			}
 		}
 
 		rc = regulator_enable(ts->vdd[i]);
 		if (rc) {
 			pr_err("%s: regulator_enable failed rc =%d\n",
 								__func__, rc);
-			regulator_set_optimum_mode(ts->vdd[i], 0);
-			regulator_set_voltage(ts->vdd[i], 0,
-						reg_info[i].max_uV);
+			if (regulator_count_voltages(ts->vdd[i]) > 0) {
+				regulator_set_optimum_mode(ts->vdd[i], 0);
+				regulator_set_voltage(ts->vdd[i], 0,
+						      reg_info[i].max_uV);
+			}
 			regulator_put(ts->vdd[i]);
 			goto error_vdd;
 		}
@@ -2439,10 +2441,11 @@
 	i = ts->platform_data->num_regulators;
 error_vdd:
 	while (--i >= 0) {
-		if (regulator_count_voltages(ts->vdd[i]) > 0)
+		if (regulator_count_voltages(ts->vdd[i]) > 0) {
 			regulator_set_voltage(ts->vdd[i], 0,
 						reg_info[i].max_uV);
-		regulator_set_optimum_mode(ts->vdd[i], 0);
+			regulator_set_optimum_mode(ts->vdd[i], 0);
+		}
 		regulator_disable(ts->vdd[i]);
 		regulator_put(ts->vdd[i]);
 	}
@@ -2834,6 +2837,8 @@
 		goto regulator_hpm;
 
 	for (i = 0; i < num_reg; i++) {
+		if (regulator_count_voltages(ts->vdd[i]) < 0)
+			continue;
 		rc = regulator_set_optimum_mode(ts->vdd[i],
 					reg_info[i].lpm_load_uA);
 		if (rc < 0) {
@@ -2848,6 +2853,8 @@
 
 regulator_hpm:
 	for (i = 0; i < num_reg; i++) {
+		if (regulator_count_voltages(ts->vdd[i]) < 0)
+			continue;
 		rc = regulator_set_optimum_mode(ts->vdd[i],
 					reg_info[i].hpm_load_uA);
 		if (rc < 0) {
@@ -2860,16 +2867,22 @@
 	return 0;
 
 fail_regulator_lpm:
-	while (i--)
+	while (i--) {
+		if (regulator_count_voltages(ts->vdd[i]) < 0)
+			continue;
 		regulator_set_optimum_mode(ts->vdd[i],
 					reg_info[i].hpm_load_uA);
+	}
 
 	return rc;
 
 fail_regulator_hpm:
-	while (i--)
+	while (i--) {
+		if (regulator_count_voltages(ts->vdd[i]) < 0)
+			continue;
 		regulator_set_optimum_mode(ts->vdd[i],
 					reg_info[i].lpm_load_uA);
+	}
 
 	return rc;
 }
diff --git a/drivers/media/video/msm/msm_vfe31.c b/drivers/media/video/msm/msm_vfe31.c
index 2b3732c..f1d70aa 100644
--- a/drivers/media/video/msm/msm_vfe31.c
+++ b/drivers/media/video/msm/msm_vfe31.c
@@ -3892,6 +3892,7 @@
 	spin_lock_init(&vfe31_ctrl->io_lock);
 	spin_lock_init(&vfe31_ctrl->update_ack_lock);
 	spin_lock_init(&vfe31_ctrl->tasklet_lock);
+	spin_lock_init(&vfe31_ctrl->xbar_lock);
 
 	INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
 	vfe31_init_free_buf_queue();
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index fa30ef2..2c99a7f 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.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
@@ -42,6 +42,7 @@
 #define PM8921_VERSION_MASK	0xFFF0
 #define PM8921_VERSION_VALUE	0x06F0
 #define PM8922_VERSION_VALUE	0x0AF0
+#define PM8917_VERSION_VALUE	0x12F0
 #define PM8921_REVISION_MASK	0x000F
 
 #define REG_PM8921_PON_CNTRL_3	0x01D
@@ -116,6 +117,9 @@
 	else if ((pmic->rev_registers & PM8921_VERSION_MASK)
 			== PM8922_VERSION_VALUE)
 		version = PM8XXX_VERSION_8922;
+	else if ((pmic->rev_registers & PM8921_VERSION_MASK)
+			== PM8917_VERSION_VALUE)
+		version = PM8XXX_VERSION_8917;
 
 	return version;
 }
@@ -138,7 +142,7 @@
 	.pmic_get_revision	= pm8921_get_revision,
 };
 
-static const struct resource gpio_cell_resources[] __devinitconst = {
+static struct resource gpio_cell_resources[] = {
 	[0] = {
 		.start = PM8921_IRQ_BLOCK_BIT(PM8921_GPIO_BLOCK_START, 0),
 		.end   = PM8921_IRQ_BLOCK_BIT(PM8921_GPIO_BLOCK_START, 0)
@@ -167,7 +171,7 @@
 	.num_resources	= ARRAY_SIZE(adc_cell_resources),
 };
 
-static const struct resource mpp_cell_resources[] __devinitconst = {
+static struct resource mpp_cell_resources[] = {
 	{
 		.start	= PM8921_IRQ_BLOCK_BIT(PM8921_MPP_BLOCK_START, 0),
 		.end	= PM8921_IRQ_BLOCK_BIT(PM8921_MPP_BLOCK_START, 0)
@@ -545,7 +549,14 @@
 	}
 
 	if (pdata->gpio_pdata) {
-		pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
+		if (version == PM8XXX_VERSION_8917) {
+			gpio_cell_resources[0].end = gpio_cell_resources[0].end
+							+ PM8917_NR_GPIOS
+							- PM8921_NR_GPIOS;
+			pdata->gpio_pdata->gpio_cdata.ngpios = PM8917_NR_GPIOS;
+		} else {
+			pdata->gpio_pdata->gpio_cdata.ngpios = PM8921_NR_GPIOS;
+		}
 		gpio_cell.platform_data = pdata->gpio_pdata;
 		gpio_cell.pdata_size = sizeof(struct pm8xxx_gpio_platform_data);
 		ret = mfd_add_devices(pmic->dev, 0, &gpio_cell, 1,
@@ -557,7 +568,14 @@
 	}
 
 	if (pdata->mpp_pdata) {
-		pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
+		if (version == PM8XXX_VERSION_8917) {
+			mpp_cell_resources[0].end = mpp_cell_resources[0].end
+							+ PM8917_NR_MPPS
+							- PM8921_NR_MPPS;
+			pdata->mpp_pdata->core_data.nmpps = PM8917_NR_MPPS;
+		} else {
+			pdata->mpp_pdata->core_data.nmpps = PM8921_NR_MPPS;
+		}
 		pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
 		mpp_cell.platform_data = pdata->mpp_pdata;
 		mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
@@ -665,12 +683,6 @@
 		goto bail;
 	}
 
-	ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
-	if (ret) {
-		pr_err("Failed to add pwm subdevice ret=%d\n", ret);
-		goto bail;
-	}
-
 	if (pdata->misc_pdata) {
 		misc_cell.platform_data = pdata->misc_pdata;
 		misc_cell.pdata_size = sizeof(struct pm8xxx_misc_platform_data);
@@ -682,16 +694,6 @@
 		}
 	}
 
-	if (pdata->leds_pdata) {
-		leds_cell.platform_data = pdata->leds_pdata;
-		leds_cell.pdata_size = sizeof(struct pm8xxx_led_platform_data);
-		ret = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL, 0);
-		if (ret) {
-			pr_err("Failed to add leds subdevice ret=%d\n", ret);
-			goto bail;
-		}
-	}
-
 	ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
 				irq_base);
 	if (ret) {
@@ -708,16 +710,37 @@
 		goto bail;
 	}
 
-	if (pdata->vibrator_pdata) {
-		vibrator_cell.platform_data = pdata->vibrator_pdata;
-		vibrator_cell.pdata_size =
-				sizeof(struct pm8xxx_vibrator_platform_data);
-		ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell, 1, NULL, 0);
+	if (version != PM8XXX_VERSION_8917) {
+		ret = mfd_add_devices(pmic->dev, 0, &pwm_cell, 1, NULL, 0);
 		if (ret) {
-			pr_err("Failed to add vibrator subdevice ret=%d\n",
-									ret);
+			pr_err("Failed to add pwm subdevice ret=%d\n", ret);
 			goto bail;
 		}
+
+		if (pdata->leds_pdata) {
+			leds_cell.platform_data = pdata->leds_pdata;
+			leds_cell.pdata_size =
+				sizeof(struct pm8xxx_led_platform_data);
+			ret = mfd_add_devices(pmic->dev, 0, &leds_cell,
+					      1, NULL, 0);
+			if (ret) {
+				pr_err("Failed to add leds subdevice ret=%d\n",
+						ret);
+				goto bail;
+			}
+		}
+
+		if (pdata->vibrator_pdata) {
+			vibrator_cell.platform_data = pdata->vibrator_pdata;
+			vibrator_cell.pdata_size =
+				sizeof(struct pm8xxx_vibrator_platform_data);
+			ret = mfd_add_devices(pmic->dev, 0, &vibrator_cell,
+					      1, NULL, 0);
+			if (ret) {
+				pr_err("Failed to add vibrator ret=%d\n", ret);
+				goto bail;
+			}
+		}
 	}
 
 	if (pdata->ccadc_pdata) {
@@ -768,6 +791,11 @@
 	[PM8XXX_REVISION_8922_2p0]	= "2.0",
 };
 
+static const char * const pm8917_rev_names[] = {
+	[PM8XXX_REVISION_8917_TEST]	= "test",
+	[PM8XXX_REVISION_8917_1p0]	= "1.0",
+};
+
 static int __devinit pm8921_probe(struct platform_device *pdev)
 {
 	const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
@@ -823,9 +851,14 @@
 		if (revision >= 0 && revision < ARRAY_SIZE(pm8922_rev_names))
 			revision_name = pm8922_rev_names[revision];
 		pr_info("PMIC version: PM8922 rev %s\n", revision_name);
+	} else if (version == PM8XXX_VERSION_8917) {
+		if (revision >= 0 && revision < ARRAY_SIZE(pm8917_rev_names))
+			revision_name = pm8917_rev_names[revision];
+		pr_info("PMIC version: PM8917 rev %s\n", revision_name);
 	} else {
 		WARN_ON(version != PM8XXX_VERSION_8921
-			&& version != PM8XXX_VERSION_8922);
+			&& version != PM8XXX_VERSION_8922
+			&& version != PM8XXX_VERSION_8917);
 	}
 
 	/* Log human readable restart reason */
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index fe6abf2..f6997ac 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.c
@@ -1,4 +1,4 @@
-/* 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
@@ -22,6 +22,7 @@
 #include <linux/semaphore.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/clk.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_iomap.h>
 
@@ -79,10 +80,15 @@
 };
 
 
-static int configure_iris_xo(bool use_48mhz_xo, int on)
+static int configure_iris_xo(struct device *dev, bool use_48mhz_xo, int on)
 {
 	u32 reg = 0;
 	int rc = 0;
+	struct clk *cxo = clk_get(dev, "cxo");
+	if (IS_ERR(cxo)) {
+		pr_err("Couldn't get cxo clock\n");
+		return PTR_ERR(cxo);
+	}
 
 	if (on) {
 		msm_riva_base = ioremap(MSM_RIVA_PHYS, SZ_256);
@@ -92,6 +98,11 @@
 		}
 
 		/* Enable IRIS XO */
+		rc = clk_prepare_enable(cxo);
+		if (rc) {
+			pr_err("cxo enable failed\n");
+			goto fail;
+		}
 		writel_relaxed(0, RIVA_PMU_CFG);
 		reg = readl_relaxed(RIVA_PMU_CFG);
 		reg |= RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
@@ -119,6 +130,7 @@
 		reg &= ~(RIVA_PMU_CFG_GC_BUS_MUX_SEL_TOP |
 				RIVA_PMU_CFG_IRIS_XO_CFG);
 		writel_relaxed(reg, RIVA_PMU_CFG);
+		clk_disable_unprepare(cxo);
 
 		if (!use_48mhz_xo) {
 			wlan_clock = msm_xo_get(MSM_XO_TCXO_A2, id);
@@ -148,12 +160,14 @@
 	/* Add some delay for XO to settle */
 	msleep(20);
 
+	clk_put(cxo);
 	return rc;
 
 msm_xo_vote_fail:
 	msm_xo_put(wlan_clock);
 
 fail:
+	clk_put(cxo);
 	return rc;
 }
 
@@ -302,13 +316,15 @@
 			goto fail_iris_on;
 
 		/* Configure IRIS XO */
-		rc = configure_iris_xo(cfg->use_48mhz_xo, WCNSS_WLAN_SWITCH_ON);
+		rc = configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_ON);
 		if (rc)
 			goto fail_iris_xo;
 		up(&riva_power_on_lock);
 
 	} else {
-		configure_iris_xo(cfg->use_48mhz_xo, WCNSS_WLAN_SWITCH_OFF);
+		configure_iris_xo(dev, cfg->use_48mhz_xo,
+				WCNSS_WLAN_SWITCH_OFF);
 		wcnss_iris_vregs_off();
 		wcnss_riva_vregs_off();
 	}
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index c0c398b..c40f13e 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -220,8 +220,8 @@
 	unsigned int			update_time;
 	unsigned int			max_voltage_mv;
 	unsigned int			min_voltage_mv;
-	unsigned int			cool_temp_dc;
-	unsigned int			warm_temp_dc;
+	int				cool_temp_dc;
+	int				warm_temp_dc;
 	unsigned int			temp_check_period;
 	unsigned int			cool_bat_chg_current;
 	unsigned int			warm_bat_chg_current;
@@ -2301,8 +2301,16 @@
 {
 	int rc;
 
-	btm_config.btm_warm_fn = battery_warm;
-	btm_config.btm_cool_fn = battery_cool;
+	if (chip->warm_temp_dc != INT_MIN)
+		btm_config.btm_warm_fn = battery_warm;
+	else
+		btm_config.btm_warm_fn = NULL;
+
+	if (chip->cool_temp_dc != INT_MIN)
+		btm_config.btm_cool_fn = battery_cool;
+	else
+		btm_config.btm_cool_fn = NULL;
+
 	btm_config.low_thr_temp = chip->cool_temp_dc;
 	btm_config.high_thr_temp = chip->warm_temp_dc;
 	btm_config.interval = chip->temp_check_period;
@@ -3042,7 +3050,7 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)
+	if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
 		&& !(chip->keep_btm_on_suspend)) {
 		rc = pm8xxx_adc_btm_configure(&btm_config);
 		if (rc)
@@ -3064,7 +3072,7 @@
 	int rc;
 	struct pm8921_chg_chip *chip = dev_get_drvdata(dev);
 
-	if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)
+	if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)
 		&& !(chip->keep_btm_on_suspend)) {
 		rc = pm8xxx_adc_btm_end();
 		if (rc)
@@ -3110,8 +3118,16 @@
 	chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
 	chip->batt_id_min = pdata->batt_id_min;
 	chip->batt_id_max = pdata->batt_id_max;
-	chip->cool_temp_dc = pdata->cool_temp * 10;
-	chip->warm_temp_dc = pdata->warm_temp * 10;
+	if (pdata->cool_temp != INT_MIN)
+		chip->cool_temp_dc = pdata->cool_temp * 10;
+	else
+		chip->cool_temp_dc = INT_MIN;
+
+	if (pdata->warm_temp != INT_MIN)
+		chip->warm_temp_dc = pdata->warm_temp * 10;
+	else
+		chip->warm_temp_dc = INT_MIN;
+
 	chip->temp_check_period = pdata->temp_check_period;
 	chip->max_bat_chg_current = pdata->max_bat_chg_current;
 	chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
@@ -3185,10 +3201,10 @@
 	enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
 	enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
 	/*
-	 * if both the cool_temp_dc and warm_temp_dc are zero the device doesnt
+	 * if both the cool_temp_dc and warm_temp_dc are invalid device doesnt
 	 * care for jeita compliance
 	 */
-	if (!(chip->cool_temp_dc == 0 && chip->warm_temp_dc == 0)) {
+	if (!(chip->cool_temp_dc == INT_MIN && chip->warm_temp_dc == INT_MIN)) {
 		rc = configure_btm(chip);
 		if (rc) {
 			pr_err("couldn't register with btm rc=%d\n", rc);
diff --git a/drivers/slimbus/slimbus.c b/drivers/slimbus/slimbus.c
index a541d8b..1ac301f 100644
--- a/drivers/slimbus/slimbus.c
+++ b/drivers/slimbus/slimbus.c
@@ -1074,7 +1074,7 @@
 	else
 		mc = SLIM_MSG_MC_CONNECT_SINK;
 	buf[0] = pn;
-	buf[1] = ch;
+	buf[1] = ctrl->chans[ch].chan;
 	if (la == SLIM_LA_MANAGER)
 		ctrl->ports[pn].flow = flow;
 	ret = slim_processtxn(ctrl, SLIM_MSG_DEST_LOGICALADDR, mc, 0,
@@ -1269,6 +1269,9 @@
 	int i, j;
 	int *len;
 	int sl = slc->seglen << slc->rootexp;
+	/* Channel is already active and other end is transmitting data */
+	if (slc->state >= SLIM_CH_ACTIVE)
+		return;
 	if (slc->coeff == SLIM_COEFF_1) {
 		arr = ctrl->sched.chc1;
 		len = &ctrl->sched.num_cc1;
@@ -1507,9 +1510,8 @@
  * slim_alloc_ch: Allocate a slimbus channel and return its handle.
  * @sb: client handle.
  * @chanh: return channel handle
- * Slimbus channels are limited to 256 per specification. LSB of the handle
- * indicates channel number and MSB of the handle is used by the slimbus
- * framework. -EXFULL is returned if all channels are in use.
+ * Slimbus channels are limited to 256 per specification.
+ * -EXFULL is returned if all channels are in use.
  * Although slimbus specification supports 256 channels, a controller may not
  * support that many channels.
  */
@@ -1532,6 +1534,7 @@
 	*chanh = i;
 	ctrl->chans[i].nextgrp = 0;
 	ctrl->chans[i].state = SLIM_CH_ALLOCATED;
+	ctrl->chans[i].chan = (u8)(ctrl->reserved + i);
 
 	mutex_unlock(&ctrl->m_ctrl);
 	return 0;
@@ -1539,9 +1542,68 @@
 EXPORT_SYMBOL_GPL(slim_alloc_ch);
 
 /*
+ * slim_query_ch: Get reference-counted handle for a channel number. Every
+ * channel is reference counted by upto one as producer and the others as
+ * consumer)
+ * @sb: client handle
+ * @chan: slimbus channel number
+ * @chanh: return channel handle
+ * If request channel number is not in use, it is allocated, and reference
+ * count is set to one. If the channel was was already allocated, this API
+ * will return handle to that channel and reference count is incremented.
+ * -EXFULL is returned if all channels are in use
+ */
+int slim_query_ch(struct slim_device *sb, u8 ch, u16 *chanh)
+{
+	struct slim_controller *ctrl = sb->ctrl;
+	u16 i, j;
+	int ret = 0;
+	if (!ctrl || !chanh)
+		return -EINVAL;
+	mutex_lock(&ctrl->m_ctrl);
+	/* start with modulo number */
+	i = ch % ctrl->nchans;
+
+	for (j = 0; j < ctrl->nchans; j++) {
+		if (ctrl->chans[i].chan == ch) {
+			*chanh = i;
+			ctrl->chans[i].ref++;
+			if (ctrl->chans[i].state == SLIM_CH_FREE)
+				ctrl->chans[i].state = SLIM_CH_ALLOCATED;
+			goto query_out;
+		}
+		i = (i + 1) % ctrl->nchans;
+	}
+
+	/* Channel not in table yet */
+	ret = -EXFULL;
+	for (j = 0; j < ctrl->nchans; j++) {
+		if (ctrl->chans[i].state == SLIM_CH_FREE) {
+			ctrl->chans[i].state =
+				SLIM_CH_ALLOCATED;
+			*chanh = i;
+			ctrl->chans[i].ref++;
+			ctrl->chans[i].chan = ch;
+			ctrl->chans[i].nextgrp = 0;
+			ret = 0;
+			break;
+		}
+		i = (i + 1) % ctrl->nchans;
+	}
+query_out:
+	mutex_unlock(&ctrl->m_ctrl);
+	dev_dbg(&ctrl->dev, "query ch:%d,hdl:%d,ref:%d,ret:%d",
+				ch, i, ctrl->chans[i].ref, ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(slim_query_ch);
+
+/*
  * slim_dealloc_ch: Deallocate channel allocated using the API above
  * -EISCONN is returned if the channel is tried to be deallocated without
  *  being removed first.
+ *  -ENOTCONN is returned if deallocation is tried on a channel that's not
+ *  allocated.
  */
 int slim_dealloc_ch(struct slim_device *sb, u16 chanh)
 {
@@ -1552,15 +1614,29 @@
 		return -EINVAL;
 
 	mutex_lock(&ctrl->m_ctrl);
+	if (slc->state == SLIM_CH_FREE) {
+		mutex_unlock(&ctrl->m_ctrl);
+		return -ENOTCONN;
+	}
+	if (slc->ref > 1) {
+		slc->ref--;
+		mutex_unlock(&ctrl->m_ctrl);
+		dev_dbg(&ctrl->dev, "remove chan:%d,hdl:%d,ref:%d",
+					slc->chan, chanh, slc->ref);
+		return 0;
+	}
 	if (slc->state >= SLIM_CH_PENDING_ACTIVE) {
 		dev_err(&ctrl->dev, "Channel:%d should be removed first", chan);
 		mutex_unlock(&ctrl->m_ctrl);
 		return -EISCONN;
 	}
+	slc->ref--;
 	kfree(slc->srch);
 	slc->srch = NULL;
 	slc->state = SLIM_CH_FREE;
 	mutex_unlock(&ctrl->m_ctrl);
+	dev_dbg(&ctrl->dev, "remove chan:%d,hdl:%d,ref:%d",
+				slc->chan, chanh, slc->ref);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(slim_dealloc_ch);
@@ -1589,8 +1665,8 @@
  * Channels can be grouped if multiple channels use same parameters
  * (e.g. 5.1 audio has 6 channels with same parameters. They will all be grouped
  * and given 1 handle for simplicity and avoid repeatedly calling the API)
- * -EISCONN is returned if the channel is already connected. -EBUSY is
- * returned if the channel is already allocated to some other client.
+ * -EISCONN is returned if channel is already used with different parameters.
+ * -ENXIO is returned if the channel is not yet allocated.
  */
 int slim_define_ch(struct slim_device *sb, struct slim_ch *prop, u16 *chanh,
 			u8 nchan, bool grp, u16 *grph)
@@ -1603,26 +1679,28 @@
 	mutex_lock(&ctrl->m_ctrl);
 	for (i = 0; i < nchan; i++) {
 		u8 chan = (u8)(chanh[i] & 0xFF);
-		dev_dbg(&ctrl->dev, "define_ch: port:%d, state:%d", chanh[i],
+		struct slim_ich *slc = &ctrl->chans[chan];
+		dev_dbg(&ctrl->dev, "define_ch: ch:%d, state:%d", chan,
 				(int)ctrl->chans[chan].state);
-		if (ctrl->chans[chan].state < SLIM_CH_ALLOCATED ||
-			ctrl->chans[chan].state > SLIM_CH_DEFINED) {
-			int j;
-			for (j = i - 1; j >= 0; j--)
-				ctrl->chans[chan].state = SLIM_CH_ALLOCATED;
-			ret = -EBUSY;
+		if (slc->state < SLIM_CH_ALLOCATED) {
+			ret = -ENXIO;
 			goto err_define_ch;
 		}
-		ctrl->chans[chan].prop = *prop;
-		ret = slim_nextdefine_ch(sb, chan);
-		if (ret) {
-			int j;
-			for (j = i - 1; j >= 0; j--) {
-				chan = chanh[j] & 0xFF;
-				ctrl->chans[chan].nextgrp = 0;
-				ctrl->chans[chan].state = SLIM_CH_ALLOCATED;
+		if (slc->state >= SLIM_CH_DEFINED && slc->ref >= 2) {
+			if (prop->ratem != slc->prop.ratem ||
+			prop->sampleszbits != slc->prop.sampleszbits ||
+			prop->baser != slc->prop.baser) {
+				ret = -EISCONN;
+				goto err_define_ch;
 			}
+		} else if (slc->state > SLIM_CH_DEFINED) {
+			ret = -EISCONN;
 			goto err_define_ch;
+		} else {
+			ctrl->chans[chan].prop = *prop;
+			ret = slim_nextdefine_ch(sb, chan);
+			if (ret)
+				goto err_define_ch;
 		}
 		if (i < (nchan - 1))
 			ctrl->chans[chan].nextgrp = chanh[i + 1];
@@ -1630,13 +1708,18 @@
 			ctrl->chans[chan].nextgrp |= SLIM_START_GRP;
 		if (i == (nchan - 1))
 			ctrl->chans[chan].nextgrp |= SLIM_END_GRP;
-
-		ctrl->chans[chan].state = SLIM_CH_DEFINED;
 	}
 
 	if (grp)
 		*grph = chanh[0];
+	for (i = 0; i < nchan; i++) {
+		u8 chan = (u8)(chanh[i] & 0xFF);
+		struct slim_ich *slc = &ctrl->chans[chan];
+		if (slc->state == SLIM_CH_ALLOCATED)
+			slc->state = SLIM_CH_DEFINED;
+	}
 err_define_ch:
+	dev_dbg(&ctrl->dev, "define_ch: ch:%d, ret:%d", *chanh, ret);
 	mutex_unlock(&ctrl->m_ctrl);
 	return ret;
 }
@@ -2310,14 +2393,17 @@
 					struct slim_pending_ch, pending);
 		slc = &ctrl->chans[pch->chan];
 		if (revert) {
-			u32 sl = slc->seglen << slc->rootexp;
-			if (slc->coeff == SLIM_COEFF_3)
-				sl *= 3;
-			ctrl->sched.usedslots -= sl;
-			slim_remove_ch(ctrl, slc);
-			slc->state = SLIM_CH_DEFINED;
+			if (slc->state == SLIM_CH_PENDING_ACTIVE) {
+				u32 sl = slc->seglen << slc->rootexp;
+				if (slc->coeff == SLIM_COEFF_3)
+					sl *= 3;
+				ctrl->sched.usedslots -= sl;
+				slim_remove_ch(ctrl, slc);
+				slc->state = SLIM_CH_DEFINED;
+			}
 		} else {
 			slc->state = SLIM_CH_ACTIVE;
+			slc->def++;
 		}
 		list_del_init(&pch->pending);
 		kfree(pch);
@@ -2333,6 +2419,7 @@
 			if (slc->coeff == SLIM_COEFF_3)
 				sl *= 3;
 			ctrl->sched.usedslots += sl;
+			slc->def = 1;
 			slc->state = SLIM_CH_ACTIVE;
 		} else
 			slim_remove_ch(ctrl, slc);
@@ -2383,7 +2470,8 @@
 	list_for_each_entry(pch, &sb->mark_define, pending) {
 		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		slim_add_ch(ctrl, slc);
-		slc->state = SLIM_CH_PENDING_ACTIVE;
+		if (slc->state < SLIM_CH_ACTIVE)
+			slc->state = SLIM_CH_PENDING_ACTIVE;
 	}
 
 	list_for_each_entry(pch, &sb->mark_removal, pending) {
@@ -2433,7 +2521,7 @@
 	list_for_each_entry(pch, &sb->mark_define, pending) {
 		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		/* Define content */
-		wbuf[0] = pch->chan;
+		wbuf[0] = slc->chan;
 		wbuf[1] = slc->prrate;
 		wbuf[2] = slc->prop.dataf | (slc->prop.auxf << 4);
 		wbuf[3] = slc->prop.sampleszbits / SLIM_CL_PER_SL;
@@ -2456,8 +2544,9 @@
 	}
 
 	list_for_each_entry(pch, &sb->mark_removal, pending) {
+		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		dev_dbg(&ctrl->dev, "remove chan:%x\n", pch->chan);
-		wbuf[0] = pch->chan;
+		wbuf[0] = slc->chan;
 		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
 				SLIM_MSG_MC_NEXT_REMOVE_CHANNEL, 0,
 				SLIM_MSG_MT_CORE, NULL, wbuf, 1, 4,
@@ -2466,8 +2555,9 @@
 			goto revert_reconfig;
 	}
 	list_for_each_entry(pch, &sb->mark_suspend, pending) {
+		struct slim_ich *slc = &ctrl->chans[pch->chan];
 		dev_dbg(&ctrl->dev, "suspend chan:%x\n", pch->chan);
-		wbuf[0] = pch->chan;
+		wbuf[0] = slc->chan;
 		ret = slim_processtxn(ctrl, SLIM_MSG_DEST_BROADCAST,
 				SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL, 0,
 				SLIM_MSG_MT_CORE, NULL, wbuf, 1, 4,
@@ -2489,13 +2579,13 @@
 		dev_dbg(&ctrl->dev, "new-off:%d, old-off:%d\n",
 				slc->newoff, slc->offset);
 
-		if (slc->state < SLIM_CH_ACTIVE ||
+		if (slc->state < SLIM_CH_ACTIVE || slc->def < slc->ref ||
 			slc->newintr != slc->interval ||
 			slc->newoff != slc->offset) {
 			segdist |= 0x200;
 			segdist >>= curexp;
 			segdist |= (slc->newoff << (curexp + 1)) & 0xC00;
-			wbuf[0] = (u8)(slc - ctrl->chans);
+			wbuf[0] = slc->chan;
 			wbuf[1] = (u8)(segdist & 0xFF);
 			wbuf[2] = (u8)((segdist & 0xF00) >> 8) |
 					(slc->prop.prot << 4);
@@ -2522,13 +2612,13 @@
 		dev_dbg(&ctrl->dev, "new-off:%d, old-off:%d\n",
 				slc->newoff, slc->offset);
 
-		if (slc->state < SLIM_CH_ACTIVE ||
+		if (slc->state < SLIM_CH_ACTIVE || slc->def < slc->ref ||
 			slc->newintr != slc->interval ||
 			slc->newoff != slc->offset) {
 			segdist |= 0x200;
 			segdist >>= curexp;
 			segdist |= 0xC00;
-			wbuf[0] = (u8)(slc - ctrl->chans);
+			wbuf[0] = slc->chan;
 			wbuf[1] = (u8)(segdist & 0xFF);
 			wbuf[2] = (u8)((segdist & 0xF00) >> 8) |
 					(slc->prop.prot << 4);
@@ -2607,6 +2697,8 @@
 	mutex_lock(&ctrl->m_ctrl);
 	do {
 		slc = &ctrl->chans[chan];
+		dev_dbg(&ctrl->dev, "chan:%d,ctrl:%d,def:%d", chan, chctrl,
+					slc->def);
 		if (slc->state < SLIM_CH_DEFINED) {
 			ret = -ENOTCONN;
 			break;
@@ -2616,7 +2708,7 @@
 			if (ret)
 				break;
 		} else if (chctrl == SLIM_CH_ACTIVATE) {
-			if (slc->state >= SLIM_CH_ACTIVE) {
+			if (slc->state > SLIM_CH_ACTIVE) {
 				ret = -EISCONN;
 				break;
 			}
@@ -2628,7 +2720,10 @@
 				ret = -ENOTCONN;
 				break;
 			}
-			ret = add_pending_ch(&sb->mark_removal, chan);
+			if (slc->def > 0)
+				slc->def--;
+			if (slc->def == 0)
+				ret = add_pending_ch(&sb->mark_removal, chan);
 			if (ret)
 				break;
 		}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 17b9f0d..e2d77e9 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1283,8 +1283,8 @@
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
-	clk_enable(dd->clk);
-	clk_enable(dd->pclk);
+	clk_prepare_enable(dd->clk);
+	clk_prepare_enable(dd->pclk);
 	msm_spi_enable_irqs(dd);
 
 	if (!msm_spi_is_valid_state(dd)) {
@@ -1311,8 +1311,8 @@
 	spin_unlock_irqrestore(&dd->queue_lock, flags);
 
 	msm_spi_disable_irqs(dd);
-	clk_disable(dd->clk);
-	clk_disable(dd->pclk);
+	clk_disable_unprepare(dd->clk);
+	clk_disable_unprepare(dd->pclk);
 
 	if (dd->use_rlock)
 		remote_mutex_unlock(&dd->r_lock);
@@ -1400,8 +1400,8 @@
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
 
-	clk_enable(dd->clk);
-	clk_enable(dd->pclk);
+	clk_prepare_enable(dd->clk);
+	clk_prepare_enable(dd->pclk);
 
 	spi_ioc = readl_relaxed(dd->base + SPI_IO_CONTROL);
 	mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select;
@@ -1429,8 +1429,8 @@
 
 	/* Ensure previous write completed before disabling the clocks */
 	mb();
-	clk_disable(dd->clk);
-	clk_disable(dd->pclk);
+	clk_disable_unprepare(dd->clk);
+	clk_disable_unprepare(dd->pclk);
 
 	if (dd->use_rlock)
 		remote_mutex_unlock(&dd->r_lock);
@@ -1925,7 +1925,7 @@
 	if (pdata && pdata->max_clock_speed)
 		msm_spi_clock_set(dd, dd->pdata->max_clock_speed);
 
-	rc = clk_enable(dd->clk);
+	rc = clk_prepare_enable(dd->clk);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: unable to enable core_clk\n",
 			__func__);
@@ -1933,7 +1933,7 @@
 	}
 
 	clk_enabled = 1;
-	rc = clk_enable(dd->pclk);
+	rc = clk_prepare_enable(dd->pclk);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: unable to enable iface_clk\n",
 		__func__);
@@ -1966,8 +1966,8 @@
 	if (rc)
 		goto err_probe_state;
 
-	clk_disable(dd->clk);
-	clk_disable(dd->pclk);
+	clk_disable_unprepare(dd->clk);
+	clk_disable_unprepare(dd->pclk);
 	clk_enabled = 0;
 	pclk_enabled = 0;
 
@@ -2009,10 +2009,10 @@
 err_probe_dma:
 err_probe_gsbi:
 	if (pclk_enabled)
-		clk_disable(dd->pclk);
+		clk_disable_unprepare(dd->pclk);
 err_probe_pclk_enable:
 	if (clk_enabled)
-		clk_disable(dd->clk);
+		clk_disable_unprepare(dd->clk);
 err_probe_clk_enable:
 	clk_put(dd->pclk);
 err_probe_pclk_get:
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 177176e..86f8a25 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -426,6 +426,23 @@
 	kfree(f->name);
 }
 
+static void frmnet_suspend(struct usb_function *f)
+{
+	struct f_rmnet *dev = func_to_rmnet(f);
+	unsigned port_num;
+
+	if (!atomic_read(&dev->online))
+		return;
+	/* This is a workaround for a bug in Windows 7/XP hosts in which
+	 * the DTR bit is not set low when going into suspend. Hence force it
+	 * low here when this function driver is suspended.
+	 */
+	if (dev->port.notify_modem) {
+		port_num = rmnet_ports[dev->port_num].ctrl_xport_num;
+		dev->port.notify_modem(&dev->port, port_num, ~ACM_CTRL_DTR);
+	}
+}
+
 static void frmnet_disable(struct usb_function *f)
 {
 	struct f_rmnet *dev = func_to_rmnet(f);
@@ -937,6 +954,7 @@
 	f->disable = frmnet_disable;
 	f->set_alt = frmnet_set_alt;
 	f->setup = frmnet_setup;
+	f->suspend = frmnet_suspend;
 	dev->port.send_cpkt_response = frmnet_send_cpkt_response;
 	dev->port.disconnect = frmnet_disconnect;
 	dev->port.connect = frmnet_connect;
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_smd.c b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
index 90cbe54..edba510 100644
--- a/drivers/usb/gadget/u_rmnet_ctrl_smd.c
+++ b/drivers/usb/gadget/u_rmnet_ctrl_smd.c
@@ -412,10 +412,13 @@
 
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
-	if (test_bit(CH_OPENED, &c->flags)) {
-		/* this should send the dtr zero */
+	if (test_and_clear_bit(CH_OPENED, &c->flags))
+		/* send dtr zero */
+		smd_tiocmset(c->ch, c->cbits_tomodem, ~c->cbits_tomodem);
+
+	if (c->ch) {
 		smd_close(c->ch);
-		clear_bit(CH_OPENED, &c->flags);
+		c->ch = NULL;
 	}
 }
 
@@ -464,7 +467,10 @@
 		if (!strncmp(c->name, pdev->name, SMD_CH_MAX_LEN)) {
 			clear_bit(CH_READY, &c->flags);
 			clear_bit(CH_OPENED, &c->flags);
-			smd_close(c->ch);
+			if (c->ch) {
+				smd_close(c->ch);
+				c->ch = NULL;
+			}
 			break;
 		}
 	}
@@ -603,8 +609,8 @@
 				c->cbits_tomodem ? "HIGH" : "LOW",
 				test_bit(CH_OPENED, &c->flags),
 				test_bit(CH_READY, &c->flags),
-				smd_read_avail(c->ch),
-				smd_write_avail(c->ch));
+				c->ch ? smd_read_avail(c->ch) : 0,
+				c->ch ? smd_write_avail(c->ch) : 0);
 
 		spin_unlock_irqrestore(&port->port_lock, flags);
 	}
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index caccade..93a96be 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -711,17 +711,18 @@
 	port->n_read = 0;
 	spin_unlock_irqrestore(&port->port_lock, flags);
 
-	if (!test_bit(CH_OPENED, &port->pi->flags))
-		return;
+	if (test_and_clear_bit(CH_OPENED, &port->pi->flags)) {
+		/* lower the dtr */
+		port->cbits_to_modem = 0;
+		smd_tiocmset(port->pi->ch,
+				port->cbits_to_modem,
+				~port->cbits_to_modem);
+	}
 
-	/* lower the dtr */
-	port->cbits_to_modem = 0;
-	smd_tiocmset(port->pi->ch,
-			port->cbits_to_modem,
-			~port->cbits_to_modem);
-
-	smd_close(port->pi->ch);
-	clear_bit(CH_OPENED, &port->pi->flags);
+	if (port->pi->ch) {
+		smd_close(port->pi->ch);
+		port->pi->ch = NULL;
+	}
 }
 
 #define SMD_CH_MAX_LEN	20
@@ -765,7 +766,10 @@
 		if (!strncmp(pi->name, pdev->name, SMD_CH_MAX_LEN)) {
 			clear_bit(CH_READY, &pi->flags);
 			clear_bit(CH_OPENED, &pi->flags);
-			smd_close(pi->ch);
+			if (pi->ch) {
+				smd_close(pi->ch);
+				pi->ch = NULL;
+			}
 			break;
 		}
 	}
@@ -821,6 +825,7 @@
 		size_t count, loff_t *ppos)
 {
 	struct gsmd_port *port;
+	struct smd_port_info *pi;
 	char *buf;
 	unsigned long flags;
 	int temp = 0;
@@ -833,6 +838,7 @@
 
 	for (i = 0; i < n_smd_ports; i++) {
 		port = smd_ports[i].port;
+		pi = port->pi;
 		spin_lock_irqsave(&port->port_lock, flags);
 		temp += scnprintf(buf + temp, 512 - temp,
 				"###PORT:%d###\n"
@@ -848,10 +854,10 @@
 				i, port->nbytes_tolaptop, port->nbytes_tomodem,
 				port->cbits_to_modem, port->cbits_to_laptop,
 				port->n_read,
-				smd_read_avail(port->pi->ch),
-				smd_write_avail(port->pi->ch),
-				test_bit(CH_OPENED, &port->pi->flags),
-				test_bit(CH_READY, &port->pi->flags));
+				pi->ch ? smd_read_avail(pi->ch) : 0,
+				pi->ch ? smd_write_avail(pi->ch) : 0,
+				test_bit(CH_OPENED, &pi->flags),
+				test_bit(CH_READY, &pi->flags));
 		spin_unlock_irqrestore(&port->port_lock, flags);
 	}
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 787514c..3d739ae 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -2450,7 +2450,7 @@
 		goto free_regs;
 	}
 
-	motg->xo_handle = msm_xo_get(MSM_XO_TCXO_D0, "usb");
+	motg->xo_handle = msm_xo_get(MSM_XO_CXO, "usb");
 	if (IS_ERR(motg->xo_handle)) {
 		dev_err(&pdev->dev, "%s not able to get the handle "
 			"to vote for TCXO D0 buffer\n", __func__);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index f27bd49..1449c8e 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -338,6 +338,8 @@
 {
 	unsigned long flag;
 	int ret = 0;
+	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
 	mutex_lock(&mdp_hist_mutex);
 	if (!mdp_is_hist_start) {
 		printk(KERN_ERR "%s histogram already stopped\n", __func__);
@@ -349,6 +351,14 @@
 	mdp_is_hist_start = FALSE;
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
+	if (!mfd->panel_power_on) {
+
+		mdp_is_hist_data = FALSE;
+		complete(&mdp_hist_comp);
+		ret = -EINVAL;
+		goto mdp_hist_stop_err;
+	}
+
 	ret = _mdp_histogram_ctrl(FALSE);
 
 mdp_hist_stop_err:
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 1d1d5f1..1bef55c 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1589,7 +1589,7 @@
 				continue;
 			init_completion(&pipe->comp);
 			init_completion(&pipe->dmas_comp);
-			pr_info("%s: pipe=%x ndx=%d num=%d\n", __func__,
+			pr_debug("%s: pipe=%x ndx=%d num=%d\n", __func__,
 				(int)pipe, pipe->pipe_ndx, pipe->pipe_num);
 			return pipe;
 		}
@@ -1605,7 +1605,7 @@
 {
 	uint32 ptype, num, ndx, mixer;
 
-	pr_info("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx);
+	pr_debug("%s: pipe=%x ndx=%d\n", __func__, (int)pipe, pipe->pipe_ndx);
 
 	ptype = pipe->pipe_type;
 	num = pipe->pipe_num;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index 5f5d632..96a1eda 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -585,7 +585,7 @@
 		dsi_pipe->blt_addr = 0;
 		change++;
 	}
-	pr_info("%s: enable=%d blt_addr=%x\n", __func__,
+	pr_debug("%s: enable=%d blt_addr=%x\n", __func__,
 				enable, (int)dsi_pipe->blt_addr);
 	spin_unlock_irqrestore(&mdp_spin_lock, flag);
 
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index a4a5b06..d82672e 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -2604,14 +2604,14 @@
 	if (!IS_ERR_OR_NULL(mfd->iclient)) {
 		if (!IS_ERR_OR_NULL(buf->ihdl)) {
 			ion_free(mfd->iclient, buf->ihdl);
-			pr_info("%s:%d free writeback imem\n", __func__,
+			pr_debug("%s:%d free writeback imem\n", __func__,
 				__LINE__);
 			buf->ihdl = NULL;
 		}
 	} else {
 		if (buf->phys_addr) {
 			free_contiguous_memory_by_paddr(buf->phys_addr);
-			pr_info("%s:%d free writeback pmem\n", __func__,
+			pr_debug("%s:%d free writeback pmem\n", __func__,
 				__LINE__);
 		}
 	}
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index bdfadd5..42fa2ba 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -3148,6 +3148,9 @@
 		break;
 
 	case MSMFB_HISTOGRAM_START:
+		if (!mfd->panel_power_on)
+			return -EPERM;
+
 		if (!mfd->do_histogram)
 			return -ENODEV;
 		ret = mdp_start_histogram(info);
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index f65f835..d24d43c 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -506,7 +506,7 @@
 			if (IS_ERR_OR_NULL(buff_ion_handle)) {
 				ERR("%s(): get_ION_handle failed\n",
 				 __func__);
-				goto ion_error;
+				goto bail_out_add;
 			}
 			if (ion_handle_get_flags(client_ctx->user_ion_client,
 						buff_ion_handle,
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index bdbaffd..d1c7733 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-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
@@ -40,6 +40,7 @@
 #define APQ8060_MACHINE_ID	86
 #define AO8960_MACHINE_ID	87
 #define MSM8660_MACHINE_ID	71
+#define MDM9615_MACHINE_ID	104
 #define APQ8064_MACHINE_ID	109
 #define MSM8930_MACHINE_ID	116
 #define MSM8630_MACHINE_ID	117
@@ -47,10 +48,13 @@
 #define APQ8030_MACHINE_ID	119
 #define MSM8627_MACHINE_ID	120
 #define MSM8227_MACHINE_ID	121
+#define MSM8260A_MACHINE_ID	123
+#define MSM8974_MACHINE_ID	126
 #define APQ8060_TOOLS_ID	4062
 #define AO8960_TOOLS_ID		4064
 #define APQ8064_TOOLS_ID	4072
 #define MSM8930_TOOLS_ID	4072
+#define MSM8974_TOOLS_ID	4072
 
 #define MSG_MASK_0			(0x00000001)
 #define MSG_MASK_1			(0x00000002)
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 9aa557a..7ae8342 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -29,10 +29,20 @@
 /* MXT_TOUCH_KEYARRAY_T15 */
 #define MXT_KEYARRAY_MAX_KEYS	32
 
-/* The platform data for the Atmel maXTouch touchscreen driver */
-struct mxt_platform_data {
+/* Config data for a given maXTouch controller with a specific firmware */
+struct mxt_config_info {
 	const u8 *config;
 	size_t config_length;
+	u8 family_id;
+	u8 variant_id;
+	u8 version;
+	u8 build;
+};
+
+/* The platform data for the Atmel maXTouch touchscreen driver */
+struct mxt_platform_data {
+	const struct mxt_config_info *config_array;
+	size_t config_array_size;
 
 	unsigned int x_size;
 	unsigned int y_size;
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index 5ed615b..e7bf820 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.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
@@ -28,6 +28,7 @@
 	PM8XXX_VERSION_8018,
 	PM8XXX_VERSION_8922,
 	PM8XXX_VERSION_8038,
+	PM8XXX_VERSION_8917,
 };
 
 /* PMIC version specific silicon revisions */
@@ -68,6 +69,9 @@
 #define PM8XXX_REVISION_8038_2p0	2
 #define PM8XXX_REVISION_8038_2p1	3
 
+#define PM8XXX_REVISION_8917_TEST	0
+#define PM8XXX_REVISION_8917_1p0	1
+
 struct pm8xxx_drvdata {
 	int			(*pmic_readb) (const struct device *dev,
 						u16 addr, u8 *val);
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index a954364..31af535 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -63,9 +63,11 @@
  *				after the battery has been fully charged
  * @term_current:	the charger current (mA) at which EOC happens
  * @cool_temp:		the temperature (degC) at which the battery is
- *			considered cool charging current and voltage is reduced
+ *			considered cool charging current and voltage is reduced.
+ *			Use INT_MIN to indicate not valid.
  * @warm_temp:		the temperature (degC) at which the battery is
  *			considered warm charging current and voltage is reduced
+ *			Use INT_MIN to indicate not valid.
  * @temp_check_period:	The polling interval in seconds to check battery
  *			temeperature if it has gone to cool or warm temperature
  *			area
@@ -108,8 +110,8 @@
 	unsigned int			min_voltage;
 	unsigned int			resume_voltage_delta;
 	unsigned int			term_current;
-	unsigned int			cool_temp;
-	unsigned int			warm_temp;
+	int				cool_temp;
+	int				warm_temp;
 	unsigned int			temp_check_period;
 	unsigned int			max_bat_chg_current;
 	unsigned int			cool_bat_chg_current;
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 35792d5..ee1216d 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.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
@@ -40,8 +40,10 @@
 #define PM8921_NR_IRQS		256
 
 #define PM8921_NR_GPIOS		44
+#define PM8917_NR_GPIOS		38
 
 #define PM8921_NR_MPPS		12
+#define PM8917_NR_MPPS		10
 
 #define PM8921_GPIO_BLOCK_START	24
 #define PM8921_MPP_BLOCK_START	16
diff --git a/include/linux/slimbus/slimbus.h b/include/linux/slimbus/slimbus.h
index 2b5adb3..d161d41 100644
--- a/include/linux/slimbus/slimbus.h
+++ b/include/linux/slimbus/slimbus.h
@@ -381,6 +381,16 @@
  * @srch: Source ports used by this channel.
  * @nsrc: number of source ports used by this channel.
  * @sinkh: Sink port used by this channel.
+ * @chan: Channel number sent on hardware lines for this channel. May not be
+ *	equal to array-index into chans if client requested to use number beyond
+ *	channel-array for the controller.
+ * @ref: Reference number to keep track of how many clients (upto 2) are using
+ *	this channel.
+ * @def: Used to keep track of how many times the channel definition is sent
+ *	to hardware and this will decide if channel-remove can be sent for the
+ *	channel. Channel definition may be sent upto twice (once per producer
+ *	and once per consumer). Channel removal should be sent only once to
+ *	avoid clients getting underflow/overflow errors.
  */
 struct slim_ich {
 	struct slim_ch		prop;
@@ -397,6 +407,9 @@
 	u32			*srch;
 	int			nsrc;
 	u32			sinkh;
+	u8			chan;
+	int			ref;
+	int			def;
 };
 
 /*
@@ -472,6 +485,8 @@
  * @nports: Number of ports supported by the controller
  * @chans: Channels associated with this controller
  * @nchans: Number of channels supported
+ * @reserved: Reserved channels that controller wants to use internally
+ *		Clients will be assigned channel numbers after this number
  * @sched: scheduler structure used by the controller
  * @dev_released: completion used to signal when sysfs has released this
  *	controller so that it can be deleted during shutdown
@@ -516,6 +531,7 @@
 	int			nports;
 	struct slim_ich		*chans;
 	int			nchans;
+	u8			reserved;
 	struct slim_sched	sched;
 	struct completion	dev_released;
 	int			(*xfer_msg)(struct slim_controller *ctrl,
@@ -784,18 +800,32 @@
  * slim_alloc_ch: Allocate a slimbus channel and return its handle.
  * @sb: client handle.
  * @chanh: return channel handle
- * Slimbus channels are limited to 256 per specification. LSB of the handle
- * indicates channel number and MSB of the handle is used by the slimbus
- * framework. -EXFULL is returned if all channels are in use.
+ * Slimbus channels are limited to 256 per specification.
+ * -EXFULL is returned if all channels are in use.
  * Although slimbus specification supports 256 channels, a controller may not
  * support that many channels.
  */
 extern int slim_alloc_ch(struct slim_device *sb, u16 *chanh);
 
 /*
+ * slim_query_ch: Get reference-counted handle for a channel number. Every
+ * channel is reference counted by one as producer and the others as
+ * consumer)
+ * @sb: client handle
+ * @chan: slimbus channel number
+ * @chanh: return channel handle
+ * If request channel number is not in use, it is allocated, and reference
+ * count is set to one. If the channel was was already allocated, this API
+ * will return handle to that channel and reference count is incremented.
+ * -EXFULL is returned if all channels are in use
+ */
+extern int slim_query_ch(struct slim_device *sb, u8 chan, u16 *chanh);
+/*
  * slim_dealloc_ch: Deallocate channel allocated using the API above
  * -EISCONN is returned if the channel is tried to be deallocated without
  *  being removed first.
+ *  -ENOTCONN is returned if deallocation is tried on a channel that's not
+ *  allocated.
  */
 extern int slim_dealloc_ch(struct slim_device *sb, u16 chanh);
 
@@ -813,8 +843,8 @@
  *	(e.g. 5.1 audio has 6 channels with same parameters. They will all be
  *	grouped and given 1 handle for simplicity and avoid repeatedly calling
  *	the API)
- * -EISCONN is returned if the channel is already connected. -EBUSY is
- * returned if the channel is already allocated to some other client.
+ * -EISCONN is returned if channel is already used with different parameters.
+ * -ENXIO is returned if the channel is not yet allocated.
  */
 extern int slim_define_ch(struct slim_device *sb, struct slim_ch *prop,
 				u16 *chanh, u8 nchan, bool grp, u16 *grph);
diff --git a/include/sound/compress_offload.h b/include/sound/compress_offload.h
index 423264d..f746780 100644
--- a/include/sound/compress_offload.h
+++ b/include/sound/compress_offload.h
@@ -56,6 +56,7 @@
 	size_t decoded;
 	size_t rendered;
 	__u32 sampling_rate;
+	uint64_t timestamp;
 };
 
 /**
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 5fedf19..ccdc341 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -51,6 +51,8 @@
 	SND_JACK_BTN_3		= 0x0800,
 	SND_JACK_BTN_4		= 0x0400,
 	SND_JACK_BTN_5		= 0x0200,
+	SND_JACK_BTN_6		= 0x0100,
+	SND_JACK_BTN_7		= 0x0080,
 };
 
 struct snd_jack {
@@ -59,7 +61,7 @@
 	int type;
 	const char *id;
 	char name[100];
-	unsigned int key[6];   /* Keep in sync with definitions above */
+	unsigned int key[8];   /* Keep in sync with definitions above */
 	void *private_data;
 	void (*private_free)(struct snd_jack *);
 };
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 6dd815d..8c07206 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1530,8 +1530,6 @@
 	if (PCM_RUNTIME_CHECK(substream))
 		return -ENXIO;
 	runtime = substream->runtime;
-	if (runtime->status->state != SNDRV_PCM_STATE_OPEN)
-		return -EBADFD;
 	pr_err("%s called with cmd = %d\n", __func__, cmd);
 	err = substream->ops->ioctl(substream, cmd, arg);
 	return err;
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 8de9dec..50dede5 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -23,7 +23,6 @@
 #include <linux/mfd/wcd9310/pdata.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
-#include <sound/jack.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
 #include <sound/tlv.h>
@@ -54,6 +53,7 @@
 #define TABLA_MCLK_RATE_9600KHZ 9600000
 
 #define TABLA_FAKE_INS_THRESHOLD_MS 2500
+#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
 
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
@@ -118,7 +118,6 @@
 	u16 v_brh;
 	u16 v_brl;
 	u16 v_no_mic;
-	u8 nready;
 	u8 npoll;
 	u8 nbounce_wait;
 };
@@ -2611,14 +2610,15 @@
 	if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
 		(choice == TABLA_BANDGAP_AUDIO_MODE)) {
 		tabla_codec_enable_audio_mode_bandgap(codec);
-	} else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
-		(choice == TABLA_BANDGAP_MBHC_MODE)) {
+	} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
 			0x2);
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
 			0x80);
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
 			0x4);
+		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
+			0x01);
 		usleep_range(1000, 1000);
 		snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
 			0x00);
@@ -2705,9 +2705,21 @@
 	tabla->clock_active = false;
 }
 
+static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
+{
+	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
+		return 0;
+	else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
+		return 1;
+	else {
+		BUG_ON(1);
+		return -EINVAL;
+	}
+}
+
 static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
 {
-	u8 *n_cic;
+	u8 *n_ready, *n_cic;
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
@@ -2738,15 +2750,16 @@
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
 		      (tabla->mbhc_data.v_brl >> 8) & 0xFF);
 
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
-		      tabla->mbhc_data.nready);
+		      n_ready[tabla_codec_mclk_index(tabla)]);
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
 		      tabla->mbhc_data.npoll);
 	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
 		      tabla->mbhc_data.nbounce_wait);
-
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, n_cic[0]);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
+		      n_cic[tabla_codec_mclk_index(tabla)]);
 }
 
 static int tabla_startup(struct snd_pcm_substream *substream,
@@ -2781,6 +2794,10 @@
 			tabla_codec_enable_clock_block(codec, 0);
 			tabla_codec_calibrate_hs_polling(codec);
 			tabla_codec_start_hs_polling(codec);
+		} else {
+			tabla_codec_enable_bandgap(codec,
+					TABLA_BANDGAP_AUDIO_MODE);
+			tabla_codec_enable_clock_block(codec, 0);
 		}
 	} else {
 
@@ -2802,6 +2819,10 @@
 			}
 			snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
 					0x05, 0x01);
+		} else {
+			tabla_codec_disable_clock_block(codec);
+			tabla_codec_enable_bandgap(codec,
+				TABLA_BANDGAP_OFF);
 		}
 	}
 	return 0;
@@ -3106,7 +3127,6 @@
 	/* Turn off the override after measuring mic voltage */
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
 
-	pr_debug("read microphone bias value %04x\n", bias_value);
 	return bias_value;
 }
 
@@ -3388,7 +3408,7 @@
 	 */
 	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
-	ncic = n_cic[0];
+	ncic = n_cic[tabla_codec_mclk_index(tabla)];
 	nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
 	navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
 	mclk_rate = tabla->mclk_freq;
@@ -3475,7 +3495,7 @@
 		ret += sizeof(btn_det->_n_cic);
 	case TABLA_BTN_DET_N_CIC:
 		ret += sizeof(btn_det->_n_ready);
-	case TABLA_BTN_DET_V_N_READY:
+	case TABLA_BTN_DET_N_READY:
 		ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
 	case TABLA_BTN_DET_V_BTN_HIGH:
 		ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
@@ -3496,25 +3516,25 @@
 	struct tabla_mbhc_btn_detect_cfg *btn_det;
 	struct tabla_mbhc_plug_type_cfg *plug_type;
 	u16 *btn_high;
+	u8 *n_ready;
 	int i;
 
 	tabla = snd_soc_codec_get_drvdata(codec);
 	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
 	plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
 
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
 	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
-		tabla->mbhc_data.nready = 3;
 		tabla->mbhc_data.npoll = 9;
 		tabla->mbhc_data.nbounce_wait = 30;
 	} else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
-		tabla->mbhc_data.nready = 2;
 		tabla->mbhc_data.npoll = 7;
 		tabla->mbhc_data.nbounce_wait = 23;
-	} else
-		WARN(1, "Unsupported mclk freq %d\n", tabla->mclk_freq);
+	}
 
 	tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
-				      tabla->mbhc_data.nready) + 10;
+				      n_ready[tabla_codec_mclk_index(tabla)]) +
+				     10;
 	tabla->mbhc_data.v_ins_hu =
 	    tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
 	tabla->mbhc_data.v_ins_h =
@@ -3573,10 +3593,11 @@
 
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
-			    n_cic[0]);
+			    n_cic[tabla_codec_mclk_index(tabla)]);
 
 	gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78, gain[0] << 3);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
+			    gain[tabla_codec_mclk_index(tabla)] << 3);
 
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
 			    generic->mbhc_nsa << 4);
@@ -3695,6 +3716,16 @@
 		pr_err("Error: no codec or calibration\n");
 		return -EINVAL;
 	}
+
+	if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
+		if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
+			pr_err("Error: clock rate %dHz is not yet supported\n",
+			       mclk_rate);
+		else
+			pr_err("Error: unsupported clock rate %d\n", mclk_rate);
+		return -EINVAL;
+	}
+
 	tabla = snd_soc_codec_get_drvdata(codec);
 	tabla->headset_jack = headset_jack;
 	tabla->button_jack = button_jack;
@@ -3738,39 +3769,139 @@
 }
 EXPORT_SYMBOL_GPL(tabla_hs_detect);
 
+static int tabla_determine_button(const struct tabla_priv *priv,
+				  const s32 bias_mv)
+{
+	s16 *v_btn_low, *v_btn_high;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	int i, btn = -1;
+
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+	v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
+	v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
+					       TABLA_BTN_DET_V_BTN_HIGH);
+	for (i = 0; i < btn_det->num_btn; i++) {
+		if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
+			btn = i;
+			break;
+		}
+	}
+
+	if (btn == -1)
+		pr_debug("%s: couldn't find button number for mic mv %d\n",
+			 __func__, bias_mv);
+
+	return btn;
+}
+
+static int tabla_get_button_mask(const int btn)
+{
+	int mask = 0;
+	switch (btn) {
+	case 0:
+		mask = SND_JACK_BTN_0;
+		break;
+	case 1:
+		mask = SND_JACK_BTN_1;
+		break;
+	case 2:
+		mask = SND_JACK_BTN_2;
+		break;
+	case 3:
+		mask = SND_JACK_BTN_3;
+		break;
+	case 4:
+		mask = SND_JACK_BTN_4;
+		break;
+	case 5:
+		mask = SND_JACK_BTN_5;
+		break;
+	case 6:
+		mask = SND_JACK_BTN_6;
+		break;
+	case 7:
+		mask = SND_JACK_BTN_7;
+		break;
+	}
+	return mask;
+}
+
 static irqreturn_t tabla_dce_handler(int irq, void *data)
 {
+	int i, mask;
+	short bias_value_dce;
+	s32 bias_mv_dce;
+	int btn = -1, meas = 0;
 	struct tabla_priv *priv = data;
+	const struct tabla_mbhc_btn_detect_cfg *d =
+	    TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+	short btnmeas[d->n_btn_meas + 1];
 	struct snd_soc_codec *codec = priv->codec;
-	short bias_value;
 
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 	tabla_lock_sleep(priv);
 
-	bias_value = tabla_codec_read_dce_result(codec);
-	pr_debug("%s: button press interrupt, DCE: %d,%d\n",
-		 __func__, bias_value,
-		 tabla_codec_sta_dce_v(codec, 1, bias_value));
+	bias_value_dce = tabla_codec_read_dce_result(codec);
+	bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
 
-	bias_value = tabla_codec_read_sta_result(codec);
-	pr_debug("%s: button press interrupt, STA: %d,%d\n",
-		 __func__, bias_value,
-		 tabla_codec_sta_dce_v(codec, 0, bias_value));
-	/*
-	 * TODO: If button pressed is not button 0,
-	 * report the button press event immediately.
-	 */
-	priv->buttons_pressed |= SND_JACK_BTN_0;
-
-	msleep(100);
-
-	if (schedule_delayed_work(&priv->btn0_dwork,
-				  msecs_to_jiffies(400)) == 0) {
-		WARN(1, "Button pressed twice without release event\n");
-		tabla_unlock_sleep(priv);
+	/* determine pressed button */
+	btnmeas[meas++] = tabla_determine_button(priv, bias_mv_dce);
+	pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
+		 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
+	if (d->n_btn_meas == 0)
+		btn = btnmeas[0];
+	for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
+		bias_value_dce = tabla_codec_sta_dce(codec, 1);
+		bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
+		btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
+		pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
+			 __func__, meas, bias_value_dce, bias_mv_dce,
+			 btnmeas[meas]);
+		/* if large enough measurements are collected,
+		 * start to check if last all n_btn_con measurements were
+		 * in same button low/high range */
+		if (meas + 1 >= d->n_btn_con) {
+			for (i = 0; i < d->n_btn_con; i++)
+				if ((btnmeas[meas] < 0) ||
+				    (btnmeas[meas] != btnmeas[meas - i]))
+					break;
+			if (i == d->n_btn_con) {
+				/* button pressed */
+				btn = btnmeas[meas];
+				break;
+			}
+		}
+		/* if left measurements are less than n_btn_con,
+		 * it's impossible to find button number */
+		if ((d->n_btn_meas - meas) < d->n_btn_con)
+			break;
 	}
 
+	if (btn >= 0) {
+		mask = tabla_get_button_mask(btn);
+		priv->buttons_pressed |= mask;
+
+		msleep(100);
+
+		/* XXX: assuming button 0 has the lowest micbias voltage */
+		if (btn == 0) {
+			if (schedule_delayed_work(&priv->btn0_dwork,
+						  msecs_to_jiffies(400)) == 0) {
+				WARN(1, "Button pressed twice without release"
+				     "event\n");
+				tabla_unlock_sleep(priv);
+			}
+		} else {
+			pr_debug("%s: Reporting short button %d(0x%x) press\n",
+				  __func__, btn, mask);
+			tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
+						  mask);
+		}
+	} else
+		pr_debug("%s: bogus button press, too short press?\n",
+			 __func__);
+
 	return IRQ_HANDLED;
 }
 
@@ -3778,18 +3909,18 @@
 {
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	int ret, mb_v;
+	int ret;
+	short mb_v;
 
-	pr_debug("%s\n", __func__);
+	pr_debug("%s: enter\n", __func__);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 	tabla_lock_sleep(priv);
 
 	if (priv->buttons_pressed & SND_JACK_BTN_0) {
 		ret = cancel_delayed_work(&priv->btn0_dwork);
-
 		if (ret == 0) {
-			pr_debug("%s: Reporting long button release event\n",
-					__func__);
+			pr_debug("%s: Reporting long button 0 release event\n",
+				 __func__);
 			if (priv->button_jack)
 				tabla_snd_soc_jack_report(priv,
 							  priv->button_jack, 0,
@@ -3803,25 +3934,37 @@
 				 __func__, mb_v,
 				 tabla_codec_sta_dce_v(codec, 0, mb_v));
 
-			if (mb_v < -2000 || mb_v > -670)
+			if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
+			    mb_v > (short)priv->mbhc_data.v_ins_hu)
 				pr_debug("%s: Fake buttton press interrupt\n",
-						__func__);
+					 __func__);
 			else if (priv->button_jack) {
-				pr_debug("%s:reporting short button "
+				pr_debug("%s: Reporting short button 0 "
 					 "press and release\n", __func__);
 				tabla_snd_soc_jack_report(priv,
 							  priv->button_jack,
 							  SND_JACK_BTN_0,
 							  SND_JACK_BTN_0);
 				tabla_snd_soc_jack_report(priv,
-							  priv->button_jack,
-							  0, SND_JACK_BTN_0);
+							  priv->button_jack, 0,
+							  SND_JACK_BTN_0);
 			}
 		}
 
 		priv->buttons_pressed &= ~SND_JACK_BTN_0;
 	}
 
+	if (priv->buttons_pressed) {
+		pr_debug("%s:reporting button release mask 0x%x\n", __func__,
+			 priv->buttons_pressed);
+		tabla_snd_soc_jack_report(priv, priv->button_jack, 0,
+					  priv->buttons_pressed);
+		/* hardware doesn't detect another button press until
+		 * already pressed button is released.
+		 * therefore buttons_pressed has only one button's mask. */
+		priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
+	}
+
 	tabla_codec_start_hs_polling(codec);
 	tabla_unlock_sleep(priv);
 	return IRQ_HANDLED;
@@ -3859,8 +4002,8 @@
 
 	if (!tabla->mclk_enabled) {
 		snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
-		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
-		tabla_codec_enable_clock_block(codec, 0);
+		tabla_codec_disable_clock_block(codec);
+		tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
 	}
 
 	tabla->mbhc_polling_active = false;
@@ -4131,12 +4274,15 @@
 
 static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
 {
+	short bias_value;
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
 	const struct tabla_mbhc_general_cfg *generic =
 	    TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
-	short bias_value;
+	int fake_removal = 0;
+	int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
 
+	pr_debug("%s: enter, removal interrupt\n", __func__);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
@@ -4145,11 +4291,18 @@
 	usleep_range(generic->t_shutdown_plug_rem,
 		     generic->t_shutdown_plug_rem);
 
-	bias_value = tabla_codec_sta_dce(codec, 1);
-	pr_debug("removal interrupt, DCE: %d,%d\n",
-		 bias_value, tabla_codec_sta_dce_v(codec, 1, bias_value));
+	do {
+		bias_value = tabla_codec_sta_dce(codec, 1);
+		pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
+			 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
+		if (bias_value < (short)priv->mbhc_data.v_ins_h) {
+			fake_removal = 1;
+			break;
+		}
+		min_us -= priv->mbhc_data.t_dce;
+	} while (min_us > 0);
 
-	if (bias_value < (short) priv->mbhc_data.v_ins_h) {
+	if (fake_removal) {
 		pr_debug("False alarm, headset not actually removed\n");
 		tabla_codec_start_hs_polling(codec);
 	} else {
@@ -4502,10 +4655,6 @@
 		goto err_pdata;
 	}
 
-	/* TODO only enable bandgap when necessary in order to save power */
-	tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
-	tabla_codec_enable_clock_block(codec, 0);
-
 	snd_soc_add_controls(codec, tabla_snd_controls,
 		ARRAY_SIZE(tabla_snd_controls));
 	snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 77bfc73..6f77e9f 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 #include <sound/soc.h>
+#include <sound/jack.h>
 
 #define TABLA_VERSION_1_0	0
 #define TABLA_VERSION_1_1	1
@@ -28,6 +29,11 @@
 #define STA 0
 #define DCE 1
 
+#define TABLA_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+				SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
+				SND_JACK_BTN_4 | SND_JACK_BTN_5 | \
+				SND_JACK_BTN_6 | SND_JACK_BTN_7)
+
 extern const u8 tabla_reg_readable[TABLA_CACHE_SIZE];
 extern const u8 tabla_reg_defaults[TABLA_CACHE_SIZE];
 
@@ -66,7 +72,7 @@
 enum tabla_mbhc_btn_det_mem {
 	TABLA_BTN_DET_V_BTN_LOW,
 	TABLA_BTN_DET_V_BTN_HIGH,
-	TABLA_BTN_DET_V_N_READY,
+	TABLA_BTN_DET_N_READY,
 	TABLA_BTN_DET_N_CIC,
 	TABLA_BTN_DET_GAIN
 };
diff --git a/sound/soc/msm/msm-compr-q6.c b/sound/soc/msm/msm-compr-q6.c
index d0497b1..f0f17a9 100644
--- a/sound/soc/msm/msm-compr-q6.c
+++ b/sound/soc/msm/msm-compr-q6.c
@@ -450,8 +450,37 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct compr_audio *compr = runtime->private_data;
 	struct msm_audio *prtd = &compr->prtd;
+	uint64_t timestamp;
+	uint64_t temp;
 
 	switch (cmd) {
+	case SNDRV_COMPRESS_TSTAMP: {
+		struct snd_compr_tstamp tstamp;
+		pr_debug("SNDRV_COMPRESS_TSTAMP\n");
+
+		memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
+		timestamp = q6asm_get_session_time(prtd->audio_client);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * runtime->channels);
+		temp = temp * (runtime->rate/1000);
+		temp = div_u64(temp, 1000);
+		tstamp.sampling_rate = runtime->rate;
+		tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
+		tstamp.decoded  = (size_t)((temp >> 32) & 0xFFFFFFFF);
+		tstamp.timestamp = timestamp;
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld,\n",
+			 __func__, tstamp.rendered, tstamp.decoded,
+			tstamp.timestamp);
+		if (copy_to_user((void *) arg, &tstamp,
+			sizeof(struct snd_compr_tstamp)))
+				return -EFAULT;
+		return 0;
+	}
 	case SNDRV_COMPRESS_GET_CAPS:
 		pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
 		if (copy_to_user((void *) arg, &compr->info.compr_cap,
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 0dc3b57..75bb75f 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -55,7 +55,7 @@
 
 #define TABLA_EXT_CLK_RATE 12288000
 
-#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_BUTTONS 8
 #define TABLA_MBHC_DEF_RLOADS 5
 
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
@@ -571,7 +571,7 @@
 	void *tabla_cal;
 	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
 	u16 *btn_low, *btn_high;
-	u8 *n_cic, *gain;
+	u8 *n_ready, *n_cic, *gain;
 
 	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
 						TABLA_MBHC_DEF_RLOADS),
@@ -597,20 +597,16 @@
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
 	S(v_no_mic, 30);
-	S(v_hs_max, 1450);
+	S(v_hs_max, 1550);
 #undef S
 #define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
-	S(c[0], 6);
-	S(c[1], 10);
-	S(c[2], 10);
-	S(c[3], 14);
-	S(c[4], 14);
-	S(c[5], 16);
-	S(c[6], 0);
-	S(c[7], 0);
-	S(nc, 5);
-	S(n_meas, 11);
+	S(c[0], 62);
+	S(c[1], 124);
+	S(nc, 1);
+	S(n_meas, 3);
 	S(mbhc_nsc, 11);
+	S(n_btn_meas, 1);
+	S(n_btn_con, 2);
 	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
 	S(v_btn_press_delta_sta, 100);
 	S(v_btn_press_delta_cic, 50);
@@ -618,15 +614,28 @@
 	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
 	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
 	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
-	btn_low[0] = 0;
-	btn_high[0] = 40;
-	btn_low[1] = 60;
-	btn_high[1] = 140;
-	btn_low[2] = 160;
-	btn_high[2] = 240;
+	btn_low[0] = -50;
+	btn_high[0] = 10;
+	btn_low[1] = 11;
+	btn_high[1] = 38;
+	btn_low[2] = 39;
+	btn_high[2] = 64;
+	btn_low[3] = 65;
+	btn_high[3] = 91;
+	btn_low[4] = 92;
+	btn_high[4] = 115;
+	btn_low[5] = 116;
+	btn_high[5] = 141;
+	btn_low[6] = 142;
+	btn_high[6] = 163;
+	btn_low[7] = 164;
+	btn_high[7] = 250;
+	n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
+	n_ready[0] = 48;
+	n_ready[1] = 38;
 	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
-	n_cic[0] = 120;
-	n_cic[1] = 94;
+	n_cic[0] = 60;
+	n_cic[1] = 47;
 	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
 	gain[0] = 11;
 	gain[1] = 9;
@@ -668,15 +677,16 @@
 	snd_soc_dapm_sync(dapm);
 
 	err = snd_soc_jack_new(codec, "Headset Jack",
-		(SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
-		&hs_jack);
+			       (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
+				SND_JACK_OC_HPHR),
+			       &hs_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;
 	}
 
 	err = snd_soc_jack_new(codec, "Button Jack",
-				SND_JACK_BTN_0, &button_jack);
+			       TABLA_JACK_BUTTON_MASK, &button_jack);
 	if (err) {
 		pr_err("failed to create new jack\n");
 		return err;
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index d8d9c64..177e1d8 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -615,7 +615,7 @@
 	if (afe_validate_port(port_id) < 0)
 		return -EINVAL;
 
-	pr_info("%s port_id=%d index %d\n", __func__, port_id, index);
+	pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
 
 	if (!(atomic_read(&this_adm.copp_cnt[index]))) {
 		pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index a214529..302ef57 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -386,7 +386,7 @@
 		ret = -EINVAL;
 		return ret;
 	}
-	pr_info("%s: %d %d\n", __func__, port_id, rate);
+	pr_debug("%s: %d %d\n", __func__, port_id, rate);
 
 	if ((port_id == RT_PROXY_DAI_001_RX) ||
 		(port_id == RT_PROXY_DAI_002_TX))
@@ -1428,7 +1428,7 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	pr_info("%s: port_id=%d\n", __func__, port_id);
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
 	port_id = afe_convert_virtual_to_portid(port_id);
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
@@ -1466,7 +1466,7 @@
 		ret = -EINVAL;
 		goto fail_cmd;
 	}
-	pr_info("%s: port_id=%d\n", __func__, port_id);
+	pr_debug("%s: port_id=%d\n", __func__, port_id);
 	port_id = afe_convert_virtual_to_portid(port_id);
 
 	stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,