Merge "msm: defconfig: enable SMD on 9625"
diff --git a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
index 5b4d3cf..b7dd427 100644
--- a/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
+++ b/Documentation/devicetree/bindings/arm/msm/dcvs-core-info.txt
@@ -7,10 +7,14 @@
 
 - qcom,core-core-type:	indicates whether this core is a CPU(0) or a GPU(1)
 
+- qcom,num-cores:	The number of cores this entry represents
+- qcom,sensors:		The vector of sensor ids for the cores
+
 - qcom,algo-disable-pc-threshold:	sets highest frequency at which DCVS
 					will allow the CPU to power collapse.
 - qcom,algo-em-win-size-min-us:		sets minimum Energy Minimization(EM)
 					window size.
+
 - qcom,algo-em-win-size-max-us:		sets maximum EM window size.
 - qcom,algo-em-max-util-pct:		sets maximum CPU utilization that will
 					not be exceeded by any core when
@@ -67,7 +71,7 @@
 
 			compatible = "qcom,dcvs-core-info";
 
-			qcom,num_cores = <1>;
+			qcom,num-cores = <1>;
 			qcom,sensors = <0>;
 
 			qcom,core-core-type = <1>;
diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index 16925fb..38b2721 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -62,6 +62,7 @@
 - qcom,chipid:		   If it exists this property is used to replace
 			   the chip identification read from the GPU hardware.
 			   This is used to override faulty hardware readings.
+- qcom,strtstp-sleepwake:  Boolean. Enables use of GPU SLUMBER instead of SLEEP for power savings
 
 Example of A330 GPU in MSM8974:
 
diff --git a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
index 21d376a..adb93b8 100644
--- a/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
+++ b/Documentation/devicetree/bindings/platform/msm/qpnp-power-on.txt
@@ -11,18 +11,24 @@
 - compatible:	Must be "qcom,qpnp-power-on"
 - reg:		Specifies the SPMI address and size for this PON (power-on) peripheral
 - interrupts:	Specifies the interrupt associated with PON.
+- interrupt-names:	Specify the interrupt names associated with interrupts. Must be
+			one of "kpdpwr", "kpdpwr-bark", "resin", "resin-bark", "cblpwr".
+			Bark interrupts are associated with system reset configuration
+			to allow default reset configuration to be activated. If system
+			reset configuration is not supported then bark interrupts are
+			nops.
 
 Optional properties:
-- qcom,pon-dbc-delay		The debouce delay for the power-key interrupt
-				specifed in us. The value ranges from 2 seconds
+- qcom,pon-dbc-delay		The debounce delay for the power-key interrupt
+				specified in us. The value ranges from 2 seconds
 				to 1/64 of a second. Possible values are -
 				- 2, 1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64
 				- Intermediate value is rounded down to the
 				nearest valid value.
 - qcom,pon_1 ...pon_n		These represent the child nodes which describe
 				the properties (reset, key) for each of the pon
-				reset source. All the child nodes are optional,
-				if none of them are specified the driver fails
+				reset source. All the child nodes are optional.
+				If none of them is specified, the driver fails
 				to register.
 - qcom,system-reset		Specifies that this PON peripheral can be used
 				to reset the system. This property can only be
@@ -32,32 +38,32 @@
 All the below properties are in the sub-node section (properties of the child
 node).
 
+Sub-node required properties:
+- qcom,pon-type			The type of PON/RESET source. The driver
+				currently supports KPDPWR(0), RESIN(1) and
+				CBLPWR(2) pon/reset sources.
+
+Sub-node optional properties:
 - qcom,pull-up			The initial state of the reset pin under
 				consideration.
 				0 = No pull-up
 				1 = pull-up enabled
-				This property is optional and is set to '0'
-				if not specified.
-- qcom,pon-type			The type of PON/RESET source. The driver
-				currently supports KPDPWR(0) and RESIN(1)
-				pon/reset sources. This property must be
-				specified.
+				This property is set to '0' if not specified.
 - qcom,support-reset		Indicates if this PON source supports
 				reset functionality.
 				0 = Not supported
 				1 = Supported
-				This property is optional and is set to '0'
-				if not specified.
-- qcom,s1-timer			The debouce timer for the BARK interrupt for
+				This property is set to '0' if not specified.
+- qcom,s1-timer			The debounce timer for the BARK interrupt for
 				that reset source. Value is specified in ms.
 				Supported values are -
 				- 0, 32, 56, 80, 128, 184, 272, 408, 608, 904
 				  1352, 2048, 3072, 4480, 6720, 10256
 				This property must be specified only if
 				'support-reset' is set to 1.
-- qcom,s2-timer			The debouce timer for the S2 reset specified
+- qcom,s2-timer			The debounce timer for the S2 reset specified
 				in ms. On the expiry of this timer, the PMIC
-				executes the reset sequence. Supoprted values -
+				executes the reset sequence. Supported values -
 				- 0, 10, 50, 100, 250, 500, 1000, 2000
 				This property is required only if
 				'support-reset' is set to 1.
@@ -68,7 +74,7 @@
 				'support-reset' is set to 1.
 - linux,code			The input key-code associated with the reset source.
 				The reset source in its default configuration can be
-				used to support standard keys. This property is optional.
+				used to support standard keys.
 
 Example:
 	qcom,power-on@800 {
diff --git a/arch/arm/boot/dts/msm-pm8019.dtsi b/arch/arm/boot/dts/msm-pm8019.dtsi
index 3b06450..e70eb36 100755
--- a/arch/arm/boot/dts/msm-pm8019.dtsi
+++ b/arch/arm/boot/dts/msm-pm8019.dtsi
@@ -22,6 +22,21 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		qcom,power_on@800 {
+			compatible = "qcom,qpnp-power-on";
+			reg = <0x800 0x100>;
+			interrupts = <0x0 0x8 0x2>;
+			interrupt-names = "cblpwr";
+			qcom,pon-dbc-delay = <15625>;
+			qcom,system-reset;
+
+			qcom,pon_1 {
+				qcom,pon-type = <2>;
+				qcom,pull-up = <1>;
+				linux,code = <116>;
+			};
+		};
+
 		clkdiv@5b00 {
 			reg = <0x5b00 0x100>;
 			compatible = "qcom,qpnp-clkdiv";
diff --git a/arch/arm/boot/dts/msm8974-gpu.dtsi b/arch/arm/boot/dts/msm8974-gpu.dtsi
index 017aea9..6d00b01 100644
--- a/arch/arm/boot/dts/msm8974-gpu.dtsi
+++ b/arch/arm/boot/dts/msm8974-gpu.dtsi
@@ -25,6 +25,7 @@
 
 		qcom,idle-timeout = <83>; //<HZ/12>
 		qcom,nap-allowed = <1>;
+		qcom,strtstp-sleepwake;
 		qcom,clk-map = <0x00000016>; //KGSL_CLK_CORE | KGSL_CLK_IFACE | KGSL_CLK_MEM_IFACE
 
 		/* Bus Scale Settings */
@@ -85,6 +86,9 @@
 
 			compatible = "qcom,dcvs-core-info";
 
+			qcom,num-cores = <1>;
+			qcom,sensors = <0>;
+
 			qcom,core-core-type = <1>;
 
 			qcom,algo-disable-pc-threshold = <0>;
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 1893ae4..9b5aaac 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -70,7 +70,7 @@
 			reg = <28>;
 			qcom,heap-align = <0x1000>;
 			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
-			qcom,memory-reservation-size = <0x2B4000>;
+			qcom,memory-reservation-size = <0x314000>;
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm9625-ion.dtsi b/arch/arm/boot/dts/msm9625-ion.dtsi
new file mode 100644
index 0000000..8183264
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-ion.dtsi
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+	qcom,ion {
+		compatible = "qcom,msm-ion";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		qcom,ion-heap@30 { /* SYSTEM HEAP */
+			reg = <30>;
+		};
+
+		qcom,ion-heap@25 { /* IOMMU HEAP */
+			reg = <25>;
+		};
+
+		qcom,ion-heap@28 { /* AUDIO HEAP */
+			compatible = "qcom,msm-ion-reserve";
+			reg = <28>;
+			qcom,heap-align = <0x1000>;
+			qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
+			qcom,memory-reservation-size = <0xAF000>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f50d14f..a8a2bf1 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -11,6 +11,7 @@
  */
 
 /include/ "skeleton.dtsi"
+/include/ "msm9625-ion.dtsi"
 
 / {
 	model = "Qualcomm MSM 9625";
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 9dd4347..6b8a374 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -1167,41 +1167,35 @@
 /*
  * Configure the GIC after we come out of power collapse.
  * This function will configure some of the GIC registers so as to prepare the
- * core1 to receive an SPI(ACSR_MP_CORE_IPC1, (32 + 8)), which will bring
- * core1 out of GDFS.
+ * secondary cores to receive an SPI(ACSR_MP_CORE_IPC1/IPC2/IPC3, 40/92/93),
+ * which will bring cores out of GDFS.
  */
-void core1_gic_configure_and_raise(void)
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu)
 {
 	struct gic_chip_data *gic = &gic_data[0];
+	struct irq_data *d = irq_get_irq_data(irq);
 	void __iomem *base = gic_data_dist_base(gic);
-	unsigned int value = 0;
+	unsigned int value = 0, byte_offset, offset, bit;
 	unsigned long flags;
 
+	offset = ((gic_irq(d) / 32) * 4);
+	bit = BIT(gic_irq(d) % 32);
+
 	raw_spin_lock_irqsave(&irq_controller_lock, flags);
 
-	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, base + GIC_DIST_ACTIVE_BIT + 0x4);
+	value = __raw_readl(base + GIC_DIST_ACTIVE_BIT + offset);
+	__raw_writel(value | bit, base + GIC_DIST_ACTIVE_BIT + offset);
 	mb();
 
-	value = __raw_readl(base + GIC_DIST_TARGET + 0x24);
-	value |= BIT(13);
-	__raw_writel(value, base + GIC_DIST_TARGET + 0x24);
+	value = __raw_readl(base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
+	byte_offset = (gic_irq(d) % 4) * 8;
+	value |= 1 << (cpu + byte_offset);
+	__raw_writel(value, base + GIC_DIST_TARGET + (gic_irq(d) / 4) * 4);
 	mb();
 
-	value = __raw_readl(base + GIC_DIST_TARGET + 0x28);
-	value |= BIT(1);
-	__raw_writel(value, base + GIC_DIST_TARGET + 0x28);
+	value =  __raw_readl(base + GIC_DIST_ENABLE_SET + offset);
+	__raw_writel(value | bit, base + GIC_DIST_ENABLE_SET + offset);
 	mb();
 
-	value =  __raw_readl(base + GIC_DIST_ENABLE_SET + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, base + GIC_DIST_ENABLE_SET + 0x4);
-	mb();
-
-	value =  __raw_readl(base + GIC_DIST_PENDING_SET + 0x4);
-	value |= BIT(8);
-	__raw_writel(value, base + GIC_DIST_PENDING_SET + 0x4);
-	mb();
 	raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index d96a006..5984535 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -115,6 +115,7 @@
 CONFIG_USB_BAM=y
 CONFIG_SPS_SUPPORT_BAMDMA=y
 CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_POWER_ON=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_YAFFS_FS=y
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index ad12bcd..72c3c27 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -62,7 +62,7 @@
 
 void msm_gic_save(void);
 void msm_gic_restore(void);
-void core1_gic_configure_and_raise(void);
+void gic_configure_and_raise(unsigned int irq, unsigned int cpu);
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 2020422..6f5528e 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -359,6 +359,20 @@
 	select GPIO_MSM_V3
 	select MAY_HAVE_SPARSE_IRQ
 	select SPARSE_IRQ
+
+config ARCH_MSM8910
+	bool "MSM8910"
+	select ARM_GIC
+	select GIC_SECURE
+	select SMP
+	select ARCH_MSM_CORTEXMP
+	select CPU_V7
+	select MSM_SCM if SMP
+	select MAY_HAVE_SPARSE_IRQ
+	select SPARSE_IRQ
+	select MULTI_IRQ_HANDLER
+	select GPIO_MSM_V3
+	select MSM_GPIOMUX
 endmenu
 
 choice
@@ -926,6 +940,7 @@
 	default "0x00000000" if ARCH_MSM8974
 	default "0x00000000" if ARCH_MPQ8092
 	default "0x00000000" if ARCH_MSM8226
+	default "0x00000000" if ARCH_MSM8910
 	default "0x10000000" if ARCH_FSM9XXX
 	default "0x00200000" if ARCH_MSM9625
 	default "0x00200000" if !MSM_STACKED_MEMORY
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index 3be7fc6..c7075bc 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -32,6 +32,8 @@
 
 static struct msm_dcvs_core_info grp3d_core_info = {
 	.freq_tbl	= &grp3d_freq[0],
+	.num_cores	= 1,
+	.sensors	= (int[]){0},
 	.core_param	= {
 		.core_type	= MSM_DCVS_CORE_TYPE_GPU,
 	},
diff --git a/arch/arm/mach-msm/board-8930-regulator-pm8917.c b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
index db40e5d..b7f554c 100644
--- a/arch/arm/mach-msm/board-8930-regulator-pm8917.c
+++ b/arch/arm/mach-msm/board-8930-regulator-pm8917.c
@@ -547,7 +547,7 @@
 	RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL,      0, 1p60, NONE, NONE),
 	RPM_SMPS(S3, 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80, AUTO, LPM),
 	RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, LPM),
-	RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, NONE, NONE),
+	RPM_SMPS(S7, 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20, AUTO, AUTO),
 	RPM_SMPS(S8, 1, 1, 1, 2050000, 2050000, NULL, 100000, 1p60, NONE, NONE),
 
 	/*	ID     a_on pd ss min_uV   max_uV  supply  sys_uA init_ip */
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index e8baf6a..3cd4b2f 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2671,6 +2671,8 @@
 
 static struct msm_dcvs_core_info apq8064_core_info = {
 	.freq_tbl	= &apq8064_freq[0],
+	.num_cores	= 4,
+	.sensors	= (int[]){7, 8, 9, 10},
 	.core_param	= {
 		.core_type	= MSM_DCVS_CORE_TYPE_CPU,
 	},
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index 8b59b14..614037c 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -33,6 +33,6 @@
 void __init msm8x25_spm_device_init(void);
 void __init msm_pm_register_cpr_ops(void);
 void __init msm8x25_kgsl_3d0_init(void);
-void __iomem *core1_reset_base(void);
+void __iomem *core_reset_base(unsigned int);
 extern void setup_mm_for_reboot(void);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_dcvs.h b/arch/arm/mach-msm/include/mach/msm_dcvs.h
index 490a34b..3ac0e74 100644
--- a/arch/arm/mach-msm/include/mach/msm_dcvs.h
+++ b/arch/arm/mach-msm/include/mach/msm_dcvs.h
@@ -46,6 +46,17 @@
 };
 
 /**
+ * struct msm_dcvs_freq
+ *
+ * API for clock driver code to register and receive frequency change
+ * request for the core from the msm_dcvs driver.
+ */
+struct msm_dcvs_freq {
+	const char *core_name;
+	/* Callback from msm_dcvs to set the core frequency */
+};
+
+/**
  * msm_dcvs_idle_source_register
  * @drv: Pointer to the source driver
  * @return: Handle to be used for sending idle state notifications.
@@ -90,6 +101,8 @@
  * before the sink driver can be registered.
  */
 struct msm_dcvs_core_info {
+	int					num_cores;
+	int					*sensors;
 	struct msm_dcvs_freq_entry		*freq_tbl;
 	struct msm_dcvs_core_param		core_param;
 	struct msm_dcvs_algo_param		algo_param;
@@ -101,6 +114,7 @@
  * msm_dcvs_register_core
  * @core_name: Unique name identifier for the core.
  * @info: The core specific algorithm parameters.
+ * @sensor: The thermal sensor number of the core in question
  * @return :
  *	0 on success,
  *	-ENOSYS,
@@ -110,35 +124,25 @@
  * msm_dcvs_freq_sink_register
  * Cores that need to run synchronously must share the same group id.
  */
-extern int msm_dcvs_register_core(const char *core_name,
-		struct msm_dcvs_core_info *info);
+extern int msm_dcvs_register_core(
+	const char *core_name,
+	struct msm_dcvs_core_info *info,
+	int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
+	int sensor);
 
 /**
- * struct msm_dcvs_freq
- *
- * API for clock driver code to register and receive frequency change
- * request for the core from the msm_dcvs driver.
- */
-struct msm_dcvs_freq {
-	const char *core_name;
-	/* Callback from msm_dcvs to set the core frequency */
-	int (*set_frequency)(struct msm_dcvs_freq *self,
-			unsigned int freq);
-	unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
-};
-
-/**
- * msm_dcvs_freq_sink_register
+ * msm_dcvs_freq_sink_start
  * @drv: The sink driver
  * @return: Handle unique to the core.
  *
  * Register the clock driver code with the msm_dvs driver to get notified about
  * frequency change requests.
  */
-extern int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv);
 
 /**
- * msm_dcvs_freq_sink_unregister
+ * msm_dcvs_freq_sink_stop
  * @drv: The sink driver
  * @return:
  *	0 on success,
@@ -147,6 +151,13 @@
  * Unregister the sink driver for the core. This will cause the source driver
  * for the core to stop sending idle pulses.
  */
-extern int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv);
+extern int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv);
 
+/**
+ * msm_dcvs_update_limits
+ * @drv: The sink driver
+ *
+ * Update the frequency known to dcvs when the limits are changed.
+ */
+extern void msm_dcvs_update_limits(struct msm_dcvs_freq *drv);
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8910.h b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
new file mode 100644
index 0000000..e4cd312
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-8910.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __ASM_ARCH_MSM_IOMAP_8910_H
+#define __ASM_ARCH_MSM_IOMAP_8910_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM8910_MSM_SHARED_RAM_PHYS	0x0FA00000
+
+#define MSM8910_APCS_GCC_PHYS	0xF9011000
+#define MSM8910_APCS_GCC_SIZE	SZ_4K
+
+#define MSM8910_TLMM_PHYS	0xFD510000
+#define MSM8910_TLMM_SIZE	SZ_16K
+
+#define MSM8910_IMEM_PHYS	0xFC42B000
+#define MSM8910_IMEM_SIZE	SZ_4K
+
+#ifdef CONFIG_DEBUG_MSM8910_UART
+#define MSM_DEBUG_UART_BASE	IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS	0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 8dbd29c..f372b1e 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -54,7 +54,7 @@
 	defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
 	defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
 	defined(CONFIG_ARCH_MSM9625) || defined(CONFIG_ARCH_MPQ8092) || \
-	defined(CONFIG_ARCH_MSM8226)
+	defined(CONFIG_ARCH_MSM8226) || defined(CONFIG_ARCH_MSM8910)
 
 /* Unified iomap */
 
@@ -122,6 +122,7 @@
 #include "msm_iomap-9625.h"
 #include "msm_iomap-8092.h"
 #include "msm_iomap-8226.h"
+#include "msm_iomap-8910.h"
 
 #else
 /* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index 225440c..86045b9 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -54,6 +54,12 @@
 	of_machine_is_compatible("qcom,msm8226")
 #define machine_is_msm8226_sim()		\
 	of_machine_is_compatible("qcom,msm8226-sim")
+#define early_machine_is_msm8910()	\
+	of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8910")
+#define machine_is_msm8910()		\
+	of_machine_is_compatible("qcom,msm8910")
+#define machine_is_msm8910_sim()		\
+	of_machine_is_compatible("qcom,msm8910-sim")
 #else
 #define early_machine_is_msm8974()	0
 #define machine_is_msm8974()		0
@@ -66,6 +72,9 @@
 #define early_machine_is_msm8226()	0
 #define machine_is_msm8226()		0
 #define machine_is_msm8226_sim()	0
+#define early_machine_is_msm8910()	0
+#define machine_is_msm8910()		0
+#define machine_is_msm8910_sim()	0
 
 #endif
 
@@ -99,7 +108,8 @@
 	MSM_CPU_8625,
 	MSM_CPU_9625,
 	MSM_CPU_8092,
-	MSM_CPU_8226
+	MSM_CPU_8226,
+	MSM_CPU_8910,
 };
 
 enum pmic_model {
@@ -415,4 +425,15 @@
 #endif
 }
 
+static inline int cpu_is_msm8910(void)
+{
+#ifdef CONFIG_ARCH_MSM8910
+	enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+	BUG_ON(cpu == MSM_CPU_UNKNOWN);
+	return cpu == MSM_CPU_8910;
+#else
+	return 0;
+#endif
+}
 #endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 39ac253..8ebead8 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -529,3 +529,22 @@
 	msm_map_io(msm_8226_io_desc, ARRAY_SIZE(msm_8226_io_desc));
 }
 #endif /* CONFIG_ARCH_MSM8226 */
+
+#ifdef CONFIG_ARCH_MSM8910
+static struct map_desc msm8910_io_desc[] __initdata = {
+	MSM_CHIP_DEVICE(APCS_GCC, MSM8910),
+	MSM_CHIP_DEVICE(TLMM, MSM8910),
+	MSM_CHIP_DEVICE(IMEM, MSM8910),
+	{
+		.virtual =  (unsigned long) MSM_SHARED_RAM_BASE,
+		.length =   MSM_SHARED_RAM_SIZE,
+		.type =     MT_DEVICE,
+	},
+};
+
+void __init msm_map_msm8910_io(void)
+{
+	msm_shared_ram_phys = MSM8910_MSM_SHARED_RAM_PHYS;
+	msm_map_io(msm8910_io_desc, ARRAY_SIZE(msm8910_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8910 */
diff --git a/arch/arm/mach-msm/msm_dcvs.c b/arch/arm/mach-msm/msm_dcvs.c
index 9601b7e..288d6bb 100644
--- a/arch/arm/mach-msm/msm_dcvs.c
+++ b/arch/arm/mach-msm/msm_dcvs.c
@@ -23,6 +23,7 @@
 #include <linux/spinlock.h>
 #include <linux/stringify.h>
 #include <linux/debugfs.h>
+#include <linux/msm_tsens.h>
 #include <asm/atomic.h>
 #include <asm/page.h>
 #include <mach/msm_dcvs.h>
@@ -73,7 +74,6 @@
 
 struct dcvs_core {
 	char core_name[CORE_NAME_MAX];
-	uint32_t new_freq[MAX_PENDING];
 	uint32_t actual_freq;
 	uint32_t freq_change_us;
 
@@ -91,19 +91,21 @@
 	struct task_struct *task;
 	struct core_attribs attrib;
 	uint32_t handle;
-	uint32_t freq_pending;
 	struct hrtimer timer;
 	int32_t timer_disabled;
-	/* track if kthread for change_freq is active */
-	int32_t change_freq_activated;
 	struct msm_dcvs_core_info *info;
+	int sensor;
+	int pending_freq;
+	wait_queue_head_t wait_q;
+	int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq);
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self);
 };
 
 static int msm_dcvs_debug;
 static int msm_dcvs_enabled = 1;
 module_param_named(enable, msm_dcvs_enabled, int, S_IRUGO | S_IWUSR | S_IWGRP);
 
-static struct dentry *debugfs_base;
+static struct dentry		*debugfs_base;
 
 static struct dcvs_core core_list[CORES_MAX];
 static DEFINE_MUTEX(core_list_lock);
@@ -123,28 +125,16 @@
 	uint32_t slack_us = 0;
 	uint32_t ret1 = 0;
 
-	if (!core->freq_driver || !core->freq_driver->set_frequency) {
+	if (!core->freq_driver || !core->set_frequency) {
 		/* Core may have unregistered or hotplugged */
 		return -ENODEV;
 	}
-repeat:
 	spin_lock_irqsave(&core->cpu_lock, flags);
-	if (unlikely(!core->freq_pending)) {
-		spin_unlock_irqrestore(&core->cpu_lock, flags);
-		return ret;
-	}
-	requested_freq = core->new_freq[core->freq_pending - 1];
-	if (unlikely(core->freq_pending > 1) &&
-		(msm_dcvs_debug & MSM_DCVS_DEBUG_FREQ_CHANGE)) {
-		int i;
-		for (i = 0; i < core->freq_pending - 1; i++) {
-			__info("Core %s missing freq %u\n",
-				core->core_name, core->new_freq[i]);
-		}
-	}
+repeat:
+
+	requested_freq = core->pending_freq;
 	time_start = core->time_start;
 	core->time_start = 0;
-	core->freq_pending = 0;
 	/**
 	 * Cancel the timers, we dont want the timer firing as we are
 	 * changing the clock rate. Dont let idle_exit and others setup
@@ -152,18 +142,18 @@
 	 */
 	hrtimer_cancel(&core->timer);
 	core->timer_disabled = 1;
+	if (requested_freq == core->actual_freq)
+		goto out;
+
 	spin_unlock_irqrestore(&core->cpu_lock, flags);
 
-	if (requested_freq == core->actual_freq)
-		return ret;
 
 	/**
 	 * Call the frequency sink driver to change the frequency
 	 * We will need to get back the actual frequency in KHz and
 	 * the record the time taken to change it.
 	 */
-	ret = core->freq_driver->set_frequency(core->freq_driver,
-				requested_freq);
+	ret = core->set_frequency(core->freq_driver, requested_freq);
 	if (ret <= 0) {
 		__err("Core %s failed to set freq %u\n",
 				core->core_name, requested_freq);
@@ -229,14 +219,40 @@
 			core->actual_freq, prev_freq,
 			core->freq_change_us, slack_us);
 
+	spin_lock_irqsave(&core->cpu_lock, flags);
 	/**
 	 * By the time we are done with freq changes, we could be asked to
 	 * change again. Check before exiting.
 	 */
-	if (core->freq_pending)
+	if (core->pending_freq)
 		goto repeat;
 
-	core->change_freq_activated = 0;
+
+out: /* should always be jumped to with the spin_lock held */
+	core->pending_freq = 0;
+	spin_unlock_irqrestore(&core->cpu_lock, flags);
+
+	return ret;
+}
+
+static int __msm_dcvs_report_temp(struct dcvs_core *core)
+{
+	struct msm_dcvs_core_info *info = core->info;
+	struct tsens_device tsens_dev;
+	int ret;
+	unsigned long temp = 0;
+
+	tsens_dev.sensor_num = core->sensor;
+	ret = tsens_get_temp(&tsens_dev, &temp);
+	if (!ret) {
+		tsens_dev.sensor_num = 0;
+		ret = tsens_get_temp(&tsens_dev, &temp);
+		if (!ret)
+			return -ENODEV;
+	}
+
+	ret = msm_dcvs_scm_set_power_params(core->handle, &info->power_param,
+			&info->freq_tbl[0], &core->coeffs);
 	return ret;
 }
 
@@ -246,23 +262,21 @@
 	static struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1};
 
 	sched_setscheduler(current, SCHED_FIFO, &param);
-	set_current_state(TASK_UNINTERRUPTIBLE);
 
 	while (!kthread_should_stop()) {
-		mutex_lock(&core->lock);
-		__msm_dcvs_change_freq(core);
-		mutex_unlock(&core->lock);
-
-		schedule();
+		wait_event(core->wait_q, !(core->pending_freq == 0 ||
+					  core->pending_freq == -1) ||
+					  kthread_should_stop());
 
 		if (kthread_should_stop())
 			break;
 
-		set_current_state(TASK_UNINTERRUPTIBLE);
+		mutex_lock(&core->lock);
+		__msm_dcvs_change_freq(core);
+		__msm_dcvs_report_temp(core);
+		mutex_unlock(&core->lock);
 	}
 
-	__set_current_state(TASK_RUNNING);
-
 	return 0;
 }
 
@@ -278,33 +292,25 @@
 	ret = msm_dcvs_scm_event(core->handle, event, param0,
 				core->actual_freq, &new_freq, ret1);
 	if (ret) {
-		__err("Error (%d) sending SCM event %d for core %s\n",
+		if (ret == -13)
+			ret = 0;
+		else
+			__err("Error (%d) sending SCM event %d for core %s\n",
 				ret, event, core->core_name);
-		goto freq_done;
+		goto out;
 	}
 
-	if ((core->actual_freq != new_freq) &&
-			(core->new_freq[core->freq_pending] != new_freq)) {
-		if (core->freq_pending >= MAX_PENDING - 1)
-			core->freq_pending = MAX_PENDING - 1;
-		core->new_freq[core->freq_pending++] = new_freq;
+	if (core->actual_freq != new_freq && core->pending_freq != new_freq) {
+		core->pending_freq = new_freq;
 		core->time_start = ktime_to_ns(ktime_get());
 
-		/* Schedule the frequency change */
-		if (!core->task)
-			__err("Uninitialized task for core %s\n",
-					core->core_name);
-		else {
-			if (freq_changed)
-				*freq_changed = 1;
-			core->change_freq_activated = 1;
-			wake_up_process(core->task);
-		}
+		if (core->task)
+			wake_up(&core->wait_q);
 	} else {
 		if (freq_changed)
 			*freq_changed = 0;
 	}
-freq_done:
+out:
 	spin_unlock_irqrestore(&core->cpu_lock, flags);
 
 	return ret;
@@ -571,7 +577,10 @@
 }
 
 int msm_dcvs_register_core(const char *core_name,
-		struct msm_dcvs_core_info *info)
+	struct msm_dcvs_core_info *info,
+	int (*set_frequency)(struct msm_dcvs_freq *self, unsigned int freq),
+	unsigned int (*get_frequency)(struct msm_dcvs_freq *self),
+	int sensor)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
@@ -587,6 +596,9 @@
 
 	mutex_lock(&core->lock);
 
+	core->set_frequency = set_frequency;
+	core->get_frequency = get_frequency;
+
 	core->info = info;
 	memcpy(&core->algo_param, &info->algo_param,
 			sizeof(struct msm_dcvs_algo_param));
@@ -594,6 +606,9 @@
 	memcpy(&core->coeffs, &info->energy_coeffs,
 			sizeof(struct msm_dcvs_energy_curve_coeffs));
 
+	pr_debug("registering core with sensor %d\n", sensor);
+	core->sensor = sensor;
+
 	ret = msm_dcvs_scm_register_core(core->handle, &info->core_param);
 	if (ret)
 		goto bail;
@@ -618,14 +633,27 @@
 		core_handles[core->handle - CORE_HANDLE_OFFSET] = NULL;
 		goto bail;
 	}
-
+	init_waitqueue_head(&core->wait_q);
+	core->task = kthread_run(msm_dcvs_do_freq, (void *)core,
+			"msm_dcvs/%d", core->handle);
 bail:
 	mutex_unlock(&core->lock);
 	return ret;
 }
 EXPORT_SYMBOL(msm_dcvs_register_core);
 
-int msm_dcvs_freq_sink_register(struct msm_dcvs_freq *drv)
+void msm_dcvs_update_limits(struct msm_dcvs_freq *drv)
+{
+	struct dcvs_core *core;
+
+	if (!drv || !drv->core_name)
+		return;
+
+	core = msm_dcvs_get_core(drv->core_name, false);
+	core->actual_freq = core->get_frequency(drv);
+}
+
+int msm_dcvs_freq_sink_start(struct msm_dcvs_freq *drv)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
@@ -644,8 +672,6 @@
 		__info("Frequency notifier for %s being replaced\n",
 				core->core_name);
 	core->freq_driver = drv;
-	core->task = kthread_create(msm_dcvs_do_freq, (void *)core,
-			"msm_dcvs/%d", core->handle);
 	if (IS_ERR(core->task)) {
 		mutex_unlock(&core->lock);
 		return -EFAULT;
@@ -655,7 +681,7 @@
 		__info("Enabling idle pulse for %s\n", core->core_name);
 
 	if (core->idle_driver) {
-		core->actual_freq = core->freq_driver->get_frequency(drv);
+		core->actual_freq = core->get_frequency(drv);
 		/* Notify TZ to start receiving idle info for the core */
 		ret = msm_dcvs_update_freq(core, MSM_DCVS_SCM_DCVS_ENABLE, 1,
 					   &ret1, &ret2);
@@ -667,9 +693,9 @@
 
 	return core->handle;
 }
-EXPORT_SYMBOL(msm_dcvs_freq_sink_register);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_start);
 
-int msm_dcvs_freq_sink_unregister(struct msm_dcvs_freq *drv)
+int msm_dcvs_freq_sink_stop(struct msm_dcvs_freq *drv)
 {
 	int ret = -EINVAL;
 	struct dcvs_core *core = NULL;
@@ -698,14 +724,12 @@
 		if (msm_dcvs_debug & MSM_DCVS_DEBUG_IDLE_PULSE)
 			__info("Enabling LPM for %s\n", core->core_name);
 	}
-	core->freq_pending = 0;
 	core->freq_driver = NULL;
 	mutex_unlock(&core->lock);
-	kthread_stop(core->task);
 
 	return 0;
 }
-EXPORT_SYMBOL(msm_dcvs_freq_sink_unregister);
+EXPORT_SYMBOL(msm_dcvs_freq_sink_stop);
 
 int msm_dcvs_idle_source_register(struct msm_dcvs_idle *drv)
 {
@@ -785,7 +809,7 @@
 			__err("Error (%d) sending idle exit for %s\n",
 					ret, core->core_name);
 		/* only start slack timer if change_freq won't */
-		if (freq_changed || core->change_freq_activated)
+		if (freq_changed)
 			break;
 		if (timer_interval_us && !core->timer_disabled) {
 			ret = hrtimer_start(&core->timer,
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index e8f8c59..3b31b9f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -120,7 +120,7 @@
 	 */
 	write_pen_release(-1);
 
-	/* clear the IPC1(SPI-8) pending SPI */
+	/* clear the IPC pending SPI */
 	if (power_collapsed) {
 		raise_clear_spi(cpu, false);
 		clear_pending_spi(cpu_data[cpu].ipc_irq);
@@ -173,9 +173,9 @@
 	return 0;
 }
 
-void __iomem *core1_reset_base(void)
+void __iomem *core_reset_base(unsigned int cpu)
 {
-	return cpu_data[1].reset_core_base;
+	return cpu_data[cpu].reset_core_base;
 }
 
 int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -217,7 +217,7 @@
 	 */
 
 	if (power_collapsed) {
-		core1_gic_configure_and_raise();
+		gic_configure_and_raise(cpu_data[cpu].ipc_irq, cpu);
 		raise_clear_spi(cpu, true);
 	} else {
 		gic_raise_softirq(cpumask_of(cpu), 1);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 10c5445..427e39f 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -487,7 +487,7 @@
 	void __iomem *base_ptr;
 	unsigned int value = 0;
 
-	base_ptr = core1_reset_base();
+	base_ptr = core_reset_base(1);
 	if (!base_ptr)
 		return;
 
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index ac077e9..969af98 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -286,6 +286,9 @@
 	/* 8092 IDs */
 	[146] = MSM_CPU_8092,
 
+	/* 8910 IDs */
+	[147] = MSM_CPU_8910,
+
 	/* 8064AB IDs */
 	[153] = MSM_CPU_8064AB,
 
@@ -732,6 +735,10 @@
 		dummy_socinfo.id = 146;
 		strlcpy(dummy_socinfo.build_id, "mpq8092 - ",
 		sizeof(dummy_socinfo.build_id));
+	} else if (early_machine_is_msm8910()) {
+		dummy_socinfo.id = 147;
+		strlcpy(dummy_socinfo.build_id, "msm8910 - ",
+			sizeof(dummy_socinfo.build_id));
 	}
 	strlcat(dummy_socinfo.build_id, "Dummy socinfo",
 		sizeof(dummy_socinfo.build_id));
diff --git a/drivers/cpufreq/cpufreq_gov_msm.c b/drivers/cpufreq/cpufreq_gov_msm.c
index 4eeff35..9ad1811 100644
--- a/drivers/cpufreq/cpufreq_gov_msm.c
+++ b/drivers/cpufreq/cpufreq_gov_msm.c
@@ -36,11 +36,13 @@
 static void msm_gov_check_limits(struct cpufreq_policy *policy)
 {
 	struct msm_gov *gov = &per_cpu(msm_gov_info, policy->cpu);
+	struct msm_dcvs_freq *dcvs_notifier =
+			&(per_cpu(msm_gov_info, policy->cpu).gov_notifier);
 
 	if (policy->max < gov->cur_freq)
 		__cpufreq_driver_target(policy, policy->max,
 				CPUFREQ_RELATION_H);
-	else if (policy->min > gov->min_freq)
+	else if (policy->min > gov->cur_freq)
 		__cpufreq_driver_target(policy, policy->min,
 				CPUFREQ_RELATION_L);
 	else
@@ -50,6 +52,7 @@
 	gov->cur_freq = policy->cur;
 	gov->min_freq = policy->min;
 	gov->max_freq = policy->max;
+	msm_dcvs_update_limits(dcvs_notifier);
 }
 
 static int msm_dcvs_freq_set(struct msm_dcvs_freq *self,
@@ -66,13 +69,17 @@
 	if (freq > gov->max_freq)
 		freq = gov->max_freq;
 
-	ret = __cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
-	gov->cur_freq = gov->policy->cur;
-
 	mutex_unlock(&per_cpu(gov_mutex, gov->cpu));
 
-	if (!ret)
-		return gov->cur_freq;
+	ret = cpufreq_driver_target(gov->policy, freq, CPUFREQ_RELATION_L);
+
+	if (!ret) {
+		gov->cur_freq = cpufreq_quick_get(gov->cpu);
+		if (freq != gov->cur_freq)
+			pr_err("cpu %d freq %u gov->cur_freq %u didn't match",
+						gov->cpu, freq, gov->cur_freq);
+	}
+	ret = gov->cur_freq;
 
 	return ret;
 }
@@ -82,7 +89,12 @@
 	struct msm_gov *gov =
 		container_of(self, struct msm_gov, gov_notifier);
 
-	return gov->cur_freq;
+	/*
+	 * the rw_sem in cpufreq is always held when this is called.
+	 * The policy->cur won't be updated in this case - so it is safe to
+	 * access policy->cur
+	 */
+	return gov->policy->cur;
 }
 
 static int cpufreq_governor_msm(struct cpufreq_policy *policy,
@@ -104,18 +116,14 @@
 		per_cpu(msm_gov_info, cpu).cpu = cpu;
 		gov->policy = policy;
 		dcvs_notifier->core_name = core_name[cpu];
-		dcvs_notifier->set_frequency = msm_dcvs_freq_set;
-		dcvs_notifier->get_frequency = msm_dcvs_freq_get;
-		handle = msm_dcvs_freq_sink_register(dcvs_notifier);
+		handle = msm_dcvs_freq_sink_start(dcvs_notifier);
 		BUG_ON(handle < 0);
 		msm_gov_check_limits(policy);
 		mutex_unlock(&per_cpu(gov_mutex, cpu));
 		break;
 
 	case CPUFREQ_GOV_STOP:
-		mutex_lock(&per_cpu(gov_mutex, cpu));
-		msm_dcvs_freq_sink_unregister(dcvs_notifier);
-		mutex_unlock(&per_cpu(gov_mutex, cpu));
+		msm_dcvs_freq_sink_stop(dcvs_notifier);
 		break;
 
 	case CPUFREQ_GOV_LIMITS:
@@ -139,13 +147,19 @@
 	int ret = 0;
 	int cpu;
 	struct msm_dcvs_core_info *core = NULL;
+	int sensor = 0;
 
 	core = pdev->dev.platform_data;
 
 	for_each_possible_cpu(cpu) {
 		mutex_init(&per_cpu(gov_mutex, cpu));
 		snprintf(core_name[cpu], 10, "cpu%d", cpu);
-		ret = msm_dcvs_register_core(core_name[cpu], core);
+		if (cpu < core->num_cores)
+			sensor = core->sensors[cpu];
+		ret = msm_dcvs_register_core(core_name[cpu], core,
+						msm_dcvs_freq_set,
+						msm_dcvs_freq_get,
+						sensor);
 		if (ret)
 			pr_err("Unable to register core for %d\n", cpu);
 	}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 573e0a6..97711e2 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -896,6 +896,19 @@
 			info->freq_tbl[index].leakage_energy_offset = 0;
 	}
 
+	if (adreno_of_read_property(node, "qcom,num-cores", &info->num_cores))
+		goto err;
+
+	info->sensors = kzalloc(info->num_cores *
+			sizeof(int),
+			GFP_KERNEL);
+
+	for (count = 0; count < info->num_cores; count++) {
+		if (adreno_of_read_property(node, "qcom,sensors",
+			&(info->sensors[count])))
+			goto err;
+	}
+
 	if (adreno_of_read_property(node, "qcom,core-core-type",
 		&info->core_param.core_type))
 		goto err;
@@ -1094,6 +1107,9 @@
 		&pdata->nap_allowed))
 		pdata->nap_allowed = 1;
 
+	pdata->strtstp_sleepwake = of_property_read_bool(pdev->dev.of_node,
+						"qcom,strtstp-sleepwake");
+
 	if (adreno_of_read_property(pdev->dev.of_node, "qcom,clk-map",
 		&pdata->clk_map))
 		goto err;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_msm.c b/drivers/gpu/msm/kgsl_pwrscale_msm.c
index acf22ac..3f9b3d7 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_msm.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_msm.c
@@ -171,7 +171,9 @@
 	low_level = pwr->num_pwrlevels - KGSL_PWRLEVEL_LAST_OFFSET;
 	for (i = 0; i <= low_level; i++)
 		tbl[i].freq = pwr->pwrlevels[low_level - i].gpu_freq / 1000;
-	ret = msm_dcvs_register_core(device->name, priv->core_info);
+	ret = msm_dcvs_register_core(device->name, priv->core_info,
+			msm_set_freq, msm_get_freq,
+			priv->core_info->sensors[0]);
 	if (ret) {
 		KGSL_PWR_ERR(device, "msm_dcvs_register_core failed");
 		goto err;
@@ -188,9 +190,7 @@
 	}
 
 	priv->freq_sink.core_name = device->name;
-	priv->freq_sink.set_frequency = msm_set_freq;
-	priv->freq_sink.get_frequency = msm_get_freq;
-	ret = msm_dcvs_freq_sink_register(&priv->freq_sink);
+	ret = msm_dcvs_freq_sink_start(&priv->freq_sink);
 	if (ret >= 0) {
 		if (device->ftbl->isidle(device)) {
 			priv->gpu_busy = 0;
@@ -220,7 +220,7 @@
 	if (pwrscale->priv == NULL)
 		return;
 	msm_dcvs_idle_source_unregister(&priv->idle_source);
-	msm_dcvs_freq_sink_unregister(&priv->freq_sink);
+	msm_dcvs_freq_sink_stop(&priv->freq_sink);
 	kfree(pwrscale->priv);
 	pwrscale->priv = NULL;
 	msm_restore_io_fraction(device);
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 775e95d..abd66f4 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -104,14 +104,75 @@
 static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
 		pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
 
+static int pmic8xxx_set_pon1(struct device *dev, u32 debounce_us, bool pull_up)
+{
+	int err;
+	u32 delay;
+	u8 pon_cntl;
+
+	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
+	if (debounce_us > USEC_PER_SEC * 2 ||
+		debounce_us < USEC_PER_SEC / 64) {
+		dev_err(dev, "invalid power key trigger delay\n");
+		return -EINVAL;
+	}
+
+	delay = (debounce_us << 6) / USEC_PER_SEC;
+	delay = ilog2(delay);
+
+	err = pm8xxx_readb(dev->parent, PON_CNTL_1, &pon_cntl);
+	if (err < 0) {
+		dev_err(dev, "failed reading PON_CNTL_1 err=%d\n", err);
+		return err;
+	}
+
+	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+
+	if (pull_up)
+		pon_cntl |= PON_CNTL_PULL_UP;
+	else
+		pon_cntl &= ~PON_CNTL_PULL_UP;
+
+	err = pm8xxx_writeb(dev->parent, PON_CNTL_1, pon_cntl);
+	if (err < 0) {
+		dev_err(dev, "failed writing PON_CNTL_1 err=%d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static ssize_t pmic8xxx_debounce_store(struct device *dev,
+			struct device_attribute *attr,
+			const char *buf, size_t size)
+{
+	struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+	int err;
+	unsigned long val;
+
+	if (size > 8)
+		return -EINVAL;
+
+	err = kstrtoul(buf, 10, &val);
+	if (err < 0)
+		return err;
+
+	err = pmic8xxx_set_pon1(dev, val, pwrkey->pdata->pull_up);
+	if (err < 0)
+		return err;
+
+	return size;
+}
+
+static DEVICE_ATTR(debounce_us, 0664, NULL, pmic8xxx_debounce_store);
+
 static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
 {
 	struct input_dev *pwr;
 	int key_release_irq = platform_get_irq(pdev, 0);
 	int key_press_irq = platform_get_irq(pdev, 1);
 	int err;
-	unsigned int delay;
-	u8 pon_cntl;
 	struct pmic8xxx_pwrkey *pwrkey;
 	const struct pm8xxx_pwrkey_platform_data *pdata =
 					dev_get_platdata(&pdev->dev);
@@ -121,13 +182,6 @@
 		return -EINVAL;
 	}
 
-	/* Valid range of pwr key trigger delay is 1/64 sec to 2 seconds. */
-	if (pdata->kpd_trigger_delay_us > USEC_PER_SEC * 2 ||
-		pdata->kpd_trigger_delay_us < USEC_PER_SEC / 64) {
-		dev_err(&pdev->dev, "invalid power key trigger delay\n");
-		return -EINVAL;
-	}
-
 	pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
 	if (!pwrkey)
 		return -ENOMEM;
@@ -147,25 +201,10 @@
 	pwr->phys = "pmic8xxx_pwrkey/input0";
 	pwr->dev.parent = &pdev->dev;
 
-	delay = (pdata->kpd_trigger_delay_us << 6) / USEC_PER_SEC;
-	delay = ilog2(delay);
-
-	err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
-		goto free_input_dev;
-	}
-
-	pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
-	pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
-	if (pdata->pull_up)
-		pon_cntl |= PON_CNTL_PULL_UP;
-	else
-		pon_cntl &= ~PON_CNTL_PULL_UP;
-
-	err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
-	if (err < 0) {
-		dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+	err = pmic8xxx_set_pon1(&pdev->dev,
+			pdata->kpd_trigger_delay_us, pdata->pull_up);
+	if (err) {
+		dev_dbg(&pdev->dev, "Can't set PON CTRL1 register: %d\n", err);
 		goto free_input_dev;
 	}
 
@@ -211,12 +250,22 @@
 		goto free_press_irq;
 	}
 
+	err = device_create_file(&pdev->dev, &dev_attr_debounce_us);
+	if (err < 0) {
+		dev_err(&pdev->dev,
+				"dev file creation for debounce failed: %d\n",
+				err);
+		goto free_rel_irq;
+	}
+
 	device_init_wakeup(&pdev->dev, pdata->wakeup);
 
 	return 0;
 
+free_rel_irq:
+	free_irq(key_release_irq, pwrkey);
 free_press_irq:
-	free_irq(key_press_irq, NULL);
+	free_irq(key_press_irq, pwrkey);
 unreg_input_dev:
 	platform_set_drvdata(pdev, NULL);
 	input_unregister_device(pwr);
@@ -236,6 +285,7 @@
 
 	device_init_wakeup(&pdev->dev, 0);
 
+	device_remove_file(&pdev->dev, &dev_attr_debounce_us);
 	free_irq(key_press_irq, pwrkey);
 	free_irq(key_release_irq, pwrkey);
 	input_unregister_device(pwrkey->pwr);
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.c b/drivers/media/video/msm_vidc/msm_vidc_debug.c
index 7921f84..fa62988 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.c
@@ -104,6 +104,7 @@
 		dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
 		goto failed_create_dir;
 	}
+	msm_vidc_debug = 0x3;
 failed_create_dir:
 	return dir;
 }
diff --git a/drivers/media/video/msm_vidc/msm_vidc_debug.h b/drivers/media/video/msm_vidc/msm_vidc_debug.h
index b7928e9..f7aa742 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_debug.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_debug.h
@@ -18,19 +18,24 @@
 
 #define VIDC_DBG_TAG "msm_vidc: %d: "
 
+/*To enable messages OR these values and
+* echo the result to debugfs file*/
+
 enum vidc_msg_prio {
-	VIDC_ERR,
-	VIDC_WARN,
-	VIDC_INFO,
-	VIDC_DBG,
+	VIDC_ERR  = 0x0001,
+	VIDC_WARN = 0x0002,
+	VIDC_INFO = 0x0004,
+	VIDC_DBG  = 0x0008,
+	VIDC_PROF = 0x0010,
+	VIDC_FW   = 0x1000,
 };
 
 extern int msm_vidc_debug;
-#define dprintk(level, fmt, arg...)	\
-	do {							\
-		if (msm_vidc_debug >= level) \
-			printk(KERN_DEBUG VIDC_DBG_TAG fmt, \
-				level, ## arg); \
+#define dprintk(__level, __fmt, arg...)	\
+	do { \
+		if (msm_vidc_debug & __level) \
+			printk(KERN_DEBUG VIDC_DBG_TAG __fmt,\
+				__level, ## arg); \
 	} while (0)
 
 struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
diff --git a/drivers/media/video/msm_vidc/vidc_hal_api.h b/drivers/media/video/msm_vidc/vidc_hal_api.h
index 659cf7e..879418d 100644
--- a/drivers/media/video/msm_vidc/vidc_hal_api.h
+++ b/drivers/media/video/msm_vidc/vidc_hal_api.h
@@ -210,7 +210,7 @@
 
 enum hal_mpeg4_profile {
 	HAL_MPEG4_PROFILE_SIMPLE           = 0x00000001,
-	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00000002,
+	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00000002,
 	HAL_MPEG4_PROFILE_CORE             = 0x00000004,
 	HAL_MPEG4_PROFILE_MAIN             = 0x00000008,
 	HAL_MPEG4_PROFILE_NBIT             = 0x00000010,
@@ -224,7 +224,7 @@
 	HAL_MPEG4_PROFILE_ADVANCEDCODING   = 0x00001000,
 	HAL_MPEG4_PROFILE_ADVANCEDCORE     = 0x00002000,
 	HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
-	HAL_MPEG4_PROFILE_ADVANCEDSIMPLE   = 0x00008000,
+	HAL_MPEG4_PROFILE_SIMPLESCALABLE   = 0x00008000,
 	HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
 };
 
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 0ea843c..e7e11d0 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -263,6 +263,7 @@
 	{{0x0, 0x0, 0x2, 0x1}, taiko_devs, ARRAY_SIZE(taiko_devs)},
 	{{0x0, 0x0, 0x0, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
 	{{0x1, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
+	{{0x2, 0x0, 0x1, 0x1}, sitar_devs, ARRAY_SIZE(sitar_devs)},
 };
 
 static void wcd9xxx_bring_up(struct wcd9xxx *wcd9xxx)
@@ -314,18 +315,17 @@
 					struct mfd_cell **wcd9xxx_dev,
 					int *wcd9xxx_dev_size)
 {
-	struct wcd9xx_codec_type *cdc = wcd9xxx_codecs;
-	int index;
+	int i;
 	int ret;
-	index = WCD9XXX_A_CHIP_ID_BYTE_0;
-	while (index <= WCD9XXX_A_CHIP_ID_BYTE_3) {
-		ret = wcd9xxx_reg_read(wcd9xxx, index);
+	i = WCD9XXX_A_CHIP_ID_BYTE_0;
+	while (i <= WCD9XXX_A_CHIP_ID_BYTE_3) {
+		ret = wcd9xxx_reg_read(wcd9xxx, i);
 		if (ret < 0)
 			goto exit;
-		wcd9xxx->idbyte[index-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
+		wcd9xxx->idbyte[i-WCD9XXX_A_CHIP_ID_BYTE_0] = (u8)ret;
 		pr_debug("%s: wcd9xx read = %x, byte = %x\n", __func__, ret,
-			index);
-		index++;
+			i);
+		i++;
 	}
 
 	/* Read codec version */
@@ -333,18 +333,19 @@
 	if (ret < 0)
 		goto exit;
 	wcd9xxx->version = (u8)ret & 0x1F;
-
-	while (cdc < (cdc + ARRAY_SIZE(wcd9xxx_codecs)) && cdc != NULL) {
-		if ((cdc->byte[0] == wcd9xxx->idbyte[0]) &&
-		    (cdc->byte[1] == wcd9xxx->idbyte[1]) &&
-		    (cdc->byte[2] == wcd9xxx->idbyte[2]) &&
-		    (cdc->byte[3] == wcd9xxx->idbyte[3])) {
-			pr_info("%s: codec is %s", __func__, cdc->dev->name);
-			*wcd9xxx_dev = cdc->dev;
-			*wcd9xxx_dev_size = cdc->size;
+	i = 0;
+	while (i < ARRAY_SIZE(wcd9xxx_codecs)) {
+		if ((wcd9xxx_codecs[i].byte[0] == wcd9xxx->idbyte[0]) &&
+		    (wcd9xxx_codecs[i].byte[1] == wcd9xxx->idbyte[1]) &&
+		    (wcd9xxx_codecs[i].byte[2] == wcd9xxx->idbyte[2]) &&
+		    (wcd9xxx_codecs[i].byte[3] == wcd9xxx->idbyte[3])) {
+			pr_info("%s: codec is %s", __func__,
+				wcd9xxx_codecs[i].dev->name);
+			*wcd9xxx_dev = wcd9xxx_codecs[i].dev;
+			*wcd9xxx_dev_size = wcd9xxx_codecs[i].size;
 			break;
 		}
-		cdc++;
+		i++;
 	}
 	if (*wcd9xxx_dev == NULL || *wcd9xxx_dev_size == 0)
 		ret = -ENODEV;
diff --git a/drivers/mfd/wcd9xxx-irq.c b/drivers/mfd/wcd9xxx-irq.c
index 68c4557..e9b2ef3 100644
--- a/drivers/mfd/wcd9xxx-irq.c
+++ b/drivers/mfd/wcd9xxx-irq.c
@@ -25,6 +25,8 @@
 #define BYTE_BIT_MASK(nr)		(1UL << ((nr) % BITS_PER_BYTE))
 #define BIT_BYTE(nr)			((nr) / BITS_PER_BYTE)
 
+#define WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS 100
+
 struct wcd9xxx_irq {
 	bool level;
 };
@@ -106,11 +108,17 @@
 {
 	enum wcd9xxx_pm_state os;
 
-	/* wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
+	/*
+	 * wcd9xxx_{lock/unlock}_sleep will be called by wcd9xxx_irq_thread
 	 * and its subroutines only motly.
 	 * but btn0_lpress_fn is not wcd9xxx_irq_thread's subroutine and
-	 * it can race with wcd9xxx_irq_thread.
-	 * so need to embrace wlock_holders with mutex.
+	 * It can race with wcd9xxx_irq_thread.
+	 * So need to embrace wlock_holders with mutex.
+	 *
+	 * If system didn't resume, we can simply return false so codec driver's
+	 * IRQ handler can return without handling IRQ.
+	 * As interrupt line is still active, codec will have another IRQ to
+	 * retry shortly.
 	 */
 	mutex_lock(&wcd9xxx->pm_lock);
 	if (wcd9xxx->wlock_holders++ == 0) {
@@ -124,11 +132,11 @@
 						WCD9XXX_PM_AWAKE)) ==
 						    WCD9XXX_PM_SLEEPABLE ||
 			 (os == WCD9XXX_PM_AWAKE)),
-			5 * HZ)) {
-		pr_err("%s: system didn't resume within 5000ms, state %d, "
-		       "wlock %d\n", __func__, wcd9xxx->pm_state,
-		       wcd9xxx->wlock_holders);
-		WARN_ON(1);
+			msecs_to_jiffies(WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS))) {
+		pr_warn("%s: system didn't resume within %dms, s %d, w %d\n",
+			__func__,
+			WCD9XXX_SYSTEM_RESUME_TIMEOUT_MS, wcd9xxx->pm_state,
+			wcd9xxx->wlock_holders);
 		wcd9xxx_unlock_sleep(wcd9xxx);
 		return false;
 	}
@@ -141,8 +149,14 @@
 {
 	mutex_lock(&wcd9xxx->pm_lock);
 	if (--wcd9xxx->wlock_holders == 0) {
-		wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
-		pr_debug("%s: releasing wake lock\n", __func__);
+		pr_debug("%s: releasing wake lock pm_state %d -> %d\n",
+			 __func__, wcd9xxx->pm_state, WCD9XXX_PM_SLEEPABLE);
+		/*
+		 * if wcd9xxx_lock_sleep failed, pm_state would be still
+		 * WCD9XXX_PM_ASLEEP, don't overwrite
+		 */
+		if (likely(wcd9xxx->pm_state == WCD9XXX_PM_AWAKE))
+			wcd9xxx->pm_state = WCD9XXX_PM_SLEEPABLE;
 		pm_qos_update_request(&wcd9xxx->pm_qos_req,
 				PM_QOS_DEFAULT_VALUE);
 	}
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 33b12ae..76a758b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -39,8 +39,10 @@
 
 #define QPNP_PON_RESIN_PULL_UP		BIT(0)
 #define QPNP_PON_KPDPWR_PULL_UP		BIT(1)
+#define QPNP_PON_CBLPWR_PULL_UP		BIT(2)
 #define QPNP_PON_S2_CNTL_EN		BIT(7)
 #define QPNP_PON_S2_RESET_ENABLE	BIT(7)
+#define QPNP_PON_DELAY_BIT_SHIFT	6
 
 #define QPNP_PON_S1_TIMER_MASK		(0xF)
 #define QPNP_PON_S2_TIMER_MASK		(0x7)
@@ -49,6 +51,7 @@
 #define QPNP_PON_DBC_DELAY_MASK		(0x7)
 #define QPNP_PON_KPDPWR_N_SET		BIT(0)
 #define QPNP_PON_RESIN_N_SET		BIT(1)
+#define QPNP_PON_CBLPWR_N_SET		BIT(2)
 #define QPNP_PON_RESIN_BARK_N_SET	BIT(4)
 
 #define QPNP_PON_RESET_EN		BIT(7)
@@ -66,6 +69,7 @@
 enum pon_type {
 	PON_KPDPWR,
 	PON_RESIN,
+	PON_CBLPWR,
 };
 
 struct qpnp_pon_config {
@@ -214,6 +218,9 @@
 	case PON_RESIN:
 		pon_rt_bit = QPNP_PON_RESIN_N_SET;
 		break;
+	case PON_CBLPWR:
+		pon_rt_bit = QPNP_PON_CBLPWR_N_SET;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -253,6 +260,18 @@
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t qpnp_cblpwr_irq(int irq, void *_pon)
+{
+	int rc;
+	struct qpnp_pon *pon = _pon;
+
+	rc = qpnp_pon_input_dispatch(pon, PON_CBLPWR);
+	if (rc)
+		dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
+	return IRQ_HANDLED;
+}
+
 static void bark_work_func(struct work_struct *work)
 {
 	int rc;
@@ -351,6 +370,9 @@
 	case PON_RESIN:
 		pull_bit = QPNP_PON_RESIN_PULL_UP;
 		break;
+	case PON_CBLPWR:
+		pull_bit = QPNP_PON_CBLPWR_PULL_UP;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -489,6 +511,17 @@
 			}
 		}
 		break;
+	case PON_CBLPWR:
+		rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+							qpnp_cblpwr_irq,
+				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+					"qpnp_cblpwr_status", pon);
+		if (rc < 0) {
+			dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+							cfg->state_irq);
+			return rc;
+		}
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -595,6 +628,15 @@
 				}
 			}
 			break;
+		case PON_CBLPWR:
+			cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+							NULL, "cblpwr");
+			if (cfg->state_irq < 0) {
+				dev_err(&pon->spmi->dev,
+						"Unable to get cblpwr irq\n");
+				return rc;
+			}
+			break;
 		default:
 			dev_err(&pon->spmi->dev, "PON RESET %d not supported",
 								cfg->pon_type);
@@ -763,11 +805,13 @@
 
 	rc = of_property_read_u32(pon->spmi->dev.of_node,
 				"qcom,pon-dbc-delay", &delay);
-	if (rc && rc != -EINVAL) {
-		dev_err(&spmi->dev, "Unable to read debounce delay\n");
-		return rc;
+	if (rc) {
+		if (rc != -EINVAL) {
+			dev_err(&spmi->dev, "Unable to read debounce delay\n");
+			return rc;
+		}
 	} else {
-		delay = (delay << 6) / USEC_PER_SEC;
+		delay = (delay << QPNP_PON_DELAY_BIT_SHIFT) / USEC_PER_SEC;
 		delay = ilog2(delay);
 		rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
 						QPNP_PON_DBC_DELAY_MASK, delay);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6e332ef..5fdee02 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -920,7 +920,7 @@
 	u32 i;
 	u32 found = false;
 
-	for (i = 0; i <= pool->count && !found; i++) {
+	for (i = 1; i <= pool->count && !found; i++) {
 		if (pool->entries[i].virtual == addr)
 			found = true;
 
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 32d3aef..9cc0de4 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -284,7 +284,8 @@
 			uint32_t rate, uint32_t channels);
 
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
-				uint32_t rate, uint32_t channels);
+				uint32_t rate, uint32_t channels,
+				char *channel_map);
 
 int q6asm_media_format_block_aac(struct audio_client *ac,
 			struct asm_aac_cfg *cfg);
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index d0c5baf..4eec66e 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -295,7 +295,9 @@
 static int
 cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
 {
-	return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
+	return *rdp->nxttail[RCU_DONE_TAIL +
+			     ACCESS_ONCE(rsp->completed) != rdp->completed] &&
+	       !rcu_gp_in_progress(rsp);
 }
 
 /*
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 4c655c2..d2f60a0 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1629,6 +1629,8 @@
 			 $exec_file =~ /^.+\.ihex$/ or
 			 $exec_file =~ /^.+\.hex$/ or
 			 $exec_file =~ /^.+\.HEX$/ or
+			 $exec_file =~ /^.+\.dts$/ or
+			 $exec_file =~ /^.+\.dtsi$/ or
 			 $exec_file =~ /^.+defconfig$/ or
 			 $exec_file =~ /^Makefile$/ or
 			 $exec_file =~ /^Kconfig$/) &&
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index deddbe8..5a819c9 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -33,6 +33,9 @@
 #include <linux/pm_runtime.h>
 #include <linux/kernel.h>
 #include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/wakelock.h>
+#include <linux/suspend.h>
 #include "wcd9310.h"
 
 static int cfilt_adjust_ms = 10;
@@ -340,6 +343,9 @@
 	 */
 	struct work_struct hs_correct_plug_work_nogpio;
 
+	bool gpio_irq_resend;
+	struct wake_lock irq_resend_wlock;
+
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_poke;
 	struct dentry *debugfs_mbhc;
@@ -7352,9 +7358,18 @@
 {
 	int r = IRQ_HANDLED;
 	struct snd_soc_codec *codec = data;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
 	if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
 		pr_warn("%s: failed to hold suspend\n", __func__);
+		/*
+		 * Give up this IRQ for now and resend this IRQ so IRQ can be
+		 * handled after system resume
+		 */
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
+		tabla->gpio_irq_resend = true;
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+		wake_lock_timeout(&tabla->irq_resend_wlock, HZ);
 		r = IRQ_NONE;
 	} else {
 		tabla_hs_gpio_handler(codec);
@@ -8267,6 +8282,15 @@
 		goto err_hphr_ocp_irq;
 	}
 	wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
+
+	/*
+	 * Register suspend lock and notifier to resend edge triggered
+	 * gpio IRQs
+	 */
+	wake_lock_init(&tabla->irq_resend_wlock, WAKE_LOCK_SUSPEND,
+		       "tabla_gpio_irq_resend");
+	tabla->gpio_irq_resend = false;
+
 	for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
 		switch (tabla_dai[i].id) {
 		case AIF1_PB:
@@ -8331,6 +8355,9 @@
 {
 	int i;
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+	wake_lock_destroy(&tabla->irq_resend_wlock);
+
 	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
 	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
 	wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
@@ -8380,11 +8407,29 @@
 
 static int tabla_resume(struct device *dev)
 {
+	int irq;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct tabla_priv *tabla = platform_get_drvdata(pdev);
+
 	dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
-	if (tabla)
+	if (tabla) {
+		TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
 		tabla->mbhc_last_resume = jiffies;
+		if (tabla->gpio_irq_resend) {
+			WARN_ON(!tabla->mbhc_cfg.gpio_irq);
+			tabla->gpio_irq_resend = false;
+
+			irq = tabla->mbhc_cfg.gpio_irq;
+			pr_debug("%s: Resending GPIO IRQ %d\n", __func__, irq);
+			irq_set_pending(irq);
+			check_irq_resend(irq_to_desc(irq), irq);
+
+			/* release suspend lock */
+			wake_unlock(&tabla->irq_resend_wlock);
+		}
+		TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
+	}
+
 	return 0;
 }
 
diff --git a/sound/soc/msm/msm-lowlatency-pcm-q6.c b/sound/soc/msm/msm-lowlatency-pcm-q6.c
index 129f69f..fcfcb66 100644
--- a/sound/soc/msm/msm-lowlatency-pcm-q6.c
+++ b/sound/soc/msm/msm-lowlatency-pcm-q6.c
@@ -218,8 +218,27 @@
 	if (prtd->enabled)
 		return 0;
 
+	if (!prtd->set_channel_map) {
+		memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+		if (prtd->channel_mode == 1) {
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+		} else if (prtd->channel_mode == 2) {
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+			prtd->channel_map[0] = PCM_CHANNEL_FR;
+		} else if (prtd->channel_mode == 6) {
+			prtd->channel_map[0] = PCM_CHANNEL_FC;
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+			prtd->channel_map[0] = PCM_CHANNEL_FR;
+			prtd->channel_map[0] = PCM_CHANNEL_LB;
+			prtd->channel_map[0] = PCM_CHANNEL_RB;
+			prtd->channel_map[0] = PCM_CHANNEL_LFE;
+		} else {
+			pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				prtd->channel_mode);
+		}
+	}
 	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
-			runtime->rate, runtime->channels);
+			runtime->rate, runtime->channels, prtd->channel_map);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -389,6 +408,7 @@
 	}
 
 	prtd->dsp_cnt = 0;
+	prtd->set_channel_map = false;
 	runtime->private_data = prtd;
 	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
 	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
diff --git a/sound/soc/msm/msm-multi-ch-pcm-q6.c b/sound/soc/msm/msm-multi-ch-pcm-q6.c
index 5b0759c..7d04f95 100644
--- a/sound/soc/msm/msm-multi-ch-pcm-q6.c
+++ b/sound/soc/msm/msm-multi-ch-pcm-q6.c
@@ -269,9 +269,29 @@
 	prtd->channel_mode = runtime->channels;
 	if (prtd->enabled)
 		return 0;
-
+	pr_debug("prtd->set_channel_map: %d", prtd->set_channel_map);
+	if (!prtd->set_channel_map) {
+		pr_debug("using default channel map");
+		memset(prtd->channel_map, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+		if (prtd->channel_mode == 1) {
+			prtd->channel_map[0] = PCM_CHANNEL_FL;
+		} else if (prtd->channel_mode == 2) {
+			prtd->channel_map[1] = PCM_CHANNEL_FL;
+			prtd->channel_map[2] = PCM_CHANNEL_FR;
+		} else if (prtd->channel_mode == 6) {
+			prtd->channel_map[0] = PCM_CHANNEL_FC;
+			prtd->channel_map[1] = PCM_CHANNEL_FL;
+			prtd->channel_map[2] = PCM_CHANNEL_FR;
+			prtd->channel_map[3] = PCM_CHANNEL_LB;
+			prtd->channel_map[4] = PCM_CHANNEL_RB;
+			prtd->channel_map[5] = PCM_CHANNEL_LFE;
+		} else {
+			pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+				prtd->channel_mode);
+		}
+	}
 	ret = q6asm_media_format_block_multi_ch_pcm(prtd->audio_client,
-			runtime->rate, runtime->channels);
+			runtime->rate, runtime->channels, prtd->channel_map);
 	if (ret < 0)
 		pr_info("%s: CMD Format block failed\n", __func__);
 
@@ -452,6 +472,7 @@
 	}
 
 	prtd->dsp_cnt = 0;
+	prtd->set_channel_map = false;
 	runtime->private_data = prtd;
 	pr_debug("substream->pcm->device = %d\n", substream->pcm->device);
 	pr_debug("soc_prtd->dai_link->be_id = %d\n", soc_prtd->dai_link->be_id);
@@ -492,6 +513,15 @@
 	return rc;
 }
 
+void multi_ch_pcm_set_channel_map(char *channel_mapping)
+{
+	pr_debug("%s\n", __func__);
+	if (multi_ch_pcm_audio.prtd) {
+		multi_ch_pcm_audio.prtd->set_channel_map = true;
+		memcpy(multi_ch_pcm_audio.prtd->channel_map, channel_mapping,
+			 PCM_FORMAT_MAX_NUM_CHANNEL);
+	}
+}
 
 static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
 	snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index f1af99a..2678498 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -81,6 +81,8 @@
 	int periods;
 	int mmap_flag;
 	atomic_t pending_buffer;
+	bool set_channel_map;
+	char channel_map[8];
 };
 
 struct output_meta_data_st {
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4d0caa3..f28d01a 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -78,6 +78,7 @@
 static const DECLARE_TLV_DB_LINEAR(compressed2_rx_vol_gain, 0,
 			INT_RX_VOL_MAX_STEPS);
 static int msm_route_ec_ref_rx;
+static char channel_mapping[PCM_FORMAT_MAX_NUM_CHANNEL];
 
 /* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
 #define MAX_EQ_SESSIONS		MSM_FRONTEND_DAI_CS_VOICE
@@ -862,6 +863,27 @@
 	return 0;
 }
 
+static int msm_routing_get_channel_map_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		ucontrol->value.integer.value[i] = channel_mapping[i];
+	return 0;
+}
+
+static int msm_routing_put_channel_map_mixer(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	int i;
+
+	for (i = 0; i < PCM_FORMAT_MAX_NUM_CHANNEL; i++)
+		channel_mapping[i] = (char)(ucontrol->value.integer.value[i]);
+	multi_ch_pcm_set_channel_map(channel_mapping);
+
+	return 0;
+}
+
 static int msm_routing_set_compressed_vol_mixer(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -1891,6 +1913,12 @@
 	msm_routing_set_compressed2_vol_mixer, compressed2_rx_vol_gain),
 };
 
+static const struct snd_kcontrol_new multi_ch_channel_map_mixer_controls[] = {
+	SOC_SINGLE_MULTI_EXT("Playback Channel Map", SND_SOC_NOPM, 0, 8,
+	0, 8, msm_routing_get_channel_map_mixer,
+	msm_routing_put_channel_map_mixer),
+};
+
 static const struct snd_kcontrol_new lpa_SRS_trumedia_controls[] = {
 	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "SRS TruMedia",
@@ -2867,6 +2895,10 @@
 	snd_soc_add_platform_controls(platform,
 				ec_ref_rx_mixer_controls,
 			ARRAY_SIZE(ec_ref_rx_mixer_controls));
+
+	snd_soc_add_platform_controls(platform,
+				multi_ch_channel_map_mixer_controls,
+			ARRAY_SIZE(multi_ch_channel_map_mixer_controls));
 	return 0;
 }
 
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index 6b87475..14f330b 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -126,4 +126,6 @@
 
 int compressed_set_volume(unsigned volume);
 
+void multi_ch_pcm_set_channel_map(char *channel_mapping);
+
 #endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index 6865871..0aad217 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -2317,7 +2317,7 @@
 }
 
 int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
-				uint32_t rate, uint32_t channels)
+			uint32_t rate, uint32_t channels, char *channel_map)
 {
 	struct asm_stream_media_format_update fmt;
 	u8 *channel_mapping;
@@ -2340,39 +2340,7 @@
 	channel_mapping =
 		fmt.write_cfg.multi_ch_pcm_cfg.channel_mapping;
 
-	memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
-
-	if (channels == 1)  {
-		channel_mapping[0] = PCM_CHANNEL_FL;
-	} else if (channels == 2) {
-		channel_mapping[0] = PCM_CHANNEL_FL;
-		channel_mapping[1] = PCM_CHANNEL_FR;
-	} else if (channels == 4) {
-		channel_mapping[0] = PCM_CHANNEL_FL;
-		channel_mapping[1] = PCM_CHANNEL_FR;
-		channel_mapping[1] = PCM_CHANNEL_LB;
-		channel_mapping[1] = PCM_CHANNEL_RB;
-	} else if (channels == 6) {
-		channel_mapping[0] = PCM_CHANNEL_FC;
-		channel_mapping[1] = PCM_CHANNEL_FL;
-		channel_mapping[2] = PCM_CHANNEL_FR;
-		channel_mapping[3] = PCM_CHANNEL_LB;
-		channel_mapping[4] = PCM_CHANNEL_RB;
-		channel_mapping[5] = PCM_CHANNEL_LFE;
-	} else if (channels == 8) {
-		channel_mapping[0] = PCM_CHANNEL_FC;
-		channel_mapping[1] = PCM_CHANNEL_FL;
-		channel_mapping[2] = PCM_CHANNEL_FR;
-		channel_mapping[3] = PCM_CHANNEL_LB;
-		channel_mapping[4] = PCM_CHANNEL_RB;
-		channel_mapping[5] = PCM_CHANNEL_LFE;
-		channel_mapping[6] = PCM_CHANNEL_FLC;
-		channel_mapping[7] = PCM_CHANNEL_FRC;
-	} else {
-		pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
-				channels);
-		return -EINVAL;
-	}
+	memcpy(channel_mapping, channel_map, PCM_FORMAT_MAX_NUM_CHANNEL);
 
 	rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
 	if (rc < 0) {
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index 62257b4..fac55b4 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -116,8 +116,18 @@
 				wake_up(&this_adm.wait[index]);
 				break;
 			case ADM_CMD_SHARED_MEM_MAP_REGIONS:
-				/* Block until memory handle comes back */
-				/* via ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+				pr_debug("%s: ADM_CMD_SHARED_MEM_MAP_REGIONS\n",
+					__func__);
+				/* Should only come here if there is an APR */
+				/* error or malformed APR packet. Otherwise */
+				/* response will be returned as */
+				/* ADM_CMDRSP_SHARED_MEM_MAP_REGIONS */
+				if (payload[1] != 0) {
+					pr_err("%s: ADM map error, resuming\n",
+						__func__);
+					atomic_set(&this_adm.copp_stat[0], 1);
+					wake_up(&this_adm.wait[index]);
+				}
 				break;
 			default:
 				pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
@@ -247,24 +257,27 @@
 	get_audproc_cal(acdb_path, &aud_cal);
 
 	/* map & cache buffers used */
+	atomic_set(&mem_map_index, acdb_path);
 	if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
 		(aud_cal.cal_size > 0)) ||
 		(aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
 
-		atomic_set(&mem_map_index, acdb_path);
 		if (mem_addr_audproc[acdb_path].cal_paddr != 0)
 			adm_memory_unmap_regions(port_id,
 				&mem_addr_audproc[acdb_path].cal_paddr,
 				&size, 1);
 
 		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
-						0, &aud_cal.cal_size, 1);
-		if (result < 0)
+						0, &size, 1);
+		if (result < 0) {
 			pr_err("ADM audproc mmap did not work! path = %d, addr = 0x%x, size = %d\n",
 				acdb_path, aud_cal.cal_paddr,
 				aud_cal.cal_size);
-		else
-			mem_addr_audproc[acdb_path] = aud_cal;
+		} else {
+			mem_addr_audproc[acdb_path].cal_paddr =
+							aud_cal.cal_paddr;
+			mem_addr_audproc[acdb_path].cal_size = size;
+		}
 	}
 
 	if (!send_adm_cal_block(port_id, &aud_cal))
@@ -278,24 +291,27 @@
 	get_audvol_cal(acdb_path, &aud_cal);
 
 	/* map & cache buffers used */
+	atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
 	if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
 		(aud_cal.cal_size > 0))  ||
 		(aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
 
-		atomic_set(&mem_map_index, (acdb_path + MAX_AUDPROC_TYPES));
 		if (mem_addr_audvol[acdb_path].cal_paddr != 0)
 			adm_memory_unmap_regions(port_id,
 				&mem_addr_audvol[acdb_path].cal_paddr,
 				&size, 1);
 
 		result = adm_memory_map_regions(port_id, &aud_cal.cal_paddr,
-						0, &aud_cal.cal_size, 1);
-		if (result < 0)
+						0, &size, 1);
+		if (result < 0) {
 			pr_err("ADM audvol mmap did not work! path = %d, addr = 0x%x, size = %d\n",
 				acdb_path, aud_cal.cal_paddr,
 				aud_cal.cal_size);
-		else
-			mem_addr_audvol[acdb_path] = aud_cal;
+		} else {
+			mem_addr_audvol[acdb_path].cal_paddr =
+							aud_cal.cal_paddr;
+			mem_addr_audvol[acdb_path].cal_size = size;
+		}
 	}
 
 	if (!send_adm_cal_block(port_id, &aud_cal))
@@ -664,8 +680,8 @@
 								APR_PKT_VER);
 	mmap_regions->hdr.pkt_size = cmd_size;
 	mmap_regions->hdr.src_port = 0;
-	mmap_regions->hdr.dest_port = 0;
-	mmap_regions->hdr.token = 0;
+	mmap_regions->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	mmap_regions->hdr.token = port_id;
 	mmap_regions->hdr.opcode = ADM_CMD_SHARED_MEM_MAP_REGIONS;
 	mmap_regions->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL & 0x00ff;
 	mmap_regions->num_regions = bufcnt & 0x00ff;
@@ -733,8 +749,8 @@
 							APR_PKT_VER);
 	unmap_regions.hdr.pkt_size = cmd_size;
 	unmap_regions.hdr.src_port = 0;
-	unmap_regions.hdr.dest_port = 0;
-	unmap_regions.hdr.token = 0;
+	unmap_regions.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+	unmap_regions.hdr.token = port_id;
 	unmap_regions.hdr.opcode = ADM_CMD_SHARED_MEM_UNMAP_REGIONS;
 	unmap_regions.mem_map_handle = atomic_read(&mem_map_handles[
 						atomic_read(&mem_map_index)]);